PageSourceSearch

https://cdn.apisetu.gov.in/portal/home/_next/static/chunks/9e2b0e85-283c69c90247b95a.js

js apisetu.gov.in collected 2026-10-03 19:30:38 UTC 290,114 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[761],{8024:()=>{let n="undefined"!=typeof window&&"undefined"!=typeof document;if(!function(){if(!n||window.__UX4G_RUNTIME_INITIALIZED__)return;window.__UX4G_RUNTIME_INITIALIZED__=!0;let e=document.createElement("script");e.setAttribute("data-ux4g-runtime","main"),e.textContent='/*!\r\n * UX4G.js\r\n * Components: Dropdown, Collapse/Accordion, Offcanvas, Tooltip, Popover, Toast, Carousel, Tabs, Scrollspy\r\n * Compatibility: UX4G markup (data-ux-*)\r\n * Version: 1.1.0\r\n */\r\n\r\n(function (global) {\r\n  "use strict";\r\n\r\n  // -----------------------------\r\n  // Utilities\r\n  // -----------------------------\r\n  const U = {\r\n    qs(sel, root = document) { return root.querySelector(sel); },\r\n    qsa(sel, root = document) { return Array.from(root.querySelectorAll(sel)); },\r\n    on(el, evt, cb, opts) { el && el.addEventListener(evt, cb, opts); },\r\n    off(el, evt, cb, opts) { el && el.removeEventListener(evt, cb, opts); },\r\n    closest(el, sel) { return el ? el.closest(sel) : null; },\r\n    isVisible(el) { return !!(el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length)); },\r\n    reflow(el) { return el && el.offsetHeight; },\r\n    attr(el, name, fallback = null) {\r\n      if (!el) return fallback;\r\n      const v = el.getAttribute(name);\r\n      return v == null ? fallback : v;\r\n    },\r\n    // Prefer UX4G attributes\r\n    data(el, key, fallback = null) {\r\n      if (!el) return fallback;\r\n      const ux = el.getAttribute(`data-ux-${key}`);\r\n      if (ux != null) return ux;\r\n      const bs = el.getAttribute(`data-bs-${key}`);\r\n      if (bs != null) return bs;\r\n      const ux4g = el.getAttribute(`ux4g-${key}`);\r\n      if (ux4g != null) return ux4g;\r\n      return fallback;\r\n    },\r\n    bool(v, fallback = false) {\r\n      if (v == null) return fallback;\r\n      if (typeof v === "boolean") return v;\r\n      const s = String(v).trim().toLowerCase();\r\n      if (s === "" || s === "true" || s === "1") return true;\r\n      if (s === "false" || s === "0") return false;\r\n      return fallback;\r\n    },\r\n    num(v, fallback = 0) {\r\n      const n = Number(v);\r\n      return Number.isFinite(n) ? n : fallback;\r\n    },\r\n    dispatch(el, name, detail) {\r\n      if (!el) return;\r\n      el.dispatchEvent(new CustomEvent(name, { bubbles: true, cancelable: true, detail }));\r\n    },\r\n    focusables(root) {\r\n      if (!root) return [];\r\n      const sel = [\r\n        "a[href]",\r\n        "area[href]",\r\n        "button:not([disabled])",\r\n        "input:not([disabled]):not([type=\'hidden\'])",\r\n        "select:not([disabled])",\r\n        "textarea:not([disabled])",\r\n        "[tabindex]:not([tabindex=\'-1\'])",\r\n        "[contenteditable=\'true\']"\r\n      ].join(",");\r\n      return U.qsa(sel, root).filter(U.isVisible);\r\n    },\r\n    // Body scroll lock (simple)\r\n    lockBody(lock) {\r\n      const cls = "ux4g-scroll-lock";\r\n      if (lock) document.body.classList.add(cls);\r\n      else document.body.classList.remove(cls);\r\n    },\r\n    ensureBackdrop(kind) {\r\n      let bd = U.qs(`.ux4g-backdrop[data-kind="${kind}"]`);\r\n      if (!bd) {\r\n        bd = document.createElement("div");\r\n        bd.className = "ux4g-backdrop";\r\n        bd.setAttribute("data-kind", kind);\r\n        document.body.appendChild(bd);\r\n      }\r\n      return bd;\r\n    },\r\n    removeBackdrop(kind) {\r\n      const bd = U.qs(`.ux4g-backdrop[data-kind="${kind}"]`);\r\n      if (bd) bd.remove();\r\n    },\r\n    // Lightweight positioning (NOT Popper-perfect)\r\n    placeFloating(target, floating, placement = "bottom", offset = 8, constrainToViewport = true) {\r\n      if (!target || !floating) return;\r\n\r\n      let rect = target.getBoundingClientRect();\r\n      const scrollX = window.pageXOffset || document.documentElement.scrollLeft;\r\n      const scrollY = window.pageYOffset || document.documentElement.scrollTop;\r\n      let vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
1\r\n      let vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);\r\n      \r\n      // Temporary show to measure\r\n      const originalDisplay = floating.style.display;\r\n      const originalVisibility = floating.style.visibility;\r\n      floating.style.display = "block";\r\n      floating.style.visibility = "hidden";\r\n      floating.style.position = constrainToViewport ? "fixed" : "absolute";\r\n\r\n      const op = floating.offsetParent;\r\n      if (op && op !== document.body && op !== document.documentElement) {\r\n        const opRect = op.getBoundingClientRect();\r\n        vw = opRect.width;\r\n        vh = opRect.height;\r\n        rect = {\r\n          top: rect.top - opRect.top,\r\n          left: rect.left - opRect.left,\r\n          right: rect.right - opRect.left,\r\n          bottom: rect.bottom - opRect.top,\r\n          width: rect.width,\r\n          height: rect.height\r\n        };\r\n      }\r\n\r\n      if (!constrainToViewport) {\r\n        floating.style.boxSizing = "border-box";\r\n        floating.style.minWidth = "0";\r\n        floating.style.maxWidth = `${Math.max(1, vw - 16)}px`;\r\n        floating.style.overflow = "visible";\r\n      }\r\n\r\n      let fr = floating.getBoundingClientRect();\r\n\r\n      const clamp = (v, min, max) => Math.min(max, Math.max(min, v));\r\n\r\n      const resolvedPlacement = !constrainToViewport ? floating.getAttribute("data-ux-resolved-placement") : null;\r\n      const want = resolvedPlacement || placement;\r\n      const [wantedSide, wantedAlign] = want.split("-");\r\n      const tries = [want];\r\n      const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };\r\n      const sideFallback = opposite[wantedSide];\r\n      \r\n      if (wantedAlign) {\r\n        const alignFallback = wantedAlign === "start" ? "end" : "start";\r\n        tries.push(`${wantedSide}-${alignFallback}`);\r\n        tries.push(wantedSide);\r\n      } else {\r\n        tries.push(`${wantedSide}-start`);\r\n        tries.push(`${wantedSide}-end`);\r\n      }\r\n      \r\n      if (sideFallback) {\r\n        tries.push(sideFallback + (wantedAlign ? \'-\' + wantedAlign : \'\'));\r\n        if (wantedAlign) {\r\n          const alignFallback = wantedAlign === "start" ? "end" : "start";\r\n          tries.push(`${sideFallback}-${alignFallback}`);\r\n          tries.push(sideFallback);\r\n        } else {\r\n          tries.push(`${sideFallback}-start`);\r\n          tries.push(`${sideFallback}-end`);\r\n        }\r\n      }\r\n      \r\n      const altAxis = (wantedSide === "left" || wantedSide === "right") ? ["top", "bottom"] : ["left", "right"];\r\n      altAxis.forEach(axis => {\r\n        ["", "-start", "-end"].forEach(align => {\r\n           const p = axis + align;\r\n           if (!tries.includes(p)) tries.push(p);\r\n        });\r\n      });\r\n      ["bottom", "top", "right", "left"].forEach(s => {\r\n        if (!tries.includes(s)) tries.push(s);\r\n      });\r\n\r\n      const compute = (p) => {\r\n        let t = 0, l = 0;\r\n        const [side, align] = p.split("-");\r\n        \r\n        if (side === "top") {\r\n          t = rect.top - fr.height - offset;\r\n          if (align === "start") l = rect.left;\r\n          else if (align === "end") l = rect.right - fr.width;\r\n          else l = rect.left + (rect.width - fr.width) / 2;\r\n        } else if (side === "bottom") {\r\n          t = rect.bottom + offset;\r\n          if (align === "start") l = rect.left;\r\n          else if (align === "end") l = rect.right - fr.width;\r\n          else l = rect.left + (rect.width - fr.width) / 2;\r\n        } else if (side === "left") {\r\n          l = rect.left - fr.width - offset;\r\n          if (align === "start") t = rect.top;\r\n          else if (align === "end") t = rect.bottom - fr.height;\r\n          else t = rect.top + (rect.height - fr.height) / 2;\r\n        } else if (side === "right") {\r\n          l = rect.right + offset;\r\n          if (align === "start") t = rect.top;\r\n          else if (align === "end") t = rect.bottom - fr.height;\r\n          else t = rect.top + (rect.height - fr.height) / 2;\r\n        } else {\r\n          t = rect.bottom + offset;\r\n          l = rect.left + (rect.width - fr.width) / 2;\r\n          p = "bottom";\r\n        }\r\n        return { t, l, p };\r\n      };\r\n\r\n      let chosen = null;\r\n      if (constrainToViewport || !resolvedPlacement) {\r\n        for (const p of tries) {\r\n          const c = compute(p);\r\n          const fitsH = c.t >= 0 && (c.t + fr.height) <= vh;\r\n          const fitsW = c.l >= 0 && (c.l + fr.width) <= vw;\r\n          if (fitsH && fitsW) { chosen = c; break; }\r\n        }\r\n      }\r\n      if (!chosen && !resolvedPlacement) {\r\n        const visibleArea = c => {\r\n          const visibleWidth = Math.max(0, Math.min(vw, c.l + fr.width) - Math.max(0, c.l));\r\n          const visibleHeight = Math.max(0, Math.min(vh, c.t + fr.height) - Math.max(0, c.t));\r\n          return visibleWidth * visibleHeight;\r\n        };\r\n        chosen = tries.map(compute).sort((a, b) => visibleArea(b) - visibleArea(a))[0];\r\n      }\r\n      if (!chosen) chosen = compute(want);\r\n\r\n      if (!constrainToViewport) {\r\n        floating.setAttribute("data-ux-resolved-placement", chosen.p);\r\n        const [side] = chosen.p.split("-");\r\n        const availableWidth = side === "left"\r\n          ? rect.left - offset - 8\r\n          : side === "right"\r\n            ? vw - rect.right - offset - 8\r\n            : vw - 16;\r\n\r\n        floating.style.maxWidth = `${Math.max(1, availableWidth)}px`;\r\n\r\n        const body = floating.querySelector(".ux4g-popover-body");\r\n        if (body) {\r\n          body.style.boxSizing = "border-box";\r\n          body.style.maxWidth = "100%";
1\r\n          body.style.overflowWrap = "anywhere";\r\n          body.style.wordBreak = "break-word";\r\n        }\r\n\r\n        fr = floating.getBoundingClientRect();\r\n        chosen = compute(chosen.p);\r\n      }\r\n\r\n      floating.style.display = originalDisplay;\r\n      floating.style.visibility = originalVisibility;\r\n\r\n      const [chosenSide] = chosen.p.split("-");\r\n      const hasOp = op && op !== document.body && op !== document.documentElement;\r\n      let top = constrainToViewport\r\n        ? clamp(chosen.t, 8, Math.max(8, vh - fr.height - 8))\r\n        : (hasOp ? chosen.t : chosen.t + scrollY);\r\n      let left = constrainToViewport\r\n        ? clamp(chosen.l, 8, Math.max(8, vw - fr.width - 8))\r\n        : (hasOp ? chosen.l : chosen.l + scrollX);\r\n\r\n      floating.style.position = constrainToViewport ? "fixed" : "absolute";\r\n      floating.style.top = `${top}px`;\r\n      floating.style.left = `${left}px`;\r\n      floating.setAttribute("data-placement", chosen.p);\r\n      \r\n      const isTooltip = floating.classList.contains(\'ux4g-tooltip\');\r\n      const baseClass = isTooltip ? \'ux4g-tooltip\' : \'ux4g-popover\';\r\n      \r\n      const placementPrefix = `${baseClass}-`;\r\n      for (const cls of Array.from(floating.classList)) {\r\n        if (cls.startsWith(placementPrefix) && cls !== baseClass) {\r\n          floating.classList.remove(cls);\r\n        }\r\n      }\r\n      floating.classList.add(`${placementPrefix}${chosen.p}`);\r\n    }\r\n  };\r\n\r\n  const Registry = new WeakMap();\r\n  const getI = (el, key) => (Registry.get(el)?.[key]) || null;\r\n  const setI = (el, key, inst) => {\r\n    let map = Registry.get(el);\r\n    if (!map) { map = {}; Registry.set(el, map); }\r\n    map[key] = inst;\r\n  };\r\n\r\n  const escapeHtml = (s) => String(s)\r\n    .replaceAll("&", "&amp;")\r\n    .replaceAll("<", "&lt;")\r\n    .replaceAll(">", "&gt;")\r\n    .replaceAll(\'"\', "&quot;")\r\n    .replaceAll("\'", "&#039;");\r\n\r\n  // -----------------------------\r\n  // Dropdown\r\n  // -----------------------------\r\n  class Dropdown {\r\n    constructor(toggle) {\r\n      this.toggle = toggle;\r\n      this.menu = this._findMenu(toggle);\r\n      this._open = false;\r\n\r\n      U.on(this.toggle, "click", (e) => {\r\n        e.preventDefault();\r\n        this.toggleDropdown();\r\n      });\r\n\r\n      U.on(document, "click", (e) => {\r\n        if (!this._open) return;\r\n        if (this.menu && (this.menu.contains(e.target) || this.toggle.contains(e.target))) return;\r\n        this.hide();\r\n      });\r\n\r\n      U.on(document, "keydown", (e) => {\r\n        if (!this._open) return;\r\n        if (e.key === "Escape") {\r\n          this.hide();\r\n          this.toggle.focus();\r\n        }\r\n      });\r\n    }\r\n\r\n    _findMenu(toggle) {\r\n      // Standard dropdown structure: .dropdown > [toggle] + .dropdown-menu\r\n      const parent = toggle.parentElement;\r\n      let menu = parent ? parent.querySelector(".dropdown-menu") : null;\r\n      if (!menu) {\r\n        const target = U.data(toggle, "target") || U.attr(toggle, "aria-controls");\r\n        if (target && target.startsWith("#")) menu = U.qs(target);\r\n      }\r\n      return menu;\r\n    }\r\n\r\n    show() {\r\n      if (!this.menu) return;\r\n      this._open = true;\r\n      this.toggle.classList.add("show");\r\n      this.menu.classList.add("show");\r\n      this.toggle.setAttribute("aria-expanded", "true");\r\n\r\n      const placement = U.data(this.toggle, "placement", "bottom");\r\n      const offset = U.num(U.data(this.toggle, "offset", 6), 6);\r\n      U.placeFloating(this.toggle, this.menu, placement, offset);\r\n\r\n      U.dispatch(this.toggle, "ux4g.dropdown.shown", { menu: this.menu });\r\n    }\r\n\r\n    hide() {\r\n      if (!this.menu) return;\r\n      this._open = false;\r\n      this.toggle.classList.remove("show");\r\n      this.menu.classList.remove("show");\r\n      this.toggle.setAttribute("aria-expanded", "false");\r\n      U.dispatch(this.toggle, "ux4g.dropdown.hidden", { menu: this.menu });\r\n    }\r\n\r\n    toggleDropdown() { this._open ? this.hide() : this.show(); }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "dropdown");\r\n      if (!inst) { inst = new Dropdown(el); setI(el, "dropdown", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Collapse / Accordion\r\n  // -----------------------------\r\n  class Collapse {\r\n    constructor(trigger) {\r\n      this.trigger = trigger;\r\n      this.target = this._resolveTarget(trigger);\r\n      // ux4g accordion uses data-bs-parent on .collapse\r\n      this.parentSel = U.data(this.target, "parent") || U.data(this.trigger, "parent");\r\n      this.duration = this._readDuration(this.target, 200);\r\n\r\n      U.on(this.trigger, "click", (e) => {\r\n        e.preventDefault();\r\n        this.toggle();\r\n      });\r\n    }\r\n\r\n    _resolveTarget(trigger) {\r\n      const sel = U.data(trigger, "target") || U.attr(trigger, "href") || U.attr(trigger, "aria-controls") || U.attr(trigger, "ux4g-target");\r\n      if (sel && sel.startsWith("#")) return U.qs(sel);\r\n      return U.qs("#" + sel);\r\n    }\r\n\r\n    _readDuration(el, fallbackMs) {\r\n      if (!el) return fallbackMs;\r\n      const d = getComputedStyle(el).transitionDuration || "";\r\n      const ms = d.includes("ms") ? parseFloat(d) : (d.includes("s") ? parseFloat(d) * 1000 : NaN);\r\n      return Number.isFinite(ms) && ms > 0 ? ms : fallbackMs;\r\n    }\r\n\r\n    show() {\r\n      if (!this.target) return;\r\n\r\n      // Accordion: close other open within parent\r\n      if (this.parentSel) {\r\n        const parent = U.qs(this.parentSel);\r\n        if (parent) {\r\n          U.qsa(".collapse.show", parent).forEach((el) => {\r\n            if (el === this.target) return;\r\n            el.classList.remove("show");\r\n            // update triggers for that element\r\n            if (el.id) {\r\n              U.qsa(`[data-bs-target="#${el.id}"],[data-ux-target="#${el.id}"],[ux4g-target="#${el.id}"],a[href="#${el.id}"]`)\r\n                .forEach(t => {\r\n                  t.classList.add("collapsed");\r\n                  t.setAttribute("aria-expanded", "false");\r\n                });\r\n            }\r\n          });\r\n        }\r\n      }\r\n\r\n      // Animate height\r\n      this.target.classList.add("collapsing");\r\n      this.target.classList.remove("collapse");\r\n      this.target.style.height = "0px";\r\n      U.reflow(this.target);\r\n\r\n      const h = this.target.scrollHeight;\r\n      this.target.style.height = h + "px";\r\n\r\n      this.trigger.classList.remove("collapsed");\r\n      this.trigger.setAttribute("aria-expanded", "true");\r\n\r\n      window.setTimeout(() => {\r\n        this.target.classList.remove("collapsing");\r\n        this.target.classList.add("collapse", "show");\r\n        this.target.style.height = "";\r\n        U.dispatch(this.target, "ux4g.collapse.shown", {});\r\n      }, this.duration);\r\n    }\r\n\r\n    hide() {\r\n      if (!this.target) return;\r\n\r\n      this.target.style.height = this.target.getBoundingClientRect().height + "px";\r\n      U.reflow(this.target);\r\n\r\n      this.target.classList.add("collapsing");\r\n      this.target.classList.remove("collapse", "show");\r\n\r\n      this.trigger.classList.add("collapsed");\r\n      this.trigger.setAttribute("aria-expanded", "false");\r\n\r\n      window.setTimeout(() => {\r\n        this.target.style.height = "0px";\r\n      }, 10);\r\n\r\n      window.setTimeout(() => {\r\n        this.target.classList.remove("collapsing");\r\n        this.target.classList.add("collapse");\r\n        this.target.style.height = "";\r\n        U.dispatch(this.target, "ux4g.collapse.hidden", {});\r\n      }, this.duration);\r\n    }\r\n\r\n    toggle() {\r\n      if (!this.target) return;\r\n      this.target.classList.contains("show") ? this.hide() : this.show();\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "collapse");\r\n      if (!inst) { inst = new Collapse(el); setI(el, "collapse", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Offcanvas\r\n  // -----------------------------\r\n  class Offcanvas {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this._shown = false;\r\n      this._bdKind = "offcanvas";\r\n      this._lastFocus = null;\r\n      this.duration = this._readDuration(el, 250);\r\n\r\n      U.on(this.el, "click", (e) => {\r\n        const dismiss = U.closest(e.target, \'[data-bs-dismiss="offcanvas"],[data-ux-dismiss="offcanvas"]\');\r\n        if (dismiss) {\r\n          e.preventDefault();\r\n          this.hide();\r\n        }\r\n      });\r\n\r\n      U.on(document, "keydown", (e) => {\r\n        if (!this._shown) return;
1\r\n        if (e.key === "Escape") {\r\n          const kb = U.bool(U.data(this.el, "keyboard", "true"), true);\r\n          if (kb) this.hide();\r\n        } else if (e.key === "Tab") {\r\n          this._trapTab(e);\r\n        }\r\n      });\r\n    }\r\n\r\n    _readDuration(el, fallbackMs) {\r\n      if (!el) return fallbackMs;\r\n      const d = getComputedStyle(el).transitionDuration || "";\r\n      const ms = d.includes("ms") ? parseFloat(d) : (d.includes("s") ? parseFloat(d) * 1000 : NaN);\r\n      return Number.isFinite(ms) && ms > 0 ? ms : fallbackMs;\r\n    }\r\n\r\n    _trapTab(e) {\r\n      const f = U.focusables(this.el);\r\n      if (!f.length) return;\r\n      const first = f[0], last = f[f.length - 1];\r\n      if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }\r\n      else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }\r\n    }\r\n\r\n    show(trigger) {\r\n      if (this._shown) return;\r\n      this._shown = true;\r\n      this._lastFocus = document.activeElement;\r\n\r\n      const backdropOpt = U.data(this.el, "backdrop", "true");\r\n      const backdrop = backdropOpt !== "false";\r\n\r\n      if (backdrop) {\r\n        const bd = U.ensureBackdrop(this._bdKind);\r\n        bd.classList.add("show");\r\n        U.on(bd, "click", () => {\r\n          if (backdropOpt === "static") return;\r\n          this.hide();\r\n        });\r\n      }\r\n\r\n      U.lockBody(true);\r\n      this.el.style.visibility = "visible";\r\n      this.el.classList.add("show");\r\n      this.el.setAttribute("aria-modal", "true");\r\n\r\n      const focus = U.bool(U.data(this.el, "focus", "true"), true);\r\n      if (focus) {\r\n        const f = U.focusables(this.el);\r\n        (f[0] || this.el).focus({ preventScroll: true });\r\n      }\r\n\r\n      U.dispatch(this.el, "ux4g.offcanvas.shown", { relatedTarget: trigger || null });\r\n    }\r\n\r\n    hide() {\r\n      if (!this._shown) return;\r\n      this._shown = false;\r\n\r\n      this.el.classList.remove("show");\r\n      this.el.removeAttribute("aria-modal");\r\n\r\n      window.setTimeout(() => {\r\n        this.el.style.visibility = "";\r\n        U.lockBody(false);\r\n        U.removeBackdrop(this._bdKind);\r\n\r\n        if (this._lastFocus && typeof this._lastFocus.focus === "function") {\r\n          this._lastFocus.focus({ preventScroll: true });\r\n        }\r\n        U.dispatch(this.el, "ux4g.offcanvas.hidden", {});\r\n      }, this.duration);\r\n    }\r\n\r\n    toggle(trigger) { this._shown ? this.hide() : this.show(trigger); }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "offcanvas");\r\n      if (!inst) { inst = new Offcanvas(el); setI(el, "offcanvas", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Tooltip / Popover (lightweight)\r\n  // -----------------------------\r\n  let floatingId = 0;\r\n\r\n  class Floating {\r\n    constructor(el, kind) {\r\n      this.el = el;\r\n      this.kind = kind; // tooltip | popover\r\n      this._open = false;\r\n      this._floating = null;\r\n      this._uid = ++floatingId;\r\n      this._warnings = new Set();\r\n\r\n      this.placement = U.data(el, "placement", kind === "tooltip" ? "top" : "right");\r\n      this.offset = U.num(U.data(el, "offset", 8), 8);\r\n      this.trigger = U.data(el, "trigger", kind === "tooltip" ? "hover focus" : "click");\r\n      this.html = U.bool(U.data(el, "html", "false"), false);\r\n\r\n      if (this.kind === "popover") {\r\n        const contentId = U.data(this.el, "content-id");\r\n        const source = contentId\r\n          ? (this.el.ownerDocument || document).getElementById(contentId)\r\n          : null;\r\n        if (source && source.tagName !== "TEMPLATE") {\r\n          source.hidden = true;\r\n        }\r\n      }\r\n\r\n      this._bind();\r\n    }\r\n\r\n    _warn(message) {\r\n      if (this._warnings.has(message)) return;\r\n      this._warnings.add(message);\r\n      console.warn(`[UX4G Popover] ${message}`);\r\n    }\r\n\r\n    _rewriteClonedIds(fragment) {\r\n      const idMap = new Map();\r\n      U.qsa("[id]", fragment).forEach((element) =>
1 {\r\n        const originalId = element.id;\r\n        const clonedId = `ux4g-popover-${this._uid}-${originalId}`;\r\n        idMap.set(originalId, clonedId);\r\n        element.id = clonedId;\r\n      });\r\n\r\n      const tokenReferenceAttributes = [\r\n        "aria-controls",\r\n        "aria-describedby",\r\n        "aria-details",\r\n        "aria-labelledby",\r\n        "aria-owns",\r\n        "for"\r\n      ];\r\n\r\n      U.qsa("*", fragment).forEach((element) => {\r\n        tokenReferenceAttributes.forEach((attribute) => {\r\n          const value = element.getAttribute(attribute);\r\n          if (!value) return;\r\n          const rewritten = value\r\n            .split(/\\s+/)\r\n            .map((token) => idMap.get(token) || token)\r\n            .join(" ");\r\n          element.setAttribute(attribute, rewritten);\r\n        });\r\n\r\n        const href = element.getAttribute("href");\r\n        if (href && href.startsWith("#") && idMap.has(href.slice(1))) {\r\n          element.setAttribute("href", `#${idMap.get(href.slice(1))}`);\r\n        }\r\n      });\r\n    }\r\n\r\n    _getContentFragment() {\r\n      if (this.kind !== "popover") return null;\r\n\r\n      const contentId = U.data(this.el, "content-id");\r\n      if (!contentId) return null;\r\n\r\n      if (U.data(this.el, "content") != null) {\r\n        this._warn(\r\n          `Both data-ux-content-id and data-ux-content are set; ` +\r\n          `data-ux-content-id="${contentId}" takes precedence.`\r\n        );\r\n      }\r\n\r\n      const ownerDocument = this.el.ownerDocument || document;\r\n      const matches = U.qsa("[id]", ownerDocument)\r\n        .filter((element) => element.id === contentId);\r\n      const source = ownerDocument.getElementById(contentId);\r\n\r\n      if (!source) {\r\n        this._warn(`No content element found with id "${contentId}".`);\r\n        return ownerDocument.createDocumentFragment();\r\n      }\r\n\r\n      if (matches.length > 1) {\r\n        this._warn(\r\n          `Multiple elements use id "${contentId}". IDs must be unique; ` +\r\n          `the first matching element will be used.`\r\n        );\r\n      }\r\n\r\n      const fragment = source.tagName === "TEMPLATE"\r\n        ? source.content.cloneNode(true)\r\n        : (() => {\r\n            source.hidden = true;\r\n            const clone = ownerDocument.createDocumentFragment();\r\n            Array.from(source.childNodes).forEach((node) => {\r\n              clone.appendChild(node.cloneNode(true));\r\n            });\r\n            return clone;\r\n          })();\r\n\r\n      this._rewriteClonedIds(fragment);\r\n      return fragment;\r\n    }\r\n\r\n    _getAnchorParent() {\r\n      const ownerDocument = this.el.ownerDocument || document;\r\n      let anchorParent = this.el.parentElement || ownerDocument.body;\r\n      let ancestor = anchorParent;\r\n\r\n      while (ancestor && ancestor !== ownerDocument.body) {\r\n        const style = getComputedStyle(ancestor);\r\n        const clipsContent = [style.overflow, style.overflowX, style.overflowY]\r\n          .some((value) => value && value !== "visible");\r\n\r\n        if (clipsContent && ancestor.parentElement) {\r\n          anchorParent = ancestor.parentElement;\r\n        }\r\n        ancestor = ancestor.parentElement;\r\n      }\r\n\r\n      return anchorParent;\r\n    }\r\n\r\n    _getContent() {\r\n      const content = U.data(this.el, "content");\r\n      if (this.kind === "popover") {\r\n        const hasContentId = !!U.data(this.el, "content-id");\r\n        const title = U.data(this.el, "title") || this.el.getAttribute("title") || "";\r\n        const subtitle = U.data(this.el, "subtitle") || "";\r\n        const icon = U.data(this.el, "icon") || "";\r\n        const label = U.data(this.el, "label") || "";\r\n        const actionHtml = U.data(this.el, "action-html") || "";\r\n\r\n        const t = this.html ? String(title) : escapeHtml(title);\r\n        const s = this.html ? String(subtitle) : escapeHtml(subtitle);\r\n        const c = hasContentId\r\n          ? ""\r\n          : (this.html ? String(content || "") : escapeHtml(content || ""));\r\n        const i = this.html ? String(icon) : escapeHtml(icon);\r\n        const l = this.html ? String(label) : escapeHtml(label);\r\n\r\n        let inner = "";\r\n        if (t || s) {\r\n          inner += `<div class="ux4g-popover-header">\r\n            <div class="ux4g-popover-title-row">\r\n              <div class="ux4g-popover-title">\r\n                ${i ? `<i class="ux4g-icon">${i}</i>` : ""}
1\r\n                <span>${t}</span>\r\n                ${l ? `<span class="ux4g-tag-outline-brand">${l}</span>` : ""}\r\n              </div>\r\n              ${actionHtml ? `\r\n                  ${actionHtml}\r\n              ` : ""}\r\n            </div>\r\n            ${s ? `<div class="ux4g-popover-subtitle">${s}</div>` : ""}\r\n          </div>`;\r\n        }\r\n        inner += `<div class="ux4g-popover-body">${c}</div>`;\r\n        \r\n        const hasArrow = U.bool(U.data(this.el, "arrow", "true"), true);\r\n        if (hasArrow) {\r\n          inner += \'<div class="ux4g-popover-arrow"><i class="ux4g-icon">arrow_drop_up</i></div>\';\r\n        }\r\n        \r\n        return inner;\r\n      }\r\n\r\n      const t = content != null ? content : (this.el.getAttribute("title") || "");\r\n      return this.html ? String(t) : escapeHtml(t);\r\n    }\r\n\r\n    _create() {\r\n      if (this._floating) return;\r\n      const div = document.createElement("div");\r\n      div.className = this.kind === "tooltip" ? "ux4g-tooltip" : "ux4g-popover";\r\n      div.setAttribute("role", this.kind === "tooltip" ? "tooltip" : "dialog");\r\n      div.id = `ux4g-${this.kind}-${this._uid}`;\r\n      \r\n      const hasArrow = U.bool(U.data(this.el, "arrow", "true"), true);\r\n      if (!hasArrow) {\r\n        div.classList.add("ux4g-popover-no-arrow");\r\n      }\r\n\r\n      div.innerHTML = this._getContent() || "";\r\n      const contentFragment = this._getContentFragment();\r\n      if (contentFragment) {\r\n        const body = div.querySelector(".ux4g-popover-body");\r\n        if (body) body.appendChild(contentFragment);\r\n      }\r\n      const anchorParent = this._getAnchorParent();\r\n      const anchorPosition = getComputedStyle(anchorParent).position;\r\n      if (!anchorPosition || anchorPosition === "static") {\r\n        anchorParent.style.position = "relative";\r\n      }\r\n      anchorParent.appendChild(div);\r\n      this._floating = div;\r\n\r\n      this.el.setAttribute("aria-controls", div.id);\r\n      this.el.setAttribute("aria-expanded", "false");\r\n      if (this.kind === "popover") {\r\n        this.el.setAttribute("aria-haspopup", "dialog");\r\n      }\r\n    }\r\n\r\n    show() {\r\n      if (this._open) return;\r\n      this._open = true;\r\n\r\n      // Prevent native tooltip doubling\r\n      if (this.kind === "tooltip") {\r\n        const t = this.el.getAttribute("title");\r\n        if (t != null) {\r\n          this.el.setAttribute("data-ux-original-title", t);\r\n          this.el.removeAttribute("title");\r\n        }\r\n      }\r\n\r\n      this._create();\r\n      this._floating.style.display = "block";\r\n      this._floating.classList.add("show");\r\n      this.el.setAttribute("aria-expanded", "true");\r\n      \r\n      init(this._floating);\r\n      U.dispatch(this.el, `ux4g.${this.kind}.contentmounted`, {\r\n        floating: this._floating\r\n      });\r\n      \r\n      const update = () => {\r\n        if (!this._open) return;\r\n        if (!this.el.isConnected) {\r\n          this.hide();\r\n          if (this._floating) {\r\n            this._floating.remove();\r\n            this._floating = null;\r\n          }\r\n          return;\r\n        }\r\n        U.placeFloating(this.el, this._floating, this.placement, this.offset, true);\r\n        if (this.kind !== "popover") this._raf = requestAnimationFrame(update);\r\n      };\r\n      this._onWin = update;\r\n      if (this.kind === "popover") {\r\n        update();\r\n      } else {\r\n        this._raf = requestAnimationFrame(update);\r\n      }\r\n\r\n      U.on(window, "scroll", this._onWin, { capture: true, passive: true });\r\n      U.on(window, "resize", this._onWin);\r\n\r\n      if (this.kind === "popover" && typeof MutationObserver !== "undefined") {\r\n        this._domObserver?.disconnect();\r\n        this._domObserver = new MutationObserver(() => {\r\n          if (this.el.isConnected) return;\r\n          this.hide();\r\n          if (this._floating) {\r\n            this._floating.remove();\r\n            this._floating = null;\r\n          }\r\n        });\r\n        this._domObserver.observe(\r\n          (this.el.ownerDocument || document).body,\r\n          { childList: true, subtree: true }\r\n        );\r\n      }\r\n\r\n      U.dispatch(this.el, `ux4g.${this.kind}.shown`, {});\r\n    }\r\n\r\n    hide() {\r\n      if (!this._open) return;\r\n      this._open = false;\r\n\r\n      if (this._floating) {\r\n        this._floating.classList.remove("show");\r\n        this._floating.style.display = "none";\r\n        this._floating.removeAttribute("data-ux-resolved-placement");\r\n      }\r\n      this.el.setAttribute("aria-expanded", "false");\r\n\r\n      if (this.kind === "tooltip") {\r\n        const ot = this.el.getAttribute("data-ux-original-title");\r\n        if (ot != null) {\r\n          this.el.setAttribute("title", ot);\r\n          this.el.removeAttribute("data-ux-original-title");\r\n        }\r\n      }\r\n\r\n      if (this._raf) {\r\n        cancelAnimationFrame(this._raf);\r\n        this._raf = null;\r\n      }\r\n\r\n      if (this._onWin) {\r\n        U.off(window, "scroll", this._onWin, { capture: true });\r\n        U.off(window, "resize", this._onWin);\r\n        this._onWin = null;\r\n      }\r\n\r\n      if (this._domObserver) {\r\n        this._domObserver.disconnect();\r\n        this._domObserver = null;\r\n      }\r\n\r\n      U.dispatch(this.el, `ux4g.${this.kind}.hidden`, {});\r\n    }\r\n\r\n    toggle() { this._open ? this.hide() : this.show(); }\r\n\r\n    _bind() {\r\n      let triggers = String(this.trigger).split(/\\s+/).filter(
1Boolean);\r\n      \r\n      if (this.kind === "popover") {\r\n        triggers = triggers.filter(t => t !== "hover");\r\n        if (!triggers.length) triggers = ["click"];\r\n      }\r\n\r\n      if (triggers.includes("hover")) {\r\n        U.on(this.el, "mouseenter", () => this.show());\r\n        U.on(this.el, "mouseleave", () => this.hide());\r\n      }\r\n      if (triggers.includes("focus")) {\r\n        U.on(this.el, "focus", () => this.show());\r\n        U.on(this.el, "blur", () => this.hide());\r\n      }\r\n      if (triggers.includes("click")) {\r\n        U.on(this.el, "click", (e) => { e.preventDefault(); this.toggle(); });\r\n\r\n        U.on(document, "click", (e) => {\r\n          if (!this._open) return;\r\n          if (this.el.contains(e.target) || (this._floating && this._floating.contains(e.target))) return;\r\n          this.hide();\r\n        });\r\n\r\n        U.on(document, "keydown", (e) => {\r\n          if (!this._open) return;\r\n          if (e.key === "Escape") {\r\n            e.preventDefault();\r\n            this.hide();\r\n            window.setTimeout(() => {\r\n              this.el.focus({ preventScroll: true });\r\n            }, 0);\r\n          }\r\n        });\r\n      }\r\n    }\r\n\r\n    static getOrCreate(el, kind) {\r\n      const key = kind;\r\n      let inst = getI(el, key);\r\n      if (!inst) { inst = new Floating(el, kind); setI(el, key, inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Toast\r\n  // -----------------------------\r\n  class Toast {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this._timer = null;\r\n\r\n      U.on(this.el, "click", (e) => {\r\n        const dismiss = U.closest(e.target, \'[data-bs-dismiss="toast"],[data-ux-dismiss="toast"],.close-toast\');\r\n        if (dismiss) {\r\n          e.preventDefault();\r\n          this.hide();\r\n        }\r\n      });\r\n    }\r\n\r\n    show() {\r\n      this.el.classList.add("show");\r\n      this.el.classList.remove("hide");\r\n\r\n      const autohide = U.bool(U.data(this.el, "autohide", "true"), true);\r\n      const delay = U.num(U.data(this.el, "delay", 5000), 5000);\r\n\r\n      if (autohide) {\r\n        clearTimeout(this._timer);\r\n        this._timer = setTimeout(() => this.hide(), delay);\r\n      }\r\n      U.dispatch(this.el, "ux4g.toast.shown", {});\r\n    }\r\n\r\n    hide() {\r\n      this.el.classList.remove("show");\r\n      this.el.classList.add("hide");\r\n      clearTimeout(this._timer);\r\n      U.dispatch(this.el, "ux4g.toast.hidden", {});\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "toast");\r\n      if (!inst) { inst = new Toast(el); setI(el, "toast", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Carousel\r\n  // -----------------------------\r\n  class Carousel {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this.items = U.qsa(".carousel-item", el);\r\n      this.indicators = U.qsa("[data-bs-slide-to],[data-ux-slide-to]", el);\r\n      this.interval = U.num(U.data(el, "interval", 5000), 5000);\r\n      this.ride = U.data(el, "ride");\r\n      this.pause = U.data(el, "pause", "hover");\r\n      this.wrap = U.bool(U.data(el, "wrap", "true"), true);\r\n      this._timer = null;\r\n\r\n      U.on(el, "click", (e) => {\r\n        const prev = U.closest(e.target, \'[data-bs-slide="prev"],[data-ux-slide="prev"]\');\r\n        const next = U.closest(e.target, \'[data-bs-slide="next"],[data-ux-slide="next"]\');\r\n        if (prev) { e.preventDefault(); this.prev(); }\r\n        if (next) { e.preventDefault(); this.next(); }\r\n\r\n        const ind = U.closest(e.target, "[data-bs-slide-to],[data-ux-slide-to]");\r\n        if (ind) {\r\n          e.preventDefault();\r\n          const v = ind.getAttribute("data-bs-slide-to") ?? ind.getAttribute("data-ux-slide-to");\r\n          this.to(U.num(v, 0));\r\n        }\r\n      });\r\n\r\n      if (this.pause === "hover") {\r\n        U.on(el, "mouseenter", () => this._stop());\r\n        U.on(el, "mouseleave", () => this._start());\r\n      }\r\n\r\n      if (this.ride === "carousel") this._start();\r\n    }\r\n\r\n    _activeIndex() {\r\n      const idx = this.items.findIndex(i => i.classList.contains("active"));\r\n      return idx >= 0 ? idx : 0;\r\n    }
1\r\n\r\n    _setActive(nextIndex) {\r\n      if (!this.items.length) return;\r\n      const cur = this._activeIndex();\r\n\r\n      if (nextIndex < 0) nextIndex = this.wrap ? this.items.length - 1 : 0;\r\n      if (nextIndex >= this.items.length) nextIndex = this.wrap ? 0 : this.items.length - 1;\r\n      if (cur === nextIndex) return;\r\n\r\n      this.items[cur]?.classList.remove("active");\r\n      this.items[nextIndex]?.classList.add("active");\r\n\r\n      this.indicators.forEach(ind => ind.classList.remove("active"));\r\n      const ind = this.indicators.find(x => {\r\n        const v = x.getAttribute("data-bs-slide-to") ?? x.getAttribute("data-ux-slide-to");\r\n        return U.num(v, -1) === nextIndex;\r\n      });\r\n      if (ind) ind.classList.add("active");\r\n\r\n      U.dispatch(this.el, "ux4g.carousel.slid", { from: cur, to: nextIndex });\r\n    }\r\n\r\n    next() { this._setActive(this._activeIndex() + 1); }\r\n    prev() { this._setActive(this._activeIndex() - 1); }\r\n    to(i) { this._setActive(i); }\r\n\r\n    _start() {\r\n      if (this._timer || this.interval <= 0) return;\r\n      this._timer = setInterval(() => this.next(), this.interval);\r\n    }\r\n\r\n    _stop() { clearInterval(this._timer); this._timer = null; }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "carousel");\r\n      if (!inst) { inst = new Carousel(el); setI(el, "carousel", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Tabs\r\n  // -----------------------------\r\n  class Tab {\r\n    constructor(el) {\r\n      this.el = el;\r\n\r\n      U.on(el, "click", (e) => { e.preventDefault(); this.show(); });\r\n\r\n      U.on(el, "keydown", (e) => {\r\n        if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;\r\n        const list = U.closest(this.el, ".nav, [role=\'tablist\']");\r\n        if (!list) return;\r\n\r\n        const tabs = U.qsa("[data-bs-toggle=\'tab\'],[data-ux-toggle=\'tab\'],[role=\'tab\']", list);\r\n        const idx = tabs.indexOf(this.el);\r\n        if (idx < 0) return;\r\n\r\n        e.preventDefault();\r\n        const next = (e.key === "ArrowRight") ? idx + 1 : idx - 1;\r\n        const wrapIdx = (next + tabs.length) % tabs.length;\r\n        tabs[wrapIdx].focus();\r\n        Tab.getOrCreate(tabs[wrapIdx]).show();\r\n      });\r\n    }\r\n\r\n    _target() {\r\n      const sel = U.data(this.el, "target") || U.attr(this.el, "href") || U.attr(this.el, "data-target");\r\n      if (sel && sel.startsWith("#")) return U.qs(sel);\r\n      const controls = this.el.getAttribute("aria-controls");\r\n      if (controls) return U.qs("#" + controls);\r\n      return null;\r\n    }\r\n\r\n    show() {\r\n      const list = U.closest(this.el, ".nav, [role=\'tablist\']");\r\n      const pane = this._target();\r\n      if (!list || !pane) return;\r\n\r\n      const tabs = U.qsa("[data-bs-toggle=\'tab\'],[data-ux-toggle=\'tab\'],[role=\'tab\']", list);
1\r\n      tabs.forEach(t => {\r\n        t.classList.remove("active");\r\n        t.setAttribute("aria-selected", "false");\r\n        t.setAttribute("tabindex", "-1");\r\n      });\r\n\r\n      this.el.classList.add("active");\r\n      this.el.setAttribute("aria-selected", "true");\r\n      this.el.setAttribute("tabindex", "0");\r\n\r\n      const container = U.closest(pane, ".tab-content") || pane.parentElement;\r\n      const panes = container ? U.qsa(".tab-pane", container) : [];\r\n      panes.forEach(p => p.classList.remove("active", "show"));\r\n\r\n      pane.classList.add("active", "show");\r\n      U.dispatch(this.el, "ux4g.tab.shown", { relatedTarget: pane });\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "tab");\r\n      if (!inst) { inst = new Tab(el); setI(el, "tab", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Scrollspy\r\n  // -----------------------------\r\n  class ScrollSpy {\r\n    constructor(el) {\r\n      this.el = el; // element with data-bs-spy="scroll"\r\n      this.targetSel = U.data(el, "target");\r\n      this.offset = U.num(U.data(el, "offset", 10), 10);\r\n      this._links = [];\r\n      this._sections = [];\r\n\r\n      this.refresh();\r\n      this._bind();\r\n    }\r\n\r\n    refresh() {\r\n      const nav = this.targetSel ? U.qs(this.targetSel) : null;\r\n      if (!nav) return;\r\n\r\n      this._links = U.qsa(\'a[href^="#"]\', nav)\r\n        .filter(a => a.getAttribute("href").length > 1);\r\n\r\n      this._sections = this._links\r\n        .map(a => U.qs(a.getAttribute("href")))\r\n        .filter(Boolean);\r\n    }\r\n\r\n    _activate(id) {\r\n      const nav = this.targetSel ? U.qs(this.targetSel) : null;\r\n      if (!nav) return;\r\n\r\n      this._links.forEach(a => a.classList.remove("active"));\r\n      const link = this._links.find(a => a.getAttribute("href") === "#" + id);\r\n      if (link) link.classList.add("active");\r\n    }\r\n\r\n    _bind() {\r\n      // If the spy is on body, use window; else use that element\r\n      const container = (this.el === document.body || this.el === document.documentElement) ? window : this.el;\r\n\r\n      if ("IntersectionObserver" in window) {\r\n        const root = (container === window) ? null : this.el;\r\n\r\n        const io = new IntersectionObserver((entries) => {\r\n          const visible = entries\r\n            .filter(e => e.isIntersecting)\r\n            .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];\r\n          if (visible?.target?.id) this._activate(visible.target.id);\r\n        }, {\r\n          root,\r\n          rootMargin: `-${this.offset}px 0px -60% 0px`,\r\n          threshold: [0.1, 0.25, 0.5, 0.75]\r\n        });\r\n\r\n        this._sections.forEach(s => io.observe(s));\r\n        this._io = io;\r\n        return;\r\n      }\r\n\r\n      this._onScroll = () => {\r\n        const scrollTop = (container === window) ? window.pageYOffset : this.el.scrollTop;\r\n        let active = null;\r\n\r\n        for (const s of this._sections) {\r\n          const top = s.getBoundingClientRect().top + window.pageYOffset;\r\n          if (scrollTop + this.offset >= top) active = s;\r\n        }\r\n        if (active?.id) this._activate(active.id);\r\n      };\r\n\r\n      U.on(container, "scroll", this._onScroll, { passive: true });\r\n      this._onScroll();\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "scrollspy");\r\n      if (!inst) { inst = new ScrollSpy(el); setI(el, "scrollspy", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Table\r\n  // -----------------------------\r\n  class Table {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this._bindSort();\r\n      this._bindResize();\r\n      this._bindSelection();\r\n      this._bindFilter();\r\n    }\r\n\r\n    _bindFilter() {\r\n      const filterBtns = U.qsa(".ux4g-table-filter-icon", this.el);\r\n      filterBtns.forEach(btn => {\r\n        U.on(btn, "click", (e) => {\r\n          e.preventDefault();\r\n          e.stopPropagation();\r\n          const targetTh = U.closest(btn, "th");\r\n          if (targetTh) {\r\n            // Close other filters first if needed or just toggle this one\r\n            targetTh.
1classList.toggle("ux4g-is-filtering");\r\n            if (targetTh.classList.contains("ux4g-is-filtering")) {\r\n              const input = U.qs(".ux4g-search-input", targetTh);\r\n              if (input) input.focus();\r\n            }\r\n          }\r\n        });\r\n      });\r\n\r\n      const closeBtns = U.qsa(".ux4g-search-clear", this.el);\r\n      closeBtns.forEach(btn => {\r\n        U.on(btn, "click", (e) => {\r\n          // Only close if it\'s within a table filter\r\n          const th = U.closest(btn, "th.ux4g-is-filtering");\r\n          if (th) {\r\n            e.preventDefault();\r\n            e.stopPropagation();\r\n            th.classList.remove("ux4g-is-filtering");\r\n            const input = U.qs(".ux4g-search-input", th);\r\n            if (input) {\r\n               input.value = \'\';\r\n               const container = U.closest(input, \'.ux4g-search-container\');\r\n               if (container) container.classList.remove(\'ux4g-has-value\');\r\n            }\r\n          }\r\n        });\r\n      });\r\n\r\n      const inputs = U.qsa("th .ux4g-search-input", this.el);\r\n      inputs.forEach(input => {\r\n        U.on(input, "input", (e) => {\r\n           const container = U.closest(input, \'.ux4g-search-container\');\r\n           if (container) {\r\n              if (input.value.length > 0) {\r\n                 container.classList.add(\'ux4g-has-value\');\r\n              } else {\r\n                 container.classList.remove(\'ux4g-has-value\');\r\n              }\r\n           }\r\n        });\r\n      });\r\n    }\r\n\r\n    _bindSort() {\r\n      const sortableCols = U.qsa(".ux4g-table-sortable th[data-sort]", this.el);\r\n      sortableCols.forEach(th => {\r\n        if (!U.qs(".ux4g-table-sort-icon", th)) {\r\n          const content = U.qs(".ux4g-table-th-content", th) || th;\r\n          const icon = document.createElement("i");\r\n          icon.className = "ux4g-icon ux4g-table-sort-icon";\r\n          icon.innerHTML = "arrow_downward";\r\n          content.appendChild(icon);\r\n        }\r\n\r\n        U.on(th, "click", (e) => {\r\n          // If the click happened on a filter button or something else interactive, ignore sort\r\n          if (U.closest(e.target, ".ux4g-table-filter-icon") || U.closest(e.target, ".ux4g-search-input") || U.closest(e.target, ".ux4g-search-clear")) {\r\n             return;\r\n          }\r\n\r\n          const currentSort = U.attr(th, "data-sort", "none");\r\n          // Cycle: none -> asc -> desc -> asc... (skip none once sorted to avoid double clicks)\r\n          const nextSort = currentSort === "asc" ? "desc" : "asc";\r\n          \r\n          // Reset other columns in the same table\r\n          sortableCols.forEach(otherTh => {\r\n            if (otherTh !== th) otherTh.setAttribute("data-sort", "none");\r\n          });\r\n\r\n          th.setAttribute("data-sort", nextSort);\r\n          \r\n          // Row sorting logic\r\n          if (nextSort !== "none") {\r\n             const tbody = U.qs("tbody", this.el);\r\n             if (tbody) {\r\n                const trs = Array.from(tbody.querySelectorAll("tr"));\r\n                const thIndex = Array.from(th.parentNode.children).indexOf(th);\r\n                \r\n                trs.sort((a, b) => {\r\n                   const aCol = a.children[thIndex];\r\n                   const bCol = b.children[thIndex];\r\n                   if (!aCol || !bCol) return 0;\r\n                   \r\n                   const aText = (aCol.textContent || aCol.innerText).trim();\r\n                   const bText = (bCol.textContent || bCol.innerText).trim();\r\n                   \r\n                   const cleanV1 = aText.replace(/[₹$,\\s]/g, "");\r\n                   const cleanV2 = bText.replace(/[₹$,\\s]/g, "");\r\n                   const num1 = Number(cleanV1);\r\n                   const num2 = Number(cleanV2);\r\n                   \r\n                   const isNum = !isNaN(num1) && !isNaN(num2) && cleanV1 !== "" && cleanV2 !== "";\r\n                   \r\n                   if (isNum) {\r\n                      return nextSort === "asc" ? (num1 - num2) : (num2 - num1);\r\n                   } else {\r\n                      const comp = aText.localeCompare(bText, undefined, { numeric: true, sensitivity: \'base\' });\r\n                      return nextSort === "asc" ? comp : -comp;\r\n                   }\r\n                });
1\r\n                \r\n                trs.forEach(tr => tbody.appendChild(tr));\r\n             }\r\n          }\r\n\r\n          U.dispatch(this.el, "ux4g.table.sort", { column: th, direction: nextSort });\r\n        });\r\n      });\r\n    }\r\n\r\n    _bindResize() {\r\n      // Check if this table instance has resize enabled\r\n      if (!this.el.classList.contains("ux4g-table-resizable")) return;\r\n      const resizableCols = U.qsa("th", this.el);\r\n\r\n      resizableCols.forEach(th => {\r\n        // Skip last child to avoid out-of-bounds drag or provide a cleaner UX edge\r\n        if (th === th.parentNode.lastElementChild) return;\r\n\r\n        const handle = document.createElement("div");\r\n        handle.className = "ux4g-table-resize-handle";\r\n        th.appendChild(handle);\r\n\r\n        let startX, startWidth;\r\n        const onMouseMove = (e) => {\r\n          const newWidth = Math.max(40, startWidth + (e.clientX - startX));\r\n          th.style.width = `${newWidth}px`;\r\n          th.style.minWidth = `${newWidth}px`;\r\n        };\r\n\r\n        const onMouseUp = () => {\r\n          handle.classList.remove("is-resizing");\r\n          handle.classList.remove("ux4g-is-resizing");\r\n          U.off(document, "mousemove", onMouseMove);\r\n          U.off(document, "mouseup", onMouseUp);\r\n          U.dispatch(this.el, "ux4g.table.resize", { column: th, width: th.offsetWidth });\r\n        };\r\n\r\n        U.on(handle, "mousedown", (e) => {\r\n          e.preventDefault();\r\n          e.stopPropagation();\r\n          startX = e.clientX;\r\n          startWidth = th.offsetWidth || th.getBoundingClientRect().width;\r\n          handle.classList.add("ux4g-is-resizing");\r\n          U.on(document, "mousemove", onMouseMove);\r\n          U.on(document, "mouseup", onMouseUp);\r\n        });\r\n      });\r\n    }\r\n\r\n    _bindSelection() {\r\n      // Find a select-all checkbox in the head\r\n      const selectAll = U.qs("thead .ux4g-checkbox", this.el);\r\n      if (!selectAll) return;\r\n\r\n      const rowCheckboxes = U.qsa("tbody .ux4g-checkbox", this.el);\r\n      if (!rowCheckboxes.length) return;\r\n      \r\n      const updateState = () => {\r\n        let checkedCount = 0;\r\n        rowCheckboxes.forEach(cb => {\r\n          const tr = U.closest(cb, "tr");\r\n          if (cb.checked) {\r\n            checkedCount++;\r\n            if (tr) tr.classList.add("ux4g-is-selected");\r\n          } else {\r\n            if (tr) tr.classList.remove("ux4g-is-selected");\r\n          }\r\n        });\r\n\r\n        if (checkedCount === 0) {\r\n          selectAll.checked = false;\r\n          selectAll.indeterminate = false;\r\n        } else if (checkedCount === rowCheckboxes.length) {\r\n          selectAll.checked = true;\r\n          selectAll.indeterminate = false;\r\n        } else {\r\n          selectAll.checked = false;\r\n          selectAll.indeterminate = true;\r\n        }\r\n      };\r\n\r\n      // Listen to select-all\r\n      U.on(selectAll, "change", (e) => {\r\n        const isChecked = e.target.checked;\r\n        rowCheckboxes.forEach(cb => {\r\n          cb.checked = isChecked;\r\n        });\r\n        updateState();\r\n      });\r\n\r\n      // Listen to individual row checkboxes\r\n      rowCheckboxes.forEach(cb => {\r\n        U.on(cb, "change", updateState);\r\n        \r\n        // Also allow row click to toggle checkbox, skipping if clicking on interactable elements\r\n        const tr = U.closest(cb, "tr");\r\n        if (tr && tr.classList.contains("ux4g-table-interactive")) {\r\n          U.on(tr, "click", (e) => {\r\n            if (e.target.tagName !== "INPUT" && e.target.tagName !== "BUTTON" && !U.closest(e.target, "button") && !U.closest(e.target, "a")) {\r\n               cb.checked = !cb.checked;\r\n               updateState();\r\n            }\r\n          });\r\n        }\r\n      });\r\n\r\n      // Initialize state on load\r\n      updateState();\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "table");\r\n      if (!inst) { inst = new Table(el); setI(el, "table", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // List\r\n  // -----------------------------\r\n  class List {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this._bind();\r\n    }\r\n\r\n    _bind() {\r\n      U.on(this.el, "click", (e) => {\r\n        const item = U.closest(e.target, ".ux4g-list-item-row") || U.closest(e.target, ".ux4g-list-select-item");\r\n        if (!item || item.disabled) return;\r\n\r\n        const checkbox = U.qs(\'input[type="checkbox"]\', item);\r\n        const radio = U.qs(\'input[type="radio"]\', item);\r\n        const switchInput = U.qs(\'.ux4g-switch-input\', item);\r\n\r\n        if (radio && e.target !== radio && !U.closest(e.target, ".ux4g-radio-control")) {\r\n          return;\r\n        }
1\r\n\r\n        const isMulti = (this.el.id === "ux4g-multiselect-list") || \r\n                        this.el.classList.contains("ux4g-multiselect") || \r\n                        this.el.classList.contains("ux4g-list-multiselect") ||\r\n                        (switchInput !== null);\r\n\r\n        // If clicking on a label (but NOT the input itself), let the native browser behavior trigger the input click\r\n        if (e.target.tagName !== \'INPUT\' && (e.target.tagName === \'LABEL\' || U.closest(e.target, \'label\'))) {\r\n          return;\r\n        }\r\n\r\n        // If clicking on input directly, don\'t double toggle\r\n        if (e.target.tagName === \'INPUT\') {\r\n          const inputChecked = e.target.checked;\r\n          \r\n          if (!isMulti) {\r\n            const allItems = U.qsa(".ux4g-list-item-row, .ux4g-list-select-item", this.el);\r\n            allItems.forEach(i => {\r\n              if (i !== item) i.classList.remove("active");\r\n              // Also ensure other inputs are unchecked\r\n              if (i !== item) {\r\n                const otherInp = U.qs(\'input\', i);\r\n                if (otherInp) otherInp.checked = false;\r\n              }\r\n            });\r\n            item.classList.toggle("active", inputChecked);\r\n          } else {\r\n            item.classList.toggle("active", inputChecked);\r\n          }\r\n          return;\r\n        }\r\n\r\n        if (isMulti) {\r\n          const isActive = item.classList.toggle("active");\r\n          if (checkbox) {\r\n            checkbox.checked = isActive;\r\n            checkbox.dispatchEvent(new Event("change", { bubbles: true }));\r\n          }\r\n          if (switchInput) {\r\n            switchInput.checked = isActive;\r\n            switchInput.dispatchEvent(new Event("change", { bubbles: true }));\r\n          }\r\n        } else {\r\n          // Single selection\r\n          const wasActive = item.classList.contains("active");\r\n          const allItems = U.qsa(".ux4g-list-item-row, .ux4g-list-select-item", this.el);\r\n          \r\n          // Clear all first\r\n          allItems.forEach(i => {\r\n            i.classList.remove("active");\r\n            const cb = U.qs(\'input[type="checkbox"]\', i);\r\n            const rb = U.qs(\'input[type="radio"]\', i);\r\n            const sw = U.qs(\'.ux4g-switch-input\', i);\r\n            if (cb) cb.checked = false;\r\n            if (rb) rb.checked = false;\r\n            if (sw) sw.checked = false;\r\n          });\r\n\r\n          // Toggle: only add if it wasn\'t already active\r\n          if (!wasActive) {\r\n            item.classList.add("active");\r\n            if (checkbox) {\r\n              checkbox.checked = true;\r\n              checkbox.dispatchEvent(new Event("change", { bubbles: true }));\r\n            }\r\n            if (radio) {\r\n              radio.checked = true;\r\n              radio.dispatchEvent(new Event("change", { bubbles: true }));\r\n            }\r\n            if (switchInput) {\r\n              switchInput.checked = true;\r\n              switchInput.dispatchEvent(new Event("change", { bubbles: true }));\r\n            }\r\n          }\r\n        }\r\n        \r\n        U.dispatch(this.el, "ux4g.list.change", { item, active: item.classList.contains("active") });\r\n      });\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, "list");\r\n      if (!inst) { inst = new List(el); setI(el, "list", inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // Upload\r\n  // -----------------------------\r\n  class Upload {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this.input = el.querySelector(\'[data-ux-upload-input], .ux4g-upload-input\');\r\n      this.dropzone = el.querySelector(\'.ux4g-upload-panel\');\r\n      this.fileList = el.querySelector(\'.ux4g-upload-file-list\');\r\n      this.errorMsg = el.querySelector(\'.ux4g-upload-error-msg\');\r\n      this.errorText = el.querySelector(\'.ux4g-upload-error-text\');\r\n      this.moreButton = el.querySelector(\'.ux4g-upload-more\');\r\n      this.heading = el.querySelector(\'.ux4g-upload-heading\');\r\n      this.defaultHeading = this.heading ? this.heading.textContent.trim() : \'\';\r\n      this.files = [];\r\n      this.retryItem = null;\r\n      this.dragDepth = 0;\r\n      this.stateClasses = [\r\n        \'ux4g-upload-state-default\',\r\n        \'ux4g-upload-state-default-vle\',\r\n        \'ux4g-upload-state-selecting\',\r\n        \'ux4g-upload-state-scanning\',\r\n        \'ux4g-upload-state-uploaded\',\r\n        \'ux4g-upload-state-uploaded-vle\',\r\n        \'ux4g-upload-state-error\'\r\n      ];\r\n      this.maxSizeMB = U.num(U.data(el, \'max-size\', 5), 5);\r\n      this.accept = (U.attr(this.input, \'accept\', \'\') || \'\')\r\n        .split(\',\')\r\n        .map(s => s.trim().toLowerCase())\r\n        .filter(Boolean);\r\n      this._bind();\r\n      this._syncInitialState();\r\n    }\r\n\r\n    _bind() {\r\n      U.on(this.el, \'click\', e => {\r\n        if (U.closest(e.target, \'[data-ux-upload-trigger]\')) {\r\n          this._openPicker(null);\r\n          return;\r\n        }\r\n        if (U.closest(e.target, \'.ux4g-upload-file-remove\')) {\r\n          const item = U.closest(e.target, \'.ux4g-upload-file-item\');\r\n          this._removeFile(item);\r\n          return;\r\n        }
1\r\n        if (U.closest(e.target, \'.ux4g-upload-file-retry\')) {\r\n          const item = U.closest(e.target, \'.ux4g-upload-file-item-error\');\r\n          this._openPicker(item);\r\n          return;\r\n        }\r\n        if (U.closest(e.target, \'.ux4g-upload-more\')) {\r\n          this._openPicker(null);\r\n        }\r\n      });\r\n\r\n      U.on(this.dropzone, \'keydown\', e => {\r\n        if (e.key === \' \' || e.key === \'Enter\') {\r\n          e.preventDefault();\r\n          this._openPicker();\r\n        }\r\n      });\r\n\r\n      U.on(this.input, \'click\', () => {\r\n        this.input.setAttribute(\'data-clicked\', \'true\');\r\n      });\r\n\r\n      U.on(this.input, \'change\', e => {\r\n        const retryItem = this.retryItem;\r\n        this.retryItem = null;\r\n        this._addFiles(Array.from(e.target.files || []), retryItem);\r\n      });\r\n\r\n      U.on(this.dropzone, \'dragenter\', e => {\r\n        e.preventDefault();\r\n        this.dragDepth += 1;\r\n        this._setState(\'selecting\');\r\n      });\r\n\r\n      U.on(this.dropzone, \'dragover\', e => {\r\n        e.preventDefault();\r\n        this._setState(\'selecting\');\r\n      });\r\n\r\n      U.on(this.dropzone, \'dragleave\', e => {\r\n        e.preventDefault();\r\n        this.dragDepth = Math.max(0, this.dragDepth - 1);\r\n        const nextTarget = e.relatedTarget;\r\n        if (this.dragDepth === 0 || !nextTarget || !this.dropzone.contains(nextTarget)) {\r\n          this._clearActive();\r\n        }\r\n      });\r\n\r\n      U.on(this.dropzone, \'drop\', e => {\r\n        e.preventDefault();\r\n        this.dragDepth = 0;\r\n        this._clearActive();\r\n        this._addFiles(Array.from((e.dataTransfer && e.dataTransfer.files) || []));\r\n      });\r\n    }\r\n\r\n    _openPicker(retryItem = null) {\r\n      if (!this.input) return;\r\n      this.retryItem = retryItem;\r\n      this.input.setAttribute(\'data-clicked\', \'true\');\r\n      this.input.click();\r\n    }\r\n\r\n    _setState(state) {\r\n      this.el.classList.remove(\'ux4g-upload-state-selecting\', \'ux4g-upload-state-error\');\r\n      if (state === \'selecting\') this.el.classList.add(\'ux4g-upload-state-selecting\');\r\n      if (state === \'error\') this.el.classList.add(\'ux4g-upload-state-error\');\r\n      this._syncDragHeading(state === \'selecting\');\r\n    }\r\n\r\n    _clearActive() {\r\n      this.el.classList.remove(\'ux4g-upload-state-selecting\');\r\n      this._syncDragHeading(false);\r\n    }\r\n\r\n    _syncDragHeading(isDragging) {\r\n      if (!this.heading) return;\r\n      this.heading.textContent = isDragging ? \'Drop file here\' : this.defaultHeading;\r\n    }\r\n\r\n    _showError(msg, file) {\r\n      this.el.classList.remove(\'ux4g-upload-state-selecting\');\r\n      this.el.classList.add(\'ux4g-upload-state-error\');\r\n      this._clearErrorRows();\r\n      this._renderErrorFile(file, msg);\r\n      if (this.errorMsg) this.errorMsg.classList.add(\'ux4g-d-none\');\r\n    }\r\n\r\n    _clearError(clearRows = true) {\r\n      this.el.classList.remove(\'ux4g-upload-state-error\');\r\n      if (this.errorMsg) this.errorMsg.classList.add(\'ux4g-d-none\');\r\n      if (this.errorText) this.errorText.textContent = \'\';\r\n      if (clearRows) this._clearErrorRows();\r\n    }\r\n\r\n    _clearErrorRows() {\r\n      if (!this.fileList) return;\r\n      this.fileList.querySelectorAll(\'.ux4g-upload-file-item-error[data-ux-upload-error-row="true"]\').forEach(item => item.remove());\r\n    }\r\n\r\n    _validate(file) {\r\n      const parts = file.name.split(\'.\');\r\n      const ext = parts.length > 1 ? `.${parts.pop().toLowerCase()}` : \'\';\r\n      if (this.accept.length && !this.accept.includes(ext)) {\r\n        return `File type not allowed: ${ext || \'unknown\'}`;\r\n      }\r\n      if (file.size > this.maxSizeMB * 1024 * 1024) {\r\n        return `File too large. Max size: ${this.maxSizeMB} MB`;\r\n      }\r\n      return null;\r\n    }\r\n\r\n    _addFiles(incoming, retryItem = null) {\r\n      let errorOccurred = false;\r\n      let retryHandled = false;\r\n\r\n      incoming.forEach(file => {\r\n        const retryTarget = !retryHandled && retryItem && retryItem.isConnected ? retryItem : null;
1\r\n        const err = this._validate(file);\r\n        if (err) {\r\n          errorOccurred = true;\r\n          if (retryTarget) {\r\n            this.el.classList.add(\'ux4g-upload-state-error\');\r\n            this._renderErrorFile(file, err, retryTarget);\r\n            retryHandled = true;\r\n          } else {\r\n            this._showError(err, file);\r\n          }\r\n          U.dispatch(this.el, \'ux4g.upload.error\', { file, reason: err });\r\n          return;\r\n        }\r\n\r\n        this.files.push(file);\r\n        this._renderFile(file, retryTarget);\r\n        if (retryTarget) retryHandled = true;\r\n        U.dispatch(this.el, \'ux4g.upload.added\', { file });\r\n      });\r\n\r\n      if (!errorOccurred) {\r\n        const hasErrorRows = this.fileList && this.fileList.querySelector(\'.ux4g-upload-file-item-error\');\r\n        this._clearError(!retryHandled);\r\n        if (hasErrorRows) this.el.classList.add(\'ux4g-upload-state-error\');\r\n      }\r\n      this._syncHasFiles();\r\n      this.input.value = \'\';\r\n    }\r\n\r\n    _renderFile(file, replaceItem = null) {\r\n      if (!this.fileList) return;\r\n\r\n      const sizeKB = file.size / 1024;\r\n      const sizeLabel = sizeKB >= 1024\r\n        ? `${(sizeKB / 1024).toFixed(1)} MB`\r\n        : `${Math.max(1, Math.round(sizeKB))} KB`;\r\n\r\n      const li = document.createElement(\'li\');\r\n      li.className = \'ux4g-upload-file-item\';\r\n      li.setAttribute(\'role\', \'listitem\');\r\n      li.dataset.fileName = file.name;\r\n      li.innerHTML = `\r\n        <div class="ux4g-upload-file-row">\r\n          <span class="ux4g-upload-file-leading" aria-hidden="true">\r\n            <span class="ux4g-icon-outlined ux4g-upload-file-icon">token</span>\r\n          </span>\r\n          <span class="ux4g-upload-file-copy">\r\n            <span class="ux4g-body-m-strong ux4g-upload-file-name">${this._escape(file.name)}</span>\r\n            <span class="ux4g-body-s-default ux4g-upload-file-description">${sizeLabel}</span>\r\n          </span>\r\n          <span class="ux4g-upload-file-statusbox" aria-hidden="true">\r\n            <span class="ux4g-icon-outlined ux4g-upload-file-status">done</span>\r\n          </span>\r\n          <button type="button" class="ux4g-upload-file-remove" aria-label="Remove ${this._escape(file.name)}">\r\n            <span class="ux4g-icon-outlined" aria-hidden="true">close</span>\r\n          </button>\r\n        </div>\r\n      `;\r\n      if (replaceItem && replaceItem.isConnected) {\r\n        replaceItem.replaceWith(li);\r\n      } else {\r\n        this.fileList.appendChild(li);\r\n      }\r\n    }\r\n\r\n    _renderErrorFile(file, reason, replaceItem = null) {\r\n      if (!this.fileList) return;\r\n\r\n      const label = file && file.name ? file.name : \'Document_name.pdf\';\r\n      const li = document.createElement(\'li\');\r\n      li.className = \'ux4g-upload-file-item ux4g-upload-file-item-error\';\r\n      li.setAttribute(\'role\', \'listitem\');\r\n      li.dataset.uploadErrorRow = \'true\';\r\n      li.dataset.errorReason = reason || \'\';\r\n      li.innerHTML = `\r\n        <div class="ux4g-upload-file-row">\r\n          <span class="ux4g-upload-file-leading" aria-hidden="true">\r\n            <span class="ux4g-icon-outlined ux4g-upload-file-icon">error_outline</span>\r\n          </span>\r\n          <span class="ux4g-upload-file-copy">\r\n            <span class="ux4g-body-m-strong ux4g-upload-file-name">${this._escape(label)}</span>\r\n            <span class="ux4g-body-s-default ux4g-upload-file-description">${this._escape(reason || \'Description\')}</span>\r\n          </span>\r\n          <button type="button" class="ux4g-upload-file-retry" aria-label="Retry upload">\r\n            <span class="ux4g-icon-outlined" aria-hidden="true">replay</span>\r\n            <span class="ux4g-label-l-default">Retry</span>\r\n          </button>\r\n        </div>\r\n      `;\r\n      if (replaceItem && replaceItem.isConnected) {\r\n        replaceItem.replaceWith(li);\r\n      }
1 else {\r\n        this.fileList.appendChild(li);\r\n      }\r\n    }\r\n\r\n    _removeFile(item) {\r\n      const name = item && item.dataset.fileName;\r\n      this.files = this.files.filter(f => f.name !== name);\r\n      if (item) item.remove();\r\n      this._syncHasFiles();\r\n      U.dispatch(this.el, \'ux4g.upload.removed\', { name });\r\n    }\r\n\r\n    _syncHasFiles() {\r\n      const hasSuccessfulRows = this.fileList && this.fileList.querySelector(\'.ux4g-upload-file-item:not(.ux4g-upload-file-item-error)\');\r\n      const hasErrorRows = this.fileList && this.fileList.querySelector(\'.ux4g-upload-file-item-error\');\r\n      const hasFiles = this.files.length > 0 || !!hasSuccessfulRows || !!hasErrorRows;\r\n      if (this.fileList) this.fileList.classList.toggle(\'ux4g-d-none\', !hasFiles);\r\n      if (this.moreButton) this.moreButton.classList.toggle(\'ux4g-d-none\', !(this.files.length > 0 || !!hasSuccessfulRows));\r\n      this._deriveBaseState(hasFiles);\r\n    }\r\n\r\n    _syncInitialState() {\r\n      if (this.fileList) {\r\n        this.files = Array.from(this.fileList.querySelectorAll(\'.ux4g-upload-file-item:not(.ux4g-upload-file-item-error)\'))\r\n          .map(item => ({ name: item.dataset.fileName || item.textContent.trim(), size: 0 }));\r\n      }\r\n      if (this.el.classList.contains(\'ux4g-upload-state-error\')) {\r\n        if (this.errorMsg) this.errorMsg.classList.remove(\'ux4g-d-none\');\r\n      } else {\r\n        this._clearError();\r\n      }\r\n      this._syncHasFiles();\r\n    }\r\n\r\n    _deriveBaseState(hasFiles) {\r\n      const variant = U.data(this.el, \'variant\', \'default\');\r\n      this.stateClasses.forEach(cls => {\r\n        if (cls !== \'ux4g-upload-state-selecting\' && cls !== \'ux4g-upload-state-error\') {\r\n          this.el.classList.remove(cls);\r\n        }\r\n      });\r\n\r\n      if (this.el.classList.contains(\'ux4g-upload-state-error\')) return;\r\n      if (variant === \'scanning\') {\r\n        this.el.classList.add(\'ux4g-upload-state-scanning\');\r\n        return;\r\n      }\r\n      if (variant === \'default-vle\') {\r\n        this.el.classList.add(hasFiles ? \'ux4g-upload-state-uploaded-vle\' : \'ux4g-upload-state-default-vle\');\r\n        return;\r\n      }\r\n      this.el.classList.add(hasFiles ? \'ux4g-upload-state-uploaded\' : \'ux4g-upload-state-default\');\r\n    }\r\n\r\n    _escape(str) {\r\n      return String(str).replace(/[&<>"\']/g, c => ({ \'&\': \'&amp;\', \'<\': \'&lt;\', \'>\': \'&gt;\', \'"\': \'&quot;\', "\'": \'&#39;\' }[c]));\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, \'upload\');\r\n      if (!inst) { inst = new Upload(el); setI(el, \'upload\', inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // OTP\r\n  // -----------------------------\r\n  class OtpInput {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this.group = U.qs(\'.ux4g-otp-group\', el);\r\n      this.sourceInput = U.qs(\'.ux4g-otp-source\', el);\r\n      this.resend = U.qs(\'[data-ux-otp-resend]\', el);\r\n      this.status = U.qs(\'[data-ux-otp-status]\', el);\r\n      this.helper = U.qs(\'[data-ux-otp-helper]\', el);\r\n      this.timerTargets = U.qsa(\'[data-ux-otp-timer]\', el);\r\n      this.state = U.data(el, \'state\', \'default\');\r\n      this.count = Math.max(1, U.num(U.data(el, \'count\', 0), 0) || 1);\r\n      this.placeholder = this.sourceInput?.getAttribute(\'placeholder\') || \'-\';\r\n      this.demoErrorOnComplete = U.bool(U.data(el, \'demo-error-on-complete\', \'false\'), false);\r\n      this.noSeparator = U.bool(U.data(el, \'no-separator\', \'false\'), false);\r\n      this._timerId = null;\r\n      this._shakeTimer = null;\r\n      this._completedByUser = false;\r\n      this._observer = null;\r\n      this._demoErrorTimer = null;\r\n\r\n      this._renderInputs();\r\n      this.inputs = U.qsa(\'.ux4g-otp-input\', el);\r\n      this.length = this.count;\r\n      this._syncInputs();\r\n      this._observeErrorState();\r\n      this._bind();\r\n      this._applyVisualFocus();\r\n      this._startTimers();\r\n    }\r\n\r\n    _renderInputs() {\r\n      if (!this.group) return;\r\n\r\n      const digits = this._getDigits();\r\n      this.group.replaceChildren();
1\r\n      if (this.sourceInput) this.group.append(this.sourceInput);\r\n\r\n      for (let index = 0; index < this.count; index += 1) {\r\n        const slot = document.createElement(\'div\');\r\n        slot.className = \'ux4g-input ux4g-otp-slot\';\r\n\r\n        const input = document.createElement(\'input\');\r\n        input.className = \'ux4g-input-input ux4g-otp-input ux4g-body-m-default\';\r\n        input.type = \'text\';\r\n        input.setAttribute(\'aria-label\', `Digit ${index + 1}`);\r\n\r\n        if (digits[index]) {\r\n          input.value = digits[index];\r\n        } else {\r\n          input.placeholder = this.placeholder;\r\n        }\r\n\r\n        this._syncInputTone(input);\r\n        slot.append(input);\r\n        this.group.append(slot);\r\n\r\n        if (index < this.count - 1 && !this.noSeparator) {\r\n          const separator = document.createElement(\'span\');\r\n          separator.className = \'ux4g-otp-separator ux4g-icon-outlined\';\r\n          separator.setAttribute(\'aria-hidden\', \'true\');\r\n          separator.textContent = \'horizontal_rule\';\r\n          this.group.append(separator);\r\n        }\r\n      }\r\n    }\r\n\r\n    _getDigits() {\r\n      return ((this.sourceInput?.value || \'\').replace(/\\D/g, \'\').slice(0, this.count)).split(\'\');\r\n    }\r\n\r\n    _bind() {\r\n      this.inputs.forEach((input, index) => {\r\n        U.on(input, \'focus\', () => this._setFocused(index));\r\n        U.on(input, \'click\', () => this._setFocused(index));\r\n        U.on(input, \'input\', e => this._onInput(e, index));\r\n        U.on(input, \'keydown\', e => this._onKeydown(e, index));\r\n      });\r\n    }\r\n\r\n    _isInteractive() {\r\n      return this.state === \'default\' || this.state === \'partial-filled\' || this.state === \'all-filled\';\r\n    }\r\n\r\n    _syncInputs() {\r\n      this.inputs.forEach((input, index) => {\r\n        input.setAttribute(\'inputmode\', \'numeric\');\r\n        input.setAttribute(\'pattern\', \'[0-9]*\');\r\n        input.setAttribute(\'autocomplete\', index === 0 ? \'one-time-code\' : \'off\');\r\n        input.setAttribute(\'maxlength\', \'1\');\r\n        input.placeholder = input.value ? \'\' : this.placeholder;\r\n        this._syncInputTone(input);\r\n\r\n        if (!this._isInteractive()) {\r\n          input.setAttribute(\'readonly\', \'readonly\');\r\n          input.setAttribute(\'tabindex\', \'-1\');\r\n        }\r\n\r\n        if (this.state === \'locked-out\') {\r\n          input.setAttribute(\'disabled\', \'disabled\');\r\n        }\r\n      });\r\n    }\r\n\r\n    _syncInputTone(input) {\r\n      input.classList.toggle(\'ux4g-title-m-strong\', !!input.value);\r\n      input.classList.toggle(\'ux4g-body-m-default\', !input.value);\r\n    }\r\n\r\n    _setFocused(index) {\r\n      this.inputs.forEach((input, inputIndex) => {\r\n        input.closest(\'.ux4g-otp-slot\')?.classList.toggle(\'ux4g-otp-focus\', inputIndex === index);\r\n        input.classList.toggle(\'ux4g-otp-caret\', inputIndex === index && !input.value);\r\n        input.placeholder = input.value ? \'\' : (inputIndex === index ? \'\' : this.placeholder);\r\n      });\r\n    }\r\n\r\n    _syncFocusClass() {\r\n      const active = this.inputs.findIndex(input => input === document.activeElement);\r\n      if (active >= 0) this._setFocused(active);\r\n    }\r\n\r\n    _clearFocused() {\r\n      this.inputs.forEach(input => {\r\n        input.closest(\'.ux4g-otp-slot\')?.classList.remove(\'ux4g-otp-focus\');\r\n        input.classList.remove(\'ux4g-otp-caret\');\r\n        input.placeholder = input.value ? \'\' : this.placeholder;\r\n      });\r\n    }\r\n\r\n    _applyVisualFocus() {\r\n      if (this.state === \'default\') {\r\n        this._setFocused(0);\r\n        return;\r\n      }\r\n\r\n      if (this.state === \'partial-filled\') {\r\n        const emptyIndex = this.inputs.findIndex(input => !input.value);\r\n        this._setFocused(emptyIndex >= 0 ? emptyIndex : this.inputs.length - 1);\r\n        return;\r\n      }\r\n\r\n      if (this.state === \'all-filled\') {\r\n        this._setFocused(this.inputs.length - 1);\r\n        return;\r\n      }\r\n\r\n      this._syncFocusClass();\r\n    }\r\n\r\n    _onInput(e, index) {\r\n      const input = e.target;\r\n      const value = (input.value || \'\').replace(/\\D/g, \'\').slice(-1);\r\n      input.value = value;\r\n      input.placeholder = value ? \'\' : this.placeholder;\r\n      this._syncInputTone(input);\r\n      this._clearDemoErrorState();\r\n\r\n      this._syncSourceValue();\r\n\r\n      if (!value) return;\r\n\r\n      if (index < this.inputs.length - 1) {\r\n        this.inputs[index + 1].focus();\r\n      }\r\n\r\n      this._updateStateFromValue();\r\n    }\r\n\r\n    _onKeydown(e, index) {\r\n      const input = e.target;\r\n\r\n      if (e.key === \'Backspace\') {\r\n        if (input.value) {\r\n          input.value = \'\';\r\n          input.placeholder = this.placeholder;\r\n          this._syncInputTone(input);\r\n          this._clearDemoErrorState();\r\n          this._syncSourceValue();\r\n          this._completedByUser = false;\r\n          this._updateStateFromValue();\r\n          return;\r\n        }\r\n\r\n        if (index > 0) {\r\n          const prev = this.inputs[index - 1];\r\n          prev.value = \'\';\r\n          prev.placeholder = this.placeholder;\r\n          this._syncInputTone(prev);\r\n          prev.focus();\r\n          this._clearDemoErrorState();\r\n          this._syncSourceValue();\r\n          this._completedByUser = false;\r\n          this._updateStateFromValue();\r\n        }\r\n        return;\r\n      }\r\n\r\n      if (e.key === \'ArrowLeft\' && index > 0) {\r\n        e.preventDefault();\r\n        this.inputs[index - 1].focus();\r\n        return;\r\n      }\r\n\r\n      if (e.key === \'ArrowRight\' && index < this.inputs.length - 1) {\r\n        e.preventDefault();\r\n        this.inputs[index + 1].focus();\r\n      }\r\n    }
1\r\n\r\n    _syncSourceValue() {\r\n      if (!this.sourceInput) return;\r\n      this.sourceInput.value = this.inputs.map(input => input.value).join(\'\');\r\n    }\r\n\r\n    _updateStateFromValue() {\r\n      if (!this._isInteractive()) return;\r\n      const filled = this.inputs.filter(input => input.value).length;\r\n      this._completedByUser = filled === this.length;\r\n      const next = filled === 0 ? \'default\' : (filled === this.length ? \'all-filled\' : \'partial-filled\');\r\n      this.el.setAttribute(\'data-ux-state\', next);\r\n      if (this.demoErrorOnComplete && this._completedByUser) {\r\n        this._scheduleDemoErrorState();\r\n      }\r\n    }\r\n\r\n    _isErrorState() {\r\n      return this.el.classList.contains(\'ux4g-otp-error\') || U.data(this.el, \'state\', \'\') === \'error\';\r\n    }\r\n\r\n    _triggerShakeIfError() {\r\n      if (!this.group) return;\r\n      if (!this._completedByUser || this.inputs.some(input => !input.value) || !this._isErrorState()) return;\r\n\r\n      this.group.classList.remove(\'ux4g-otp-shake\');\r\n      void this.group.offsetWidth;\r\n      this.group.classList.add(\'ux4g-otp-shake\');\r\n\r\n      if (this._shakeTimer) global.clearTimeout(this._shakeTimer);\r\n      this._shakeTimer = global.setTimeout(() => {\r\n        this.group?.classList.remove(\'ux4g-otp-shake\');\r\n        this._shakeTimer = null;\r\n      }, 400);\r\n    }\r\n\r\n    _observeErrorState() {\r\n      this._observer = new MutationObserver(() => this._triggerShakeIfError());\r\n      this._observer.observe(this.el, {\r\n        attributes: true,\r\n        attributeFilter: [\'class\', \'data-ux-state\']\r\n      });\r\n    }\r\n\r\n    _scheduleDemoErrorState() {\r\n      if (this._demoErrorTimer) global.clearTimeout(this._demoErrorTimer);\r\n      this._demoErrorTimer = global.setTimeout(() => {\r\n        if (!this._completedByUser || this.inputs.some(input => !input.value)) return;\r\n        this._clearFocused();\r\n        if (document.activeElement && this.inputs.includes(document.activeElement)) {\r\n          document.activeElement.blur();\r\n        }\r\n        this.el.classList.add(\'ux4g-otp-error\');\r\n        this.el.setAttribute(\'data-ux-state\', \'error\');\r\n        this.el.setAttribute(\'aria-invalid\', \'true\');\r\n        if (this.helper) {\r\n          this.helper.outerHTML = \'<span class="ux4g-otp-status" data-ux-otp-status><span class="ux4g-icon-outlined" aria-hidden="true">error</span><span>Attempt 2 of 3</span></span>\';\r\n          this.helper = null;\r\n          this.status = U.qs(\'[data-ux-otp-status]\', this.el);\r\n        }\r\n      }, 300);\r\n    }\r\n\r\n    _clearDemoErrorState() {\r\n      if (!this.demoErrorOnComplete) return;\r\n      if (this._demoErrorTimer) {\r\n        global.clearTimeout(this._demoErrorTimer);\r\n        this._demoErrorTimer = null;\r\n      }\r\n      this.el.classList.remove(\'ux4g-otp-error\');\r\n      this.el.setAttribute(\'data-ux-state\', this.inputs.some(input => input.value) ? \'partial-filled\' : \'default\');\r\n      this.el.removeAttribute(\'aria-invalid\');\r\n      if (!this.helper && this.status) {\r\n        this.status.outerHTML = \'<span class="ux4g-otp-helper" data-ux-otp-helper>Didn’t receive OTP?</span>\';\r\n        this.helper = U.qs(\'[data-ux-otp-helper]\', this.el);\r\n        this.status = null;\r\n      }\r\n    }\r\n\r\n    _formatTime(totalSeconds) {\r\n      const safe = Math.max(0, totalSeconds);\r\n      const minutes = Math.floor(safe / 60);\r\n      const seconds = safe % 60;\r\n      return `${String(minutes).padStart(2, \'0\')}:${String(seconds).padStart(2, \'0\')}`;\r\n    }\r\n\r\n    _tickTimer(node) {\r\n      const total = U.num(node.getAttribute(\'data-ux-otp-seconds\'), 0);\r\n      const prefix = node.getAttribute(\'data-ux-otp-prefix\') || \'\';\r\n      node.textContent = `${prefix}${this._formatTime(total)}`;\r\n      if (total > 0) {\r\n        node.setAttribute(\'data-ux-otp-seconds\', String(total - 1));\r\n      }\r\n    }\r\n\r\n    _startTimers() {\r\n      if (!this.timerTargets.length) return;
1\r\n      this.timerTargets.forEach(node => this._tickTimer(node));\r\n      this._timerId = global.setInterval(() => {\r\n        this.timerTargets.forEach(node => this._tickTimer(node));\r\n      }, 1000);\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, \'otp\');\r\n      if (!inst) { inst = new OtpInput(el); setI(el, \'otp\', inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  // -----------------------------\r\n  // SLA Progress\r\n  // -----------------------------\r\n  class SlaProgress {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this.valueTargets = U.qsa(\'.ux4g-sla-linear-value\', el);\r\n      this.circleValue = U.qs(\'.ux4g-sla-circle-value\', el);\r\n      this.circleMeta = U.qs(\'.ux4g-sla-circle-meta\', el);\r\n      this.sync();\r\n    }\r\n\r\n    sync() {\r\n      const progress = Math.min(100, Math.max(0, U.num(U.data(this.el, \'progress\', 0), 0)));\r\n      this.el.style.setProperty(\'--ux4g-sla-progress\', String(progress));\r\n\r\n      if (this.el.hasAttribute(\'data-ux-sla-linear\')) {\r\n        this.valueTargets.forEach(node => {\r\n          node.textContent = `${Math.round(progress)}%`;\r\n        });\r\n        if (!this.el.getAttribute(\'role\')) {\r\n          this.el.setAttribute(\'role\', \'progressbar\');\r\n        }\r\n        this.el.setAttribute(\'aria-valuemin\', \'0\');\r\n        this.el.setAttribute(\'aria-valuemax\', \'100\');\r\n        this.el.setAttribute(\'aria-valuenow\', String(Math.round(progress)));\r\n      }\r\n\r\n      if (this.el.hasAttribute(\'data-ux-sla-circle\')) {\r\n        const days = U.data(this.el, \'days\', null);\r\n        if (days != null && this.circleValue) {\r\n          this.circleValue.textContent = String(days);\r\n        }\r\n        if (this.circleMeta) {\r\n          this.circleMeta.textContent = Number(days) === 1 ? \'day left\' : \'days left\';\r\n        }\r\n      }\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, \'sla-progress\');\r\n      if (!inst) { inst = new SlaProgress(el); setI(el, \'sla-progress\', inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  class ProgressIndicator {\r\n    constructor(el) {\r\n      this.el = el;\r\n      this.ensureStructure();\r\n      this.labelTargets = U.qsa(\'[data-ux-progress-label]\', el);\r\n      this.descTargets = U.qsa(\'[data-ux-progress-desc]\', el);\r\n      this.endpointStart = U.qs(\'[data-ux-progress-start]\', el);\r\n      this.endpointEnd = U.qs(\'[data-ux-progress-end]\', el);\r\n      this.halfTrackTail = U.qs(\'.ux4g-progress-half-track-tail\', el);\r\n      this.halfRoundedProgress = U.qs(\'[data-ux-progress-half-svg-progress]\', el);\r\n      this.halfRoundedTrack = U.qs(\'[data-ux-progress-half-svg-track]\', el);\r\n      this.halfSharpProgress = U.qs(\'[data-ux-progress-half-svg-progress-sharp]\', el);\r\n      this.halfSharpTrack = U.qs(\'[data-ux-progress-half-svg-track-sharp]\', el);\r\n      this.sync();\r\n    }\r\n\r\n    ensureStructure() {\r\n      if (!this.el.hasAttribute(\'data-ux-progress-half\')) return;\r\n      if (U.qs(\'.ux4g-progress-half-arc\', this.el)) return;\r\n\r\n      const size = (this.el.getAttribute(\'data-ux-size\') || \'m\').toLowerCase();\r\n      const shape = this.el.getAttribute(\'data-ux-shape\') || \'sharp\';\r\n      const config = {\r\n        s: { width: 80, height: 80, radius: 30, stroke: 10, roundedStroke: 8, labelClass: \'ux4g-label-l-strong\', descriptionClass: \'ux4g-body-xs-default\', endpoints: false },\r\n        m: { width: 160, height: 160, radius: 70, stroke: 16, roundedStroke: 16, labelClass: \'ux4g-heading-m-strong\', descriptionClass: \'ux4g-body-xs-default\', endpoints: true },\r\n        l: { width: 200, height: 200, radius: 90, stroke: 20, roundedStroke: 20, labelClass: \'ux4g-heading-m-strong\', descriptionClass: \'ux4g-body-xs-default\', endpoints: true },\r\n        xl: { width: 240, height: 240, radius: 105, stroke: 24, roundedStroke: 24, labelClass: \'ux4g-heading-xl-strong\', descriptionClass: \'ux4g-body-s-default\', endpoints: true }\r\n      }[size] || { width: 160, height: 160, radius: 70, stroke: 16, roun
1dedStroke: 16, labelClass: \'ux4g-heading-m-strong\', descriptionClass: \'ux4g-body-xs-default\', endpoints: true };\r\n\r\n      if (!this.el.hasAttribute(\'data-ux-radius\')) {\r\n        this.el.setAttribute(\'data-ux-radius\', String(config.radius));\r\n      }\r\n\r\n      const description = this.el.getAttribute(\'data-ux-description\') || \'Description\';\r\n      const start = this.el.getAttribute(\'data-ux-start-label\') || \'0%\';\r\n      const end = this.el.getAttribute(\'data-ux-end-label\') || \'100%\';\r\n\r\n      const roundedArcMarkup = `\r\n        <svg class="ux4g-progress-half-svg" viewBox="0 0 ${config.width} ${config.height}" aria-hidden="true" focusable="false">\r\n          <defs>\r\n            <linearGradient id="ux4g-progress-half-gradient-${size}" x1="0" y1="${config.height / 2}" x2="${config.width}" y2="${config.height / 2}" gradientUnits="userSpaceOnUse">\r\n              <stop offset="0%" stop-color="var(--ux4g-progress-fill-start)" />\r\n              <stop offset="100%" stop-color="var(--ux4g-progress-fill-end)" />\r\n            </linearGradient>\r\n          </defs>\r\n          <path class="ux4g-progress-half-svg-track" d="${progressHalfRoundedArcPath(config.width, config.roundedStroke)}" data-ux-progress-half-svg-track></path>\r\n          <path class="ux4g-progress-half-svg-progress" d="${progressHalfRoundedArcPath(config.width, config.roundedStroke)}" pathLength="100" data-ux-progress-half-svg-progress></path>\r\n        </svg>`;\r\n      const sharpArcMarkup = `\r\n        <svg class="ux4g-progress-half-svg ux4g-progress-half-svg-sharp" viewB
1ox="0 0 ${config.width} ${config.height}" aria-hidden="true" focusable="false">\r\n          <defs>\r\n            <linearGradient id="ux4g-progress-half-gradient-sharp-${size}" x1="0" y1="${config.height / 2}" x2="${config.width}" y2="${config.height / 2}" gradientUnits="userSpaceOnUse">\r\n              <stop offset="0%" stop-color="var(--ux4g-progress-fill-start)" />\r\n              <stop offset="100%" stop-color="var(--ux4g-progress-fill-end)" />\r\n            </linearGradient>\r\n          </defs>\r\n          <path class="ux4g-progress-half-svg-track ux4g-progress-half-svg-track-sharp" d="${progressHalfRoundedArcPath(config.width, config.stroke)}" data-ux-progress-half-svg-track-sharp></path>\r\n          <path class="ux4g-progress-half-svg-progress ux4g-progress-half-svg-progress-sharp" d="${progressHalfRoundedArcPath(config.width, config.stroke)}" data-ux-progress-half-svg-progress-sharp></path>\r\n        </svg>`;\r\n      const arcMarkup = shape === \'rounded\' ? roundedArcMarkup : sharpArcMarkup;\r\n\r\n      this.el.innerHTML = `<div class="ux4g-progress-half-arc" aria-hidden="true">${arcMarkup}</div><div class="ux4g-progress-half-copy"><span class="${config.labelClass}" data-ux-progress-label>50%</span><p class="ux4g-progress-half-description ${config.descriptionClass}" data-ux-progress-desc>${description}</p></div>${config.endpoints ? `<div class="ux4g-progress-half-endpoints"><span class="ux4g-body-xs-default" data-ux-progress-start>${start}</span><span class="ux4g-body-xs-default" data-ux-progress-end>${end}</span></div>` : \'\'}`;\r\n    }\r\n\r\n    sync() {\r\n      const progress = Math.min(100, Math.max(0, U.num(U.data(this.el, \'progress\', 0), 0)));\r\n      this.el.style.setProperty(\'--ux4g-progress-value\', String(progress));\r\n\r\n      this.labelTargets.forEach(node => {\r\n        node.textContent = `${Math.round(progress)}%`;\r\n      });\r\n\r\n      if (this.el.hasAttribute(\'data-ux-progress-half\')) {\r\n        const radius = U.num(U.data(this.el, \'radius\', 0), 0);\r\n        this.el.style.setProperty(\'--ux4g-progress-half-angle\', `${progress * 1.8}deg`);\r\n        if (this.halfRoundedProgress) {\r\n          const size = this.halfRoundedProgress.ownerSVGElement.viewBox.baseVal.width;\r\n          const stroke = U.num(getComputedStyle(this.el).getPropertyValue(\'--ux4g-progress-half-stroke\').replace(\'px\', \'\'), 0);\r\n          this.halfRoundedProgress.setAttribute(\'d\', progressHalfRoundedArcPath(size, stroke, 180, 180 + (progress * 1.8)));\r\n          this.halfRoundedProgress.style.strokeDasharray = \'\';\r\n          if (this.halfRoundedTrack) {\r\n            if (progress >= 100) {\r\n              this.halfRoundedTrack.setAttribute(\'d\', \'\');\r\n            } else {\r\n              const trackStartAngle = progress <= 0 ? 180 : 180 + (progress * 1.8);\r\n              this.halfRoundedTrack.setAttribute(\'d\', progressHalfRoundedArcPath(size, stroke, trackStartAngle, 360));\r\n            }\r\n          }\r\n          if (this.halfRoundedTrackCap) {\r\n            this.halfRoundedTrackCap.style.display = progress < 100 ? \'block\' : \'none\';\r\n          }\r\n        }\r\n        if (this.halfSharpProgress) {\r\n          const size = this.halfSharpProgress.ownerSVGElement.viewBox.baseVal.width;\r\n          const stroke = U.num(getComputedStyle(this.el).getPropertyValue(\'--ux4g-progress-half-stroke\').replace(\'px\', \'\'), 0);\r\n          this.halfSharpProgress.setAttribute(\'d\', progressHalfRoundedArcPath(size, stroke, 180, 180 + (progress * 1.8)));\r\n          if (this.halfSharpTrack) {\r\n            if (progress >= 100) {\r\n              this.halfSharpTrack.setAttribute(\'d\', \'\');\r\n            } else {\r\n              const trackStartAngle = progress <= 0 ? 180 : 180 + (progress * 1.8);\r\n              this.halfSharpTrack.setAttribute(\'d\', progressHalfRoundedArcPath(size, stroke, trackStartAngle, 360));\r\n            }\r\n          }\r\n        }\r\n        if (this.halfTrackTail) {\r\n          this.halfTrackTail.hidden = true;\r\n        }\r\n      }\r\n\r\n      const description = this.el.getAttribute(\'data-ux-description\');
1\r\n      if (description) {\r\n        this.descTargets.forEach(node => {\r\n          node.textContent = description;\r\n        });\r\n      }\r\n\r\n      const start = this.el.getAttribute(\'data-ux-start-label\');\r\n      const end = this.el.getAttribute(\'data-ux-end-label\');\r\n      if (this.endpointStart && start != null) this.endpointStart.textContent = start;\r\n      if (this.endpointEnd && end != null) this.endpointEnd.textContent = end;\r\n\r\n      if (!this.el.getAttribute(\'role\')) {\r\n        this.el.setAttribute(\'role\', \'progressbar\');\r\n      }\r\n      this.el.setAttribute(\'aria-valuemin\', \'0\');\r\n      this.el.setAttribute(\'aria-valuemax\', \'100\');\r\n      this.el.setAttribute(\'aria-valuenow\', String(Math.round(progress)));\r\n    }\r\n\r\n    static getOrCreate(el) {\r\n      let inst = getI(el, \'progress-indicator\');\r\n      if (!inst) { inst = new ProgressIndicator(el); setI(el, \'progress-indicator\', inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  function progressCircleLabelClass(size, placement) {\r\n    if (placement === \'outside\') return \'ux4g-label-xl-strong\';\r\n    if (size === \'xs\' || size === \'s\' || size === \'m\') return \'ux4g-label-m-strong\';\r\n    if (size === \'l\') return \'ux4g-label-l-strong\';\r\n    return \'ux4g-label-xl-strong\';\r\n  }\r\n\r\n  function progressCircleDescriptionClass(size, placement) {\r\n    if (placement === \'outside\') return \'ux4g-body-s-default\';\r\n    return (size === \'xl\' || size === \'2xl\' || size === \'3xl\') ? \'ux4g-body-s-default\' : \'ux4g-body-xs-default\';\r\n  }\r\n\r\n  function progressHalfLabelClass(size) {\r\n    return size === \'s\' ? \'ux4g-label-l-strong\' : \'ux4g-heading-m-strong\';\r\n  }\r\n\r\n  function progressHalfRoundedArcPath(size, stroke, startAngle = 180, endAngle = 360) {\r\n    const radius = (size / 2) - (stroke / 2);\r\n    const center = size / 2;\r\n    const start = polarPoint(center, radius, startAngle);\r\n    const end = polarPoint(center, radius, endAngle);\r\n    const largeArcFlag = Math.abs(endAngle - startAngle) > 180 ? 1 : 0;\r\n    return `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`;\r\n  }\r\n\r\n  function polarPoint(center, radius, angleDeg) {\r\n    const angle = (angleDeg * Math.PI) / 180;\r\n    return {\r\n      x: center + (radius * Math.cos(angle)),\r\n      y: center + (radius * Math.sin(angle))\r\n    };\r\n  }\r\n\r\n  function buildProgressBarDemo(shape, placement, progress) {\r\n    const inside = placement === \'inside\';\r\n    return `<article class="ux4g-progress-bar" data-ux-progress-bar data-ux-shape="${shape}" data-ux-label-placement="${placement}" data-ux-progress="${progress}" role="progressbar" aria-label="${shape} ${placement} bar ${progress} percent"><div class="ux4g-progress-bar-track"><div class="ux4g-progress-bar-fill">${inside ? `<span class="ux4g-progress-bar-label ux4g-progress-bar-label-inside ux4g-label-s-strong" data-ux-progress-label>${progress}%</span>` : \'\'}</div></div>${inside ? \'\' : `<span class="ux4g-progress-bar-label ux4g-progress-bar-label-outside ux4g-label-s-strong" data-ux-progress-label>${progress}%</span>`}</article>`;\r\n  }\r\n\r\n  function buildProgressCircleDemo(shape, size, placement) {\r\n    const labelClass = progressCircleLabelClass(size, placement);\r\n    const showInsideDescription = placement === \'inside\' && (size === \'xl\' || size === \'2xl\' || size === \'3xl\');\r\n    const descClass = progressCircleDescriptionClass(size, placement);\r\n    return `<div class="ux4g-progress-size-demo"><article class="ux4g-progress-circle" data-ux-progress-circle data-ux-shape="${shape}" data-ux-size="${size}" data-ux-label-placement="${placement}" data-ux-progress="50" ${(placement === \'outside\' || showInsideDescription) ? \'data-ux-description="Description"\' : \'\'} role="progressbar" aria-label="${size} ${shape} circle ${placement} 50 percent"><div class="ux4g-progress-circle-indicator"><span class="ux4g-progress-circle-ring"></span>${placement === \'inside\' ? `<div class="ux4g-progress-circle-value-wrap"><span class="${labelClass}" data-ux-progress-label>50%</span>${showInsideDescription ? `<p class="ux4g-progress-circle-description ${descClass}" data-ux-progress-desc>Description</p>` : \'\'}</div>` : \'\'}</div>${placement === \'outside\' ? `<div class="ux4g-progress-circle-copy"><span class="${labelClass}" data-ux-progress-label>50%</span>
1<p class="ux4g-progress-circle-description ${descClass}" data-ux-progress-desc>Description</p></div>` : \'\'}</article></div>`;\r\n  }\r\n\r\n  function renderProgressIndicatorDemos(root = document) {\r\n    const steps = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100];\r\n    const barContainers = [\r\n      [\'sharp-outside\', \'sharp\', \'outside\'],\r\n      [\'rounded-outside\', \'rounded\', \'outside\'],\r\n      [\'sharp-inside\', \'sharp\', \'inside\'],\r\n      [\'rounded-inside\', \'rounded\', \'inside\']\r\n    ];\r\n    barContainers.forEach(([key, shape, placement]) => {\r\n      const container = root.querySelector(`[data-ux-progress-demo-bars="${key}"]`);\r\n      if (!container) return;\r\n      container.innerHTML = steps.map(progress => buildProgressBarDemo(shape, placement, progress)).join(\'\');\r\n    });\r\n\r\n    const circleSizes = [\'xs\', \'s\', \'m\', \'l\', \'xl\', \'2xl\', \'3xl\'];\r\n    const circleHeadings = root.querySelector(\'[data-ux-progress-demo-circle-headings]\');\r\n    if (circleHeadings) circleHeadings.innerHTML = \'\';\r\n    const circleRows = [\r\n      [\'sharp-inside\', \'sharp\', \'inside\'],\r\n      [\'sharp-outside\', \'sharp\', \'outside\'],\r\n      [\'rounded-inside\', \'rounded\', \'inside\'],\r\n      [\'rounded-outside\', \'rounded\', \'outside\']\r\n    ];\r\n    circleRows.forEach(([key, shape, placement]) => {\r\n      const row = root.querySelector(`[data-ux-progress-demo-circles="${key}"]`);\r\n      if (!row) return;\r\n      row.innerHTML = circleSizes.map(size => buildProgressCircleDemo(shape, size, placement)).join(\'\');\r\n    });\r\n\r\n  }\r\n\r\n  // -----------------------------\r\n  // Data API init\r\n  // -----------------------------\r\n  function init(root = document) {\r\n    renderProgressIndicatorDemos(root);\r\n\r\n    // Dropdown\r\n    U.qsa(\'[data-bs-toggle="dropdown"],[data-ux-toggle="dropdown"]\', root).forEach(Dropdown.getOrCreate);\r\n\r\n    // Collapse\r\n    U.qsa(\'[data-bs-toggle="collapse"],[data-ux-toggle="collapse"],[ux4g-toggle="collapse"]\', root).forEach(Collapse.getOrCreate);\r\n\r\n    // Tabs\r\n    U.qsa(\'[data-bs-toggle="tab"],[data-ux-toggle="tab"]\', root).forEach(Tab.getOrCreate);\r\n\r\n    // Tooltips / Popovers\r\n    U.qsa(\'[data-bs-toggle="tooltip"],[data-ux-toggle="tooltip"]\', root).forEach(el => Floating.getOrCreate(el, "tooltip"));\r\n    U.qsa(\'[data-bs-toggle="popover"],[data-ux-toggle="popover"]\', root).forEach(el => Floating.getOrCreate(el, "popover"));\r\n\r\n    // Toasts (wires dismiss; does not auto-show unless .show is already present)\r\n    U.qsa(".toast", root).forEach(Toast.getOrCreate);\r\n\r\n    // Carousels\r\n    U.qsa(".carousel", root).forEach(Carousel.getOrCreate);\r\n\r\n    // Scrollspy\r\n    U.qsa(\'[data-bs-spy="scroll"],[data-ux-spy="scroll"]\', root).forEach(ScrollSpy.getOrCreate);\r\n\r\n    // Table Interactions\r\n    U.qsa(".ux4g-table", root).forEach(Table.getOrCreate);\r\n\r\n    // List Interactions\r\n    U.qsa(".ux4g-list", root).forEach(List.getOrCreate);\r\n\r\n    // Upload\r\n    U.qsa(\'[data-ux-upload]\', root).forEach(Upload.getOrCreate);\r\n\r\n    // OTP\r\n    U.qsa(\'[data-ux-otp]\', root).forEach(OtpInput.getOrCreate);\r\n\r\n    // SLA Progress\r\n    U.qsa(\'[data-ux-sla-circle],[data-ux-sla-linear]\', root).forEach(SlaProgress.getOrCreate);\r\n\r\n    // Progress Indicators\r\n    U.qsa(\'[data-ux-progress-bar],[data-ux-progress-circle],[data-ux-progress-half]\', root).forEach(ProgressIndicator.getOrCreate);\r\n\r\n    // Validation: Ensure ux4g-multiselect-list ID is only used on .ux4g-list elements\r\n    const multiselectIdEls = root.querySelectorAll(\'#ux4g-multiselect-list\');\r\n    multiselectIdEls.forEach(el => {\r\n      if (!el.classList.contains(\'ux4g-list\')) {\r\n        console.warn(`[UX4G Validation] The ID \'ux4g-multiselect-list\' should only be used on elements with the \'ux4g-list\' class. Found on:`, el);\r\n      }\r\n    });\r\n  }\r\n\r\n  // Delegated toggles for Offcanvas, Toast & other components\r\n  U.on(document, "click", (e) => {\r\n    const radio = U.closest(e.target, ".ux4g-radio");\r\n    if (radio && !U.closest(e.target, ".ux4g-radio-input, .ux4g-radio-control")) {\r\n      e.preventDefault();\r\n      return;\r\n    }\r\n\r\n    // UX4G offcanvas toggle\r\n    const offBtn = U.closest(e.target, \'[data-bs-toggle="offcanvas"],[data-ux-toggle="offcanvas"]\');\r\n    if (offBtn) {\r\n      e.preventDefault();\r\n      const sel = U.data(offBtn, "target") || U.attr(offBtn, "href");\r\n      const el = sel && sel.startsWith("#") ? U.qs(sel) : null;\r\n      if (el) Offcanvas.getOrCreate(el).toggle(offBtn);\r\n      return;\r\n    }\r\n\r\n    // Toast close class bridge (your HTML)\r\n    const closeToast = U.closest(e.target, ".close-toast");\r\n    if (closeToast) {\r\n      e.preventDefault();\r\n      const toastEl = U.closest(closeToast, ".toast");\r\n      if (toastEl) Toast.getOrCreate(toastEl).hide();\r\n      return;\r\n    }\r\n\r\n  });\r\n\r\n  // Switch keyboard support (Enter to toggle)\r\n  U.on(document, "keydown", (e) => {\r\n    if (e.key === "Enter") {\r\n      const input = U.closest(e.target, ".ux4g-switch-input");\r\n      if (input && !input.disabled) {\r\n        e.preventDefault();\r\n        input.checked = !input.checked;\r\n        input.dispatchEvent(new Event("change", { bubbles: true }));\r\n      }\r\n    }\r\n  });\r\n\r\n  // Your demo: #liveToastBtn shows #liveToast\r\n  U.on(document, "DOMContentLoaded", () => {\r\n    const btn = U.qs("#liveToastBtn");\r\n    if (btn) {\r\n      U.on(btn, "click", () => {\r\n        const toastEl = U.qs("#liveToast");\r\n        if (toastEl) Toast.getOrCreate(toastEl).show();\r\n      });\r\n    }\r\n  });\r\n\r\n  U.on(document, "ux4g.upload.error", (e) => {\r\n    if (typeof global.showContextAlert === "function") {\r\n      global.showContextAlert("top-right", "error", "Upload Failed", e.detail.reason);\r\n    }\r\n  });\r\n\r\n  // Auto-init\r\n  if (document.readyState === "loading") {\r\n    U.on(document, "DOMContentLoaded", () => init(document));\r\n  } else {\r\n    init(document);\r\n  }\r\n\r\n  // ------------------------------------------------------------------\r\n  // SPA Support: Auto-initialization\r\n  // ------------------------------------------------------------------\r\n  global.ux4gCustomInitList = global.ux4gCustomInitList || [];\r\n\r\n  const attachedGlobalListeners = new Set();\r\n  \r\n  // Safe wrapper for global event listeners to prevent double-binding\r\n  const originalDocAddEventListener = document.addEventListener;\r\n  const originalWinAddEventListener = window.addEventListener;\r\n  \r\n  function safeDocAddEventListener(type, listener, options) {\r\n    if (type === \'DOMContentLoaded\') {\r\n      return originalDocAddEventListener.call(document, type, listener, options);\r\n    }
1\r\n    const key = \'doc:\' + type + \':\' + listener.toString().substring(0, 100);\r\n    if (!attachedGlobalListeners.has(key)) {\r\n      attachedGlobalListeners.add(key);\r\n      originalDocAddEventListener.call(document, type, listener, options);\r\n    }\r\n  }\r\n  \r\n  function safeWinAddEventListener(type, listener, options) {\r\n    const key = \'win:\' + type + \':\' + listener.toString().substring(0, 100);\r\n    if (!attachedGlobalListeners.has(key)) {\r\n      attachedGlobalListeners.add(key);\r\n      originalWinAddEventListener.call(window, type, listener, options);\r\n    }\r\n  }\r\n\r\n  // Safe wrapper for querySelectorAll to prevent double-binding on elements\r\n  const originalDocQSA = Document.prototype.querySelectorAll;\r\n  const originalElementQSA = Element.prototype.querySelectorAll;\r\n  \r\n  function rewriteSelector(selector) {\r\n      if (typeof selector === \'string\' && !selector.includes(\'[data-ux4g-init]\')) {\r\n          return selector.split(\',\').map(s => s.trim() + \':not([data-ux4g-init])\').join(\', \');\r\n      }\r\n      return selector;\r\n  }\r\n  \r\n  function tagNodes(nodes) {\r\n      nodes.forEach(n => {\r\n          if (n.setAttribute) n.setAttribute(\'data-ux4g-init\', \'true\');\r\n      });\r\n      return nodes;\r\n  }\r\n\r\n  function safeDocQSA(selector) {\r\n     const newSelector = rewriteSelector(selector);\r\n     const nodes = originalDocQSA.call(this, newSelector);\r\n     return selector !== newSelector ? tagNodes(nodes) : nodes;\r\n  }\r\n\r\n  function safeElementQSA(selector) {\r\n     const newSelector = rewriteSelector(selector);\r\n     const nodes = originalElementQSA.call(this, newSelector);\r\n     return selector !== newSelector ? tagNodes(nodes) : nodes;\r\n  }\r\n\r\n  global.ux4gCustomInit = function() {\r\n    // Mock the environment\r\n    document.addEventListener = safeDocAddEventListener;\r\n    window.addEventListener = safeWinAddEventListener;\r\n    Document.prototype.querySelectorAll = safeDocQSA;\r\n    Element.prototype.querySelectorAll = safeElementQSA;\r\n    document.querySelectorAll = safeDocQSA;\r\n\r\n    // Run all registered initializers\r\n    if (global.ux4gCustomInitList) {\r\n      global.ux4gCustomInitList.forEach(fn => {\r\n        try { fn(); } catch (e) {}\r\n      });\r\n    }\r\n\r\n    // Restore the environment (always runs, even if an init function throws)\r\n    document.addEventListener = originalDocAddEventListener;\r\n    window.addEventListener = originalWinAddEventListener;\r\n    Document.prototype.querySelectorAll = originalDocQSA;\r\n    Element.prototype.querySelectorAll = originalElementQSA;\r\n    document.querySelectorAll = originalDocQSA;\r\n  };\r\n\r\n  if (typeof MutationObserver !== "undefined") {\r\n    const observer = new MutationObserver((mutations) => {\r\n      cancelAnimationFrame(global._ux4gInitRaf);\r\n      global._ux4gInitRaf = requestAnimationFrame(() => {\r\n        for (let i = 0; i < mutations.length; i++) {\r\n          for (let j = 0; j < mutations[i].addedNodes.length; j++) {\r\n            const node = mutations[i].addedNodes[j];\r\n            if (node.nodeType === 1) {\r\n              init(node);\r\n            }\r\n          }\r\n        }\r\n        global.ux4gCustomInit();\r\n      });\r\n    });\r\n    \r\n    const startObserving = () => {\r\n      if (document.body) {\r\n        observer.observe(document.body, { childList: true, subtree: true });\r\n      } else {\r\n        setTimeout(startObserving, 50);\r\n      }\r\n    };\r\n    startObserving();\r\n  }\r\n\r\n  // Expose API\r\n  global.ux4g = {\r\n    version: "1.1.0",\r\n    U,\r\n    getI,\r\n    setI,\r\n    escapeHtml,\r\n    init,\r\n    Dropdown,\r\n    Collapse,\r\n    Offcanvas,\r\n    Toast,\r\n    Carousel,\r\n    Popover: {\r\n      getOrCreate(el) { return Floating.getOrCreate(el, "popover"); }\r\n    },\r\n    Tab,\r\n    ScrollSpy,\r\n    Table,\r\n    List,\r\n    Upload,\r\n    OtpInput,\r\n    Theme: {\r\n      get() {\r\n        return document.documentElement.getAttribute("data-theme") || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");\r\n      },\r\n      set(theme) {\r\n        document.documentElement.setAttribute("data-theme", theme);\r\n        window.dispatchEvent(new CustomEvent("ux4g.theme.changed", { detail: { theme } }));\r\n      },\r\n      toggle() {\r\n        const next = this.get() === "dark" ? "light" : "dark";\r\n        this.set(next);\r\n      }\r\n    }\r\n  };\r\n\r\n  // Auto-init theme if not set\r\n  U.on(document, "DOMContentLoaded", () => {\r\n    if (!document.documentElement.hasAttribute("data-theme")) {\r\n      const preferred = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";\r\n      document.documentElement.setAttribute("data-theme", preferred);\r\n    }\r\n  });\r\n\r\n})(typeof window !== "undefined" ? window : this);\r\n\r\n',document.head.appendChild(e);let t=document.createElement("script");t.setAttribute("data-ux4g-runtime","custom"),t.textContent='/* ========================================================= tooltips js ========================================================= */\r\n(function (ux4g) {\r\n  if (!ux4g) return;\r\n  const U = ux4g.U;\r\n  const getI = ux4g.getI;\r\n  const setI = ux4g.setI;\r\n  const escapeHtml = ux4g.escapeHtml;\r\n\r\n  class Floating {\r\n    constructor(el, kind) {\r\n      this.el = el;\r\n      this.kind = kind; // tooltip | popover\r\n      this._open = false;\r\n      this._floating = null;\r\n\r\n      this.placement = U.data(el, "placement", kind === "tooltip" ? "top" : "right");\r\n      this.offset = U.num(U.data(el, "offset", 8), 8);\r\n      this.trigger = U.data(el, "trigger", kind === "tooltip" ? "hover focus" : "click");\r\n      this.html = U.bool(U.data(el, "html", "false"), false);\r\n\r\n      this._bind();\r\n    }\r\n\r\n    _getContent() {\r\n      const content = U.data(this.el, "content");\r\n      if (content != null) return this.html ? String(content) : escapeHtml(content);\r\n\r\n      if (this.kind === "popover") {\r\n        const title = U.data(this.el, "title") || this.el.getAttribute("title") || "";\r\n        const body = this.el.getAttribute("data-content") || "";\r\n        const t = this.html ? String(title) : escapeHtml(title);\r\n        const b = this.html ? String(body) : escapeHtml(body);\r\n        return `<div class="ux4g-popover-header">${t}</div><div class="ux4g-popover-body">${b}</div>`;\r\n      }\r\n\r\n      const t = this.el.getAttribute("title") || "";\r\n      return this.html ? String(t) : escapeHtml(t);\r\n    }\r\n\r\n    _create() {\r\n      if (this._floating) return;\r\n      const div = document.createElement("div");\r\n      div.className = this.kind === "tooltip" ? "ux4g-tooltip" : "ux4g-popover";\r\n      div.setAttribute("role", this.kind === "tooltip" ? "tooltip" : "dialog");\r\n      div.innerHTML = this._getContent() || "";\r\n      document.body.appendChild(div);\r\n      this._floating = div;\r\n    }\r\n\r\n    show() {\r\n      if (this._open) return;\r\n      this._open = true;\r\n\r\n      // Prevent native tooltip doubling\r\n      if (this.kind === "tooltip") {\r\n        const t = this.el.getAttribute("title");\r\n        if (t != null) {\r\n          this.el.setAttribute("data-ux-original-title", t);\r\n          this.el.removeAttribute("title");\r\n        }\r\n      }\r\n\r\n      this._create();\r\n      this._floating.style.display = "block";\r\n      this._floating.classList.add("show");\r\n      const update = () => {\r\n        if (!this._open) return;
1\r\n        if (!this.el.isConnected) {\r\n          this.hide();\r\n          if (this._floating) {\r\n            this._floating.remove();\r\n            this._floating = null;\r\n          }\r\n          return;\r\n        }\r\n        U.placeFloating(this.el, this._floating, this.placement, this.offset);\r\n        this._raf = requestAnimationFrame(update);\r\n      };\r\n      this._onWin = update;\r\n      this._raf = requestAnimationFrame(update);\r\n      U.on(window, "scroll", this._onWin, { passive: true });\r\n      U.on(window, "resize", this._onWin);\r\n\r\n      U.dispatch(this.el, `ux4g.${this.kind}.shown`, {});\r\n    }\r\n\r\n    hide() {\r\n      if (!this._open) return;\r\n      this._open = false;\r\n\r\n      if (this._floating) {\r\n        this._floating.classList.remove("show");\r\n        this._floating.style.display = "none";\r\n      }\r\n\r\n      if (this.kind === "tooltip") {\r\n        const ot = this.el.getAttribute("data-ux-original-title");\r\n        if (ot != null) {\r\n          this.el.setAttribute("title", ot);\r\n          this.el.removeAttribute("data-ux-original-title");\r\n        }\r\n      }\r\n\r\n      if (this._raf) {\r\n        cancelAnimationFrame(this._raf);\r\n        this._raf = null;\r\n      }\r\n\r\n      if (this._onWin) {\r\n        U.off(window, "scroll", this._onWin);\r\n        U.off(window, "resize", this._onWin);\r\n        this._onWin = null;\r\n      }\r\n\r\n      U.dispatch(this.el, `ux4g.${this.kind}.hidden`, {});\r\n    }\r\n\r\n    toggle() { this._open ? this.hide() : this.show(); }\r\n\r\n    _bind() {\r\n      const triggers = String(this.trigger).split(/\\s+/).filter(Boolean);\r\n\r\n      if (triggers.includes("hover")) {\r\n        U.on(this.el, "mouseenter", () => this.show());\r\n        U.on(this.el, "mouseleave", () => this.hide());\r\n      }\r\n      if (triggers.includes("focus")) {\r\n        U.on(this.el, "focus", () => this.show());\r\n        U.on(this.el, "blur", () => this.hide());\r\n      }\r\n      if (triggers.includes("click")) {\r\n        U.on(this.el, "click", (e) => { e.preventDefault(); this.toggle(); });\r\n\r\n        U.on(document, "click", (e) => {\r\n          if (!this._open) return;\r\n          if (this.el.contains(e.target) || (this._floating && this._floating.contains(e.target))) return;\r\n          this.hide();\r\n        });\r\n\r\n        U.on(document, "keydown", (e) => {\r\n          if (!this._open) return;\r\n          if (e.key === "Escape") this.hide();\r\n        });\r\n      }\r\n    }\r\n\r\n    static getOrCreate(el, kind) {\r\n      const key = kind;\r\n      let inst = getI(el, key);\r\n      if (!inst) { inst = new Floating(el, kind); setI(el, key, inst); }\r\n      return inst;\r\n    }\r\n  }\r\n\r\n  function repositionManualTooltip(tooltip) {\r\n    if (!tooltip || tooltip.dataset.uxAdjusted === "true") return;\r\n\r\n    const wrapper = tooltip.closest(\'.ux4g-tooltip-wrapper\');\r\n    if (!wrapper) return;\r\n\r\n    // We need to know where it *will* be once it\'s fully hovered\r\n    const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);\r\n    const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);\r\n\r\n    const originalTransition = tooltip.style.transition;\r\n    const originalDisplay = tooltip.style.display;\r\n    const originalOpacity = tooltip.style.opacity;\r\n\r\n    // Temporarily disable transition and force show to measure target state\r\n    tooltip.style.transition = \'none\';\r\n    tooltip.style.display = \'flex\';\r\n    tooltip.style.opacity = \'0\';\r\n\r\n    // Force reflow\r\n    tooltip.offsetHeight;\r\n\r\n    let rect = tooltip.getBoundingClientRect();\r\n    const wrapperRect = wrapper.getBoundingClientRect();\r\n    const padding = 18;\r\n\r\n    // Save original class to restore on mouseout\r\n    if (!tooltip.dataset.uxOriginalClass) {\r\n      tooltip.dataset.uxOriginalClass = tooltip.className;\r\n    }\r\n\r\n    let className = tooltip.className;
1\r\n    let changed = false;\r\n\r\n    // Vertical flip\r\n    if (className.includes(\'-top-\') && rect.top < padding) {\r\n      if (wrapperRect.bottom + rect.height + padding <= vh) {\r\n        className = className.replace(\'-top-\', \'-bottom-\');\r\n        changed = true;\r\n      }\r\n    } else if (className.includes(\'-bottom-\') && rect.bottom > vh - padding) {\r\n      if (wrapperRect.top - rect.height - padding >= 0) {\r\n        className = className.replace(\'-bottom-\', \'-top-\');\r\n        changed = true;\r\n      }\r\n    }\r\n\r\n    // Horizontal flip\r\n    if (className.includes(\'-left-\') && !className.includes(\'-top-left\') && !className.includes(\'-bottom-left\') && rect.left < padding) {\r\n      if (wrapperRect.right + rect.width + padding <= vw) {\r\n        className = className.replace(\'-left-\', \'-right-\');\r\n        changed = true;\r\n      }\r\n    } else if (className.includes(\'-right-\') && !className.includes(\'-top-right\') && !className.includes(\'-bottom-right\') && rect.right > vw - padding) {\r\n      if (wrapperRect.left - rect.width - padding >= 0) {\r\n        className = className.replace(\'-right-\', \'-left-\');\r\n        changed = true;\r\n      }\r\n    }\r\n\r\n    if (changed) {\r\n      tooltip.className = className;\r\n      tooltip.dataset.uxAdjusted = "true";\r\n      rect = tooltip.getBoundingClientRect(); // Re-measure after class change\r\n    }\r\n\r\n    let shiftX = 0;\r\n    let shiftY = 0;\r\n\r\n    // Horizontal adjustment for top/bottom tooltips if still out of bounds\r\n    if (className.includes(\'-top-\') || className.includes(\'-bottom-\')) {\r\n        if (rect.left < padding) {\r\n          shiftX = padding - rect.left;\r\n        } else if (rect.right > vw - padding) {\r\n          shiftX = (vw - padding) - rect.right;\r\n        }\r\n    }\r\n\r\n    // Vertical adjustment for left/right tooltips if still out of bounds\r\n    if (className.includes(\'-left-\') || className.includes(\'-right-\')) {\r\n        if (!className.includes(\'-top-\') && !className.includes(\'-bottom-\')) {\r\n            if (rect.top < padding) {\r\n              shiftY = padding - rect.top;\r\n            } else if (rect.bottom > vh - padding) {\r\n              shiftY = (vh - padding) - rect.bottom;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (shiftX !== 0 || shiftY !== 0) {\r\n      const computedStyle = window.getComputedStyle(tooltip);\r\n      const currentTransform = computedStyle.transform === \'none\' ? \'\' : computedStyle.transform;\r\n      // Apply the fix\r\n      tooltip.style.transform = `${currentTransform} translate(${shiftX}px, ${shiftY}px)`;\r\n      tooltip.dataset.uxAdjusted = "true";\r\n    }\r\n\r\n    // Restore state (but keep the transform)\r\n    tooltip.style.display = originalDisplay;\r\n    tooltip.style.opacity = originalOpacity;\r\n    // Delay restoring transition slightly to avoid "flying" into place from old position\r\n    setTimeout(() => {\r\n      tooltip.style.transition = originalTransition;\r\n    }, 50);\r\n  }\r\n\r\n  // Initialize\r\n  window.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n    // Data API init\r\n    U.qsa(\'[data-bs-toggle="tooltip"],[data-ux-toggle="tooltip"]\').forEach(el => Floating.getOrCreate(el, "tooltip"));\r\n\r\n    // Auto-fix manual tooltips on hover\r\n    document.body.addEventListener(\'mouseover\', (e) => {\r\n      const wrapper = e.target.closest(\'.ux4g-tooltip-wrapper\');\r\n      if (wrapper) {\r\n        const tooltip = wrapper.querySelector(\'.ux4g-tooltip\');\r\n        if (tooltip) repositionManualTooltip(tooltip);\r\n      }\r\n    });\r\n\r\n    document.body.addEventListener(\'mouseout\', (e) => {\r\n      const wrapper = e.target.closest(\'.ux4g-tooltip-wrapper\');\r\n      if (wrapper && !wrapper.contains(e.relatedTarget)) {\r\n        const tooltip = wrapper.querySelector(\'.ux4g-tooltip\');\r\n        if (tooltip) {\r\n          tooltip.style.transform = \'\';\r\n          if (tooltip.dataset.uxOriginalClass) {\r\n            tooltip.className = tooltip.dataset.uxOriginalClass;\r\n            delete tooltip.dataset.uxOriginalClass;\r\n          }\r\n          delete tooltip.dataset.uxAdjusted;\r\n        }\r\n      }\r\n    });\r\n  });\r\n\r\n  // Assign to global\r\n  ux4g.Tooltip = { getOrCreate(el) { return Floating.getOrCreate(el, "tooltip"); } };\r\n\r\n  /**\r\n   * Helper to ensure menus stay within viewport and break out of clipping bounds\r\n   */\r\n  ux4g.repositionMenu = function (container, menu) {\r\n    if (!menu) return;\r\n\r\n    // Temporarily reset to absolute to calculate natural layout sizes\r\n    menu.style.position = "absolute";\r\n    menu.style.width = ""; \r\n    menu.style.top = "";\r\n    menu.style.bottom = "";\r\n    menu.style.left = "";\r\n    menu.style.right = "";\r\n    menu.style.margin = "0";\r\n\r\n    // Measure natural absolute width BEFORE fixing position\r\n    const absoluteWidth = menu.offsetWidth;
1\r\n\r\n    // Switch to fixed to break out of overflow boundaries\r\n    menu.style.position = "fixed";\r\n    menu.style.width = absoluteWidth + "px"; // lock width\r\n\r\n    const vh = window.innerHeight;\r\n    const vw = window.innerWidth;\r\n    const containerRect = container.getBoundingClientRect();\r\n    \r\n    let offsetStr = getComputedStyle(menu).getPropertyValue(\'--ux4g-dropdown-menu-offset-y\') ||\r\n        getComputedStyle(menu).getPropertyValue(\'--ux4g-combobox-menu-offset-y\') || \'6px\';\r\n    let offset = parseInt(offsetStr, 10) || 6;\r\n\r\n    // A fixed descendant is positioned against a transformed ancestor rather\r\n    // than the viewport. Keep nested menus local to floating overlays so the\r\n    // viewport coordinates below are not applied a second time.\r\n    const floatingAncestor = container.closest(\'.ux4g-popover, .ux4g-tooltip\');\r\n    if (floatingAncestor) {\r\n      menu.style.position = "absolute";\r\n      menu.style.top = (containerRect.height + offset) + "px";\r\n      menu.style.bottom = "auto";\r\n      menu.style.left = "0";\r\n      menu.style.right = "auto";\r\n\r\n      let menuRect = menu.getBoundingClientRect();\r\n      if (menuRect.bottom > vh && containerRect.top > menuRect.height + offset) {\r\n        menu.style.top = "auto";\r\n        menu.style.bottom = (containerRect.height + offset) + "px";\r\n      }\r\n\r\n      menuRect = menu.getBoundingClientRect();\r\n      if (menuRect.right > vw) {\r\n        menu.style.left = "auto";\r\n        menu.style.right = "0";\r\n      }\r\n      return;\r\n    }\r\n\r\n    let top = containerRect.bottom + offset;\r\n    let left = containerRect.left;\r\n\r\n    menu.style.top = top + "px";\r\n    menu.style.left = left + "px";\r\n\r\n    const menuRect = menu.getBoundingClientRect();\r\n\r\n    // Vertical Flip\r\n    if (menuRect.bottom > vh && containerRect.top > menuRect.height) {\r\n      menu.style.top = "auto";\r\n      menu.style.bottom = (vh - containerRect.top + offset) + "px";\r\n    } else {\r\n      menu.style.top = top + "px";\r\n      menu.style.bottom = "auto";\r\n    }\r\n\r\n    // Horizontal Shift\r\n    const updatedRect = menu.getBoundingClientRect();\r\n    if (updatedRect.right > vw) {\r\n      menu.style.left = "auto";\r\n      menu.style.right = (vw - containerRect.right) + "px";\r\n    } else {\r\n      menu.style.left = left + "px";\r\n      menu.style.right = "auto";\r\n    }\r\n  };\r\n\r\n  // Update open menus on resize/scroll\r\n  const repositionAllMenus = () => {\r\n    document.querySelectorAll(\'.ux4g-dropdown.is-open, .ux4g-combobox.is-open, .ux4g-breadcrumb-dropdown .show + .show\').forEach(el => {\r\n      let container = el;\r\n      let menu = el.querySelector(\'.ux4g-dropdown-menu, .ux4g-combobox-menu, .ux4g-breadcrumb-menu\');\r\n      if (el.classList.contains(\'ux4g-breadcrumb-toggle\')) {\r\n        container = el.parentElement;\r\n        menu = container.querySelector(\'.ux4g-breadcrumb-menu\');\r\n      }\r\n      if (container && menu) ux4g.repositionMenu(container, menu);\r\n    });\r\n  };\r\n\r\n  window.addEventListener(\'resize\', repositionAllMenus);\r\n  window.addEventListener(\'scroll\', repositionAllMenus, true); // true for capture phase to catch all scrolls\r\n\r\n  /**\r\n   * Common Filter Core Logic\r\n   */\r\n  ux4g.filterCore = {\r\n    /**\r\n     * @param {string} text - The item text to check\r\n     * @param {string} query - The search query\r\n     * @param {string} mode - \'contains\', \'starts-with\', or \'starts-with-term\'\r\n     */\r\n    matches: function (text, query, mode) {\r\n      if (!query) return true;\r\n      const t = String(text).toLowerCase();\r\n      const q = String(query).toLowerCase().trim();\r\n\r\n      switch (mode) {\r\n        case "starts-with":\r\n          return t.startsWith(q);\r\n        case "starts-with-term": {\r\n          // Split query into terms; ALL terms must match the start of some word in the text\r\n          const qTerms = q.split(/\\s+/).filter(Boolean);\r\n          if (qTerms.length === 0) return true;\r\n          const tWords = t.split(/\\s+/);\r\n          return qTerms.every((qTerm) => tWords.some((w) => w.startsWith(qTerm)));\r\n        }\r\n        case "contains":\r\n        default:\r\n          return t.includes(q);\r\n      }\r\n    },\r\n\r\n    /**\r\n     * @param {string} originalText - The text to highlight\r\n     * @param {string} query - The search query\r\n     * @param {string} mode - \'contains\', \'starts-with\', or \'starts-with-term\'\r\n     */\r\n    highlight: function (originalText, query, mode) {\r\n      if (!query) return originalText;\r\n      const q = query.trim();\r\n      const escaped = q.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&");\r\n\r\n      let regex;\r\n      switch (mode) {\r\n        case "starts-with":\r\n          regex = new RegExp(`^(${escaped})`, "i");\r\n          break;\r\n        case "starts-with-term": {\r\n          // Highlight each query term individually at word boundaries\r\n          const qTerms = q.split(/\\s+/).filter(
1Boolean);\r\n          if (qTerms.length === 0) return originalText;\r\n          const escapedTerms = qTerms.map((t) => t.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&"));\r\n          return originalText.replace(new RegExp(`\\\\b(${escapedTerms.join("|")})`, "gi"), "<strong>$1</strong>");\r\n        }\r\n        case "contains":\r\n        default:\r\n          regex = new RegExp(`(${escaped})`, "i");\r\n          break;\r\n      }\r\n\r\n      return originalText.replace(regex, "<strong>$1</strong>");\r\n    }\r\n  };\r\n\r\n})(window.ux4g);\r\n\r\n/* ========================================================= breadcrumb js ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const dropdowns = document.querySelectorAll(".ux4g-breadcrumb-dropdown");\r\n  if (!dropdowns.length) return;\r\n\r\n  const closeDropdown = (dropdown) => {\r\n    const toggle = dropdown.querySelector(".ux4g-breadcrumb-toggle");\r\n    const menu = dropdown.querySelector(".ux4g-breadcrumb-menu");\r\n\r\n    if (!toggle || !menu) return;\r\n\r\n    toggle.classList.remove("show");\r\n    menu.classList.remove("show");\r\n    toggle.setAttribute("aria-expanded", "false");\r\n  };\r\n\r\n  const openDropdown = (dropdown) => {\r\n    const toggle = dropdown.querySelector(".ux4g-breadcrumb-toggle");\r\n    const menu = dropdown.querySelector(".ux4g-breadcrumb-menu");\r\n\r\n    if (!toggle || !menu) return;\r\n\r\n    toggle.classList.add("show");\r\n    menu.classList.add("show");\r\n    toggle.setAttribute("aria-expanded", "true");\r\n    if (window.ux4g && window.ux4g.repositionMenu) {\r\n      window.ux4g.repositionMenu(dropdown, menu);\r\n    }\r\n  };\r\n\r\n  dropdowns.forEach((dropdown) => {\r\n    const toggle = dropdown.querySelector(".ux4g-breadcrumb-toggle");\r\n    const menu = dropdown.querySelector(".ux4g-breadcrumb-menu");\r\n\r\n    if (!toggle || !menu) return;\r\n\r\n    toggle.addEventListener("click", (e) => {\r\n      e.preventDefault();\r\n      e.stopPropagation();\r\n\r\n      const isOpen = menu.classList.contains("show");\r\n\r\n      dropdowns.forEach((d) => closeDropdown(d));\r\n\r\n      if (!isOpen) openDropdown(dropdown);\r\n    });\r\n\r\n    menu.addEventListener("click", () => closeDropdown(dropdown));\r\n  });\r\n\r\n  document.addEventListener("click", () => {\r\n    dropdowns.forEach((d) => closeDropdown(d));\r\n  });\r\n\r\n  document.addEventListener("keydown", (e) => {\r\n    if (e.key === "Escape") dropdowns.forEach((d) => closeDropdown(d));\r\n  });\r\n});\r\n\r\n\r\n\r\n/* ========================================================= list js ========================================================= */\r\n\r\n// Draggable js\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n\r\n  const list = document.querySelector(".ux4g-list-draggable");\r\n  let draggedItem = null;\r\n\r\n  // enable drag only from icon\r\n  document.querySelectorAll(".ux4g-icon-outlined, .ux4g-icon").forEach(icon => {\r\n\r\n    icon.addEventListener("dragstart", (e) => {\r\n      draggedItem = icon.closest(".ux4g-list-item");\r\n      draggedItem.classList.add("dragging");\r\n\r\n      e.dataTransfer.effectAllowed = "move";\r\n    });\r\n\r\n  });\r\n\r\n  document.querySelectorAll(".ux4g-list-item").forEach(item => {\r\n\r\n    item.addEventListener("dragover", (e) => {\r\n      e.preventDefault();\r\n      const dragging = document.querySelector(".dragging");\r\n\r\n      if (dragging === item) return;\r\n\r\n      const rect = item.getBoundingClientRect();\r\n      const offset = e.clientY - rect.top;\r\n\r\n      if (offset > rect.height / 2) {\r\n        item.after(dragging);\r\n      } else {\r\n        item.before(dragging);\r\n      }\r\n    });\r\n\r\n    item.addEventListener("dragend", () => {\r\n      draggedItem.classList.remove("dragging");\r\n      draggedItem = null;\r\n    });\r\n\r\n  });\r\n\r\n});\r\n\r\n/* ========================================================= Modal js ========================================================= */\r\n\r\n// Single delegated click handler — works with any framework, no re-init needed\r\ndocument.addEventListener(\'click\', (e) => {\r\n  const openBtn = e.target.closest(\'[data-modal-target], [data-target], [data-bs-target], [data-ux-target], [ux4g-target], [data-bs-toggle="modal"], [data-ux-toggle="modal"], .open-modal-btn, .modal
1-backdrop-btn-trigger\');\r\n  if (openBtn) {\r\n    let targetSelector = openBtn.getAttribute(\'data-modal-target\') ||\r\n                         openBtn.getAttribute(\'data-target\') ||\r\n                         openBtn.getAttribute(\'data-bs-target\') ||\r\n                         openBtn.getAttribute(\'data-ux-target\') ||\r\n                         openBtn.getAttribute(\'ux4g-target\') ||\r\n                         openBtn.getAttribute(\'href\');\r\n    if (targetSelector && targetSelector.indexOf(\'#\') !== 0 && targetSelector.indexOf(\'.\') !== 0) {\r\n      targetSelector = \'#\' + targetSelector;\r\n    }\r\n    const targetModal = targetSelector ? document.querySelector(targetSelector) : null;\r\n    if (targetModal) {\r\n      targetModal.classList.add(\'is-open\');\r\n      document.body.style.overflow = \'hidden\';\r\n    }\r\n    return;\r\n  }\r\n\r\n  const closeBtn = e.target.closest(\'[data-close-modal], [data-bs-dismiss="modal"], [data-ux-dismiss="modal"], [data-dismiss="modal"], [ux4g-dismiss="modal"], .close-modal-btn, .ux4g-modal-close, .ux4g-modal-close-two\');\r\n  if (closeBtn) {\r\n    // Traverse parent tree and remove is-open from all parent backdrop or modal wrappers\r\n    let parent = closeBtn.parentElement;
1\r\n    let closedAny = false;\r\n    while (parent) {\r\n      if (parent.classList && (parent.classList.contains(\'ux4g-modal-backdrop\') || parent.classList.contains(\'ux4g-modal\'))) {\r\n        if (parent.classList.contains(\'is-open\')) {\r\n          parent.classList.remove(\'is-open\');\r\n          closedAny = true;\r\n        }\r\n      }\r\n      parent = parent.parentElement;\r\n    }\r\n    // Fallback if is-open was not found on parent tree\r\n    if (!closedAny) {\r\n      const modal = closeBtn.closest(\'.ux4g-modal-backdrop, .ux4g-modal\');\r\n      if (modal) modal.classList.remove(\'is-open\');\r\n    }\r\n    if (document.querySelectorAll(\'.ux4g-modal-backdrop.is-open, .ux4g-modal.is-open\').length === 0) {\r\n      document.body.style.overflow = \'\';\r\n    }\r\n    return;\r\n  }\r\n\r\n  const openModal = e.target.closest(\'.ux4g-modal-backdrop.is-open, .ux4g-modal.is-open\');\r\n  if (openModal && !e.target.closest(\'.ux4g-modal-box\')) {\r\n    const modals = document.querySelectorAll(\'.ux4g-modal-backdrop.is-open, .ux4g-modal.is-open\');\r\n    modals.forEach(m => m.classList.remove(\'is-open\'));\r\n    if (document.querySelectorAll(\'.ux4g-modal-backdrop.is-open, .ux4g-modal.is-open\').length === 0) {\r\n      document.body.style.overflow = \'\';\r\n    }\r\n  }\r\n});\r\n\r\n// Escape key to close all open modals — registered once, never duplicates\r\ndocument.addEventListener(\'keydown\', (e) => {\r\n  if (e.key === \'Escape\') {\r\n    const openModals = document.querySelectorAll(\'.ux4g-modal-backdrop.is-open, .ux4g-modal.is-open\');\r\n    openModals.forEach(modal => modal.classList.remove(\'is-open\'));\r\n    document.body.style.overflow = \'\';\r\n  }\r\n});\r\n\r\n/* ========================================================= clear seach btn js ========================================================= */\r\n\r\n//     if (!input || !clearBtn) return;\r\n\r\n//     input.addEventListener("input", () => {\r\n//       clearBtn.classList.toggle("ux4g-show-clear", input.value.trim() !== "");\r\n//     });\r\n\r\n//     clearBtn.addEventListener("click", () => {\r\n//       input.value = "";\r\n//       clearBtn.classList.remove("ux4g-show-clear");\r\n//       input.focus();\r\n//     });\r\n//   });\r\n// });\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  document.querySelectorAll(".ux4g-search-container").forEach((searchWrap) => {\r\n    const input = searchWrap.querySelector(".ux4g-search-input");\r\n    const clearBtn = searchWrap.querySelector(".ux4g-search-clear");\r\n    const list = searchWrap.querySelector(".ux4g-search-list");\r\n    const filterMode = searchWrap.getAttribute("ux4g-search-filter") || "contains";\r\n\r\n    if (!input) return;\r\n\r\n    const toggleSearchState = () => {\r\n      searchWrap.classList.toggle("ux4g-has-value", input.value.trim() !== "");\r\n      handleSearchFilter();\r\n    };\r\n\r\n    const handleSearchFilter = () => {\r\n      if (!list) return;\r\n\r\n      // Only show list if there\'s a value, the component is active (focused),\r\n      // or it\'s forced by \'show-empty\' class\r\n      const isActive = searchWrap.classList.contains("ux4g-is-active");\r\n      const hasValue = input.value.trim() !== "";\r\n      const showEmpty = searchWrap.classList.contains("ux4g-search-show-empty");\r\n\r\n      if (isActive || hasValue || showEmpty) {\r\n        list.style.display = "block";\r\n      } else {\r\n        list.style.display = "none";\r\n      }\r\n\r\n      const value = input.value;\r\n      const options = list.querySelectorAll(".ux4g-list-item");\r\n      const isSearchable = input.id && input.id.trim() !== "";\r\n      let visibleCount = 0;\r\n\r\n      options.forEach(option => {\r\n        // Store original text\r\n        const labelNode = option.querySelector(".ux4g-list-item-start");\r\n        if (labelNode) {\r\n          labelNode.style.gap = "0"; // Remove gap that causes space between highlight and text\r\n        }\r\n        const originalText = option.dataset.originalText || (labelNode ? labelNode.textContent.trim() : option.textContent.trim());\r\n        if (!option.dataset.originalText) option.dataset.originalText = originalText;\r\n\r\n        const isMatch = isSearchable ? window.ux4g.filterCore.matches(originalText, value, filterMode) : true;\r\n        option.style.display = isMatch ? "" : "none";\r\n\r\n        if (labelNode) {\r\n          const trimmedQuery = value.trim();\r\n          if (isSearchable && trimmedQuery && isMatch) {\r\n            labelNode.innerHTML = window.ux4g.filterCore.highlight(originalText, trimmedQuery, filterMode);\r\n          } else {\r\n            labelNode.textContent = originalText;\r\n          }\r\n        }\r\n        if (isMatch) visibleCount++;\r\n      });\r\n\r\n      // Toggle No Results Message\r\n      let noResults = list.querySelector(".ux4g-search-no-results");\r\n      if (visibleCount === 0 && value.trim() !== "") {\r\n        if (!noResults) {\r\n          noResults = document.createElement("li");\r\n          noResults.className = "ux4g-search-no-results ux4g-p-s ux4g-text-center ux4g-text-muted";\r\n          noResults.style.listStyle = "none";\r\n          noResults.textContent = "No results found";\r\n          list.appendChild(noResults);\r\n        }\r\n        noResults.style.display = "";\r\n      } else if (noResults) {\r\n        noResults.style.display = "none";\r\n      }\r\n\r\n      // Optionally show list only when there\'s a value or interaction\r\n      list.style.display = (value.trim() === "" && visibleCount === 0 && !searchWra
1p.classList.contains("ux4g-search-show-empty")) ? "none" : "";\r\n\r\n      // If list is hidden, don\'t show no results either\r\n      if (list.style.display === "none" && noResults) noResults.style.display = "none";\r\n    };\r\n\r\n    input.addEventListener("input", toggleSearchState);\r\n\r\n    if (clearBtn) {\r\n      clearBtn.addEventListener("click", () => {\r\n        input.value = "";\r\n        toggleSearchState();\r\n        input.focus();\r\n      });\r\n    }\r\n\r\n    input.addEventListener("focus", () => {\r\n      searchWrap.classList.add("ux4g-is-active");\r\n      handleSearchFilter();\r\n    });\r\n\r\n    input.addEventListener("blur", (e) => {\r\n      // Small timeout to allow potential clicks on the list item itself\r\n      setTimeout(() => {\r\n        if (!searchWrap.contains(document.activeElement)) {\r\n          searchWrap.classList.remove("ux4g-is-active");\r\n          handleSearchFilter();\r\n        }\r\n      }, 200);\r\n    });\r\n\r\n    // Close when clicking outside\r\n    document.addEventListener("mousedown", (e) =>
1 {\r\n      if (!searchWrap.contains(e.target)) {\r\n        searchWrap.classList.remove("ux4g-is-active");\r\n        handleSearchFilter();\r\n      }\r\n    });\r\n\r\n    // Initial state\r\n    toggleSearchState();\r\n  });\r\n});\r\n\r\n// clear input text\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const toggle = (i) => i.closest(".ux4g-input-container")?.classList.toggle("ux4g-has-value", i.value.length > 0);\r\n\r\n  document.addEventListener("input", (e) => e.target.tagName === "INPUT" && toggle(e.target));\r\n\r\n  document.addEventListener("click", (e) => {\r\n    const btn = e.target.closest(\'[aria-label="Clear input"], .ux4g-input-clear\');\r\n    if (btn) {\r\n      const input = btn.closest(".ux4g-input-container")?.querySelector("input");\r\n      if (input && !input.disabled && !input.readOnly) {\r\n        input.value = "";\r\n        toggle(input);\r\n        input.dispatchEvent(new Event("input", { bubbles: true }));\r\n        input.focus();\r\n      }\r\n    }\r\n  });\r\n\r\n  document.querySelectorAll(".ux4g-input-container input").forEach(toggle);\r\n});\r\n\r\n/* ========================================================= textarea counter js ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const updateCounter = (textarea) => {\r\n    const wrapper = textarea.closest(".ux4g-textarea");\r\n    if (!wrapper) return;\r\n\r\n    const counter = wrapper.querySelector(".ux4g-textarea-counter");\r\n    if (!counter) return;\r\n\r\n    const maxLength = textarea.getAttribute("maxlength") || 0;\r\n    const currentLength = textarea.value.length;\r\n\r\n    // Update text content with standard "0 / 200" format \r\n    // Uses textContent to avoid XSS vectors or accidental HTML\r\n    counter.textContent = `${currentLength} / ${maxLength}`;\r\n  };\r\n\r\n  // Add listener for all input events globally (event delegation)\r\n  document.addEventListener("input", (e) => {\r\n    if (e.target && e.target.matches && e.target.matches(".ux4g-textarea-input")) {\r\n      updateCounter(e.target);\r\n    }\r\n  });\r\n\r\n  // Initialize all textareas with counters on page load\r\n  document.querySelectorAll(".ux4g-textarea-input").forEach((textarea) => {\r\n    updateCounter(textarea);\r\n  });\r\n});\r\n\r\n\r\n\r\n// ux4g drawer js\r\n\r\n/* ---------------- */\r\n/* CLOSE DRAWER FUNCTION */\r\n/* ---------------- */\r\n\r\nfunction closeDrawer() {\r\n  const openDrawer = document.querySelector(".ux4g-drawer.ux4g-drawer-open");\r\n  const openOverlay = document.querySelector(".ux4g-drawer-overlay.ux4g-drawer-open");\r\n\r\n  if (!openDrawer || !openOverlay) return;\r\n\r\n  openDrawer.classList.remove("ux4g-drawer-open");\r\n  openOverlay.classList.remove("ux4g-drawer-open");\r\n\r\n  document.body.classList.remove("ux4g-drawer-lock");\r\n}\r\n\r\n/* ---------------- */\r\n/* DELEGATED CLICK HANDLERS */\r\n/* ---------------- */\r\n\r\ndocument.addEventListener("click", (e) => {\r\n  // OPEN DRAWER\r\n  const openTrigger = e.target.closest("[data-drawer]");\r\n  if (openTrigger) {\r\n    const drawerId = openTrigger.getAttribute("data-drawer");\r\n    const drawer = document.getElementById(drawerId);\r\n    \r\n    if (drawer) {\r\n      const overlay = drawer.closest(".ux4g-drawer-overlay");\r\n\r\n      document.querySelectorAll(".ux4g-drawer-open")\r\n        .forEach(el => el.classList.remove("ux4g-drawer-open"));\r\n\r\n      if (overlay) overlay.classList.add("ux4g-drawer-open");\r\n      drawer.classList.add("ux4g-drawer-open");\r\n\r\n      document.body.classList.add("ux4g-drawer-lock");\r\n    }\r\n    return;\r\n  }\r\n\r\n  // CLOSE VIA BUTTONS\r\n  const closeTrigger = e.target.closest("[data-drawer-close]");\r\n  if (closeTrigger) {\r\n    closeDrawer();\r\n    return;\r\n  }\r\n\r\n  /* CLOSE VIA OVERLAY CLICK */\r\n  const overlay = e.target.closest(".ux4g-drawer-overlay");\r\n  if (overlay && !e.target.closest(".ux4g-drawer")) {\r\n    closeDrawer();\r\n  }\r\n});
1\r\n\r\n/* ---------------- */\r\n/* CLOSE VIA ESC KEY */\r\n/* ---------------- */\r\n\r\ndocument.addEventListener("keydown", (e) => {\r\n  if (e.key === "Escape") {\r\n    closeDrawer();\r\n  }\r\n});\r\n\r\n\r\n// ux4g table checkbox selection\r\n\r\nconst getTableRowCheckboxes = (table) => Array.from(\r\n  table.querySelectorAll(\'tbody .ux4g-table-selection-col .ux4g-checkbox-input[type="checkbox"]\')\r\n).filter(input => !input.disabled);\r\n\r\nconst syncTableSelectionState = (table) => {\r\n  if (!table) return;\r\n  const rowCheckboxes = getTableRowCheckboxes(table);\r\n  const selectAll = table.querySelector(\'thead .ux4g-checkbox-input[type="checkbox"]\');\r\n\r\n  rowCheckboxes.forEach(input => {\r\n    const row = input.closest(\'tr\');\r\n    if (row) row.classList.toggle(\'ux4g-is-selected\', input.checked);\r\n  });\r\n\r\n  if (!selectAll) return;\r\n  const selectedCount = rowCheckboxes.filter(input => input.checked).length;\r\n  selectAll.checked = rowCheckboxes.length > 0 && selectedCount === rowCheckboxes.length;\r\n  selectAll.indeterminate = selectedCount > 0 && selectedCount < rowCheckboxes.length;\r\n};\r\n\r\nconst initTableSelection = (root = document) => {\r\n  root.querySelectorAll(\'.ux4g-table\').forEach(syncTableSelectionState);\r\n};\r\n\r\ndocument.addEventListener(\'change\', (event) => {\r\n  const checkbox = event.target.closest?.(\'.ux4g-table .ux4g-checkbox-input[type="checkbox"]\');\r\n  if (!checkbox) return;\r\n\r\n  const table = checkbox.closest(\'.ux4g-table\');\r\n  if (!table) return;\r\n\r\n  if (checkbox.closest(\'thead\')) {\r\n    getTableRowCheckboxes(table).forEach(input => {\r\n      input.checked = checkbox.checked;\r\n    });\r\n  }\r\n\r\n  syncTableSelectionState(table);\r\n  window.queueMicrotask(() => syncTableSelectionState(table));\r\n  window.setTimeout(() => syncTableSelectionState(table), 0);\r\n});\r\n\r\nwindow.ux4gTableSelectionInit = initTableSelection;\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || [];\r\nwindow.ux4gCustomInitList.push(() => initTableSelection());\r\n\r\n/* ========================================================= dropdown js ========================================================= */\r\n\r\n/* ========================================================= dropdown js ========================================================= */\r\n\r\nconst ux4gDropdownInit = (root = document) => {\r\n  const dropdowns = Array.from(root.querySelectorAll(".ux4g-dropdown"))\r\n    .filter((dropdown) => dropdown.dataset.ux4gDropdownInitialized !== "true");\r\n  if (!dropdowns.length) return;\r\n\r\n  const closeDropdown = (dropdown) => {\r\n    dropdown.classList.remove("is-open");\r\n    const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n    if (control) control.setAttribute("aria-expanded", "false");\r\n  };\r\n\r\n  const openDropdown = (dropdown) => {\r\n    dropdowns.forEach((item) => {\r\n      if (item !== dropdown) closeDropdown(item);\r\n    });\r\n    dropdown.classList.add("is-open");\r\n    const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n    if (control) control.setAttribute("aria-expanded", "true");\r\n\r\n    const menu = dropdown.querySelector(".ux4g-dropdown-menu");\r\n    if (menu && window.ux4g && window.ux4g.repositionMenu) {\r\n      window.ux4g.repositionMenu(dropdown, menu);\r\n    }\r\n  };\r\n\r\n  const setControlText = (dropdown, value) => {\r\n    const hasValue = Boolean(value && String(value).trim());\r\n    dropdown.classList.toggle("has-value", hasValue);\r\n\r\n    const searchInput = dropdown.querySelector("[ux4g-dropdown-search]");\r\n    if (searchInput) {\r\n      if (dropdown.classList.contains("ux4g-dropdown-single")) {\r\n        searchInput.value = value || "";\r\n      } else {\r\n        searchInput.value = "";\r\n      }\r\n      // Trigger filter logic to stay in sync\r\n      searchInput.dispatchEvent(new Event("input", { bubbles: true }));\r\n      return;\r\n    }\r\n\r\n    const valueNode = dropdown.querySelector("[ux4g-dropdown-value]");\r\n    if (!valueNode) return;\r\n    const placeholder = valueNode.getAttribute("data-placeholder") || "Please select..";\r\n    valueNode.textContent = hasValue ? value : placeholder;\r\n    valueNode.classList.toggle("is-placeholder", !hasValue);\r\n  };\r\n\r\n  const getInputLabel = (input) => {\r\n    if (!input) return "";\r\n    if (input.dataset.label) return input.dataset.label;\r\n    if (input.value) return input.value;\r\n    const option = input.closest(".ux4g-dropdown-option");\r\n    const text = option?.querySelector(".ux4g-checkbox-label, .ux4g-dropdown-option-title");\r\n    return text?.textContent?.trim() || "";\r\n  };\r\n\r\n  const getChoiceLabel = (choice) => {\r\n    if (!choice) return "";\r\n    return (choice.getAttribute("ux4g-dropdown-choice") || choice.textContent || "").trim();\r\n  };\r\n\r\n  const applySingleSelection = (dropdown, value) => {\r\n    const chipsNode = dropdown.querySelector("[ux4g-dropdown-chips]");\r\n    dropdown.classList.remove("has-selection");\r\n    setControlText(dropdown, value);\r\n    if (!chipsNode) return;\r\n    chipsNode.innerHTML = "";\r\n  };\r\n\r\n  const setSingleSelectedOption = (dropdown, selectedOption) => {\r\n    const options = dropdown.querySelectorAll(".ux4g-dropdown-single-option");\r\n    options.forEach((option) => {\r\n      const isSelected = option === selectedOption;\r\n      if (isSelected) {\r\n        option.classList.add("is-selected", "active");\r\n        option.setAttribute("aria-selected", "true");\r\n      } else {\r\n        option.classList.remove("is-selected", "active");\r\n        option.setAttribute("aria-selected", "false");\r\n      }\r\n      const listItem = option.closest(".ux4g-list-item");\r\n      if (listItem) listItem.setAttribute("aria-selected", String(isSelected));\r\n    });\r\n  };\r\n\r\n  const renderMultiSelection = (dropdown) => {\r\n    const chipsNode = dropdown.querySelector("[ux4g-dropdown-chips]");\r\n    const checkedInputs = Array.from(\r\n      dropdown.querySelectorAll(".ux4g-dropdown-option-input:checked")\r\n    );\r\n    const options = Array.from(dropdown.querySelectorAll(".ux4g-dropdown-option"));\r\n\r\n    const hasSelection = checkedInputs.length > 0;\r\n    dropdown.classList.toggle("has-selection", hasSelection && Boolean(chipsNode));\r\n    options.forEach((option) => {\r\n      const input = option.querySelector(".ux4g-dropdown-option-input");\r\n      const isSelected = Boolean(input?.checked);\r\n      option.classList.toggle("is-selected", isSelected);\r\n      option.classList.toggle("active", isSelected);\r\n      option.setAttribute("aria-selected", String(isSelected));\r\n    });\r\n\r\n    setControlText(dropdown, "");\r\n    if (!chipsNode) return;\r\n    chipsNode.innerHTML = "";\r\n    if (!chipsNode || !hasSelection) return;
1\r\n\r\n    let chipSizeClass = "ux4g-input-chip-sm";\r\n    if (dropdown.classList.contains("ux4g-dropdown-sm")) chipSizeClass = "ux4g-input-chip-xs";\r\n    if (dropdown.classList.contains("ux4g-dropdown-lg")) chipSizeClass = "ux4g-input-chip";\r\n\r\n    checkedInputs.forEach((input) => {\r\n      const label = getInputLabel(input);\r\n      if (!label) return;\r\n\r\n      const chip = document.createElement("span");\r\n      chip.className = `${chipSizeClass} ux4g-dropdown-chip`;\r\n      chip.setAttribute("role", "button");\r\n      chip.setAttribute("tabindex", "0");\r\n      chip.setAttribute("aria-label", `Remove ${label}`);\r\n      chip.setAttribute("data-input-id", input.id);\r\n      chip.innerHTML = `<span class="ux4g-icon-outlined" aria-hidden="true">token</span><span>${label}</span><span class="ux4g-icon-outlined" aria-hidden="true">close</span>`;\r\n\r\n      const closeBtn = chip.querySelector(".ux4g-icon-outlined:last-child");\r\n\r\n      const clearSelection = (event) => {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n        input.checked = false;\r\n        renderMultiSelection(dropdown);\r\n      };\r\n\r\n      chip.addEventListener("mousedown", (event) => {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n      });\r\n\r\n      if (closeBtn) {\r\n        closeBtn.addEventListener("click", clearSelection);\r\n      }\r\n\r\n      chip.addEventListener("keydown", (event) => {\r\n        if (event.key === "Enter" || event.key === " ") {\r\n          clearSelection(event);\r\n        }\r\n      });\r\n\r\n      chipsNode.appendChild(chip);\r\n    });\r\n  };\r\n\r\n  dropdowns.forEach((dropdown, index) => {\r\n    const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n    const menu = dropdown.querySelector(".ux4g-dropdown-menu");\r\n    if (!control || !menu) return;\r\n    dropdown.dataset.ux4gDropdownInitialized = "true";\r\n\r\n    if (!control.id) {\r\n      control.id = `ux4g-dropdown-control-${index + 1}`;\r\n    }\r\n\r\n    const popupRole = menu.getAttribute("role") === "menu" ? "menu" : "listbox";\r\n    control.setAttribute("aria-haspopup", popupRole);\r\n    control.setAttribute("aria-expanded", "false");\r\n    menu.setAttribute("aria-labelledby", control.id);\r\n\r\n    const isSingle = dropdown.classList.contains("ux4g-dropdown-single");\r\n    const isMulti = dropdown.classList.contains("ux4g-dropdown-multi");\r\n\r\n    const dropdownInputs = Array.from(menu.querySelectorAll(".ux4g-dropdown-option-input"));\r\n    dropdownInputs.forEach((input, inputIndex) => {\r\n      if (!input.id) {\r\n        input.id = `${control.id}-option-${inputIndex + 1}`;\r\n      }\r\n    });\r\n\r\n    control.addEventListener("click", (event) => {\r\n      // Prevent interactions if disabled\r\n      if (control.disabled || control.getAttribute("aria-disabled") === "true") {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n        return;\r\n      }\r\n\r\n      if (event.target.closest("[ux4g-dropdown-search]")) {\r\n        if (!dropdown.classList.contains("is-open")) {\r\n          openDropdown(dropdown);\r\n        }\r\n        return;\r\n      }\r\n      event.preventDefault();\r\n      event.stopPropagation();\r\n      if (dropdown.classList.contains("is-open")) closeDropdown(dropdown);\r\n      else openDropdown(dropdown);\r\n    });\r\n\r\n    menu.addEventListener("click", (event) => {\r\n      const choice = event.target.closest("[ux4g-dropdown-choice]");\r\n      if (!choice) return;\r\n\r\n      // Stop propagation to prevent global list JS from re-adding \'active\' class\r\n      event.stopPropagation();\r\n\r\n      const value = getChoiceLabel(choice);\r\n      if (!value) return;\r\n\r\n      if (isSingle) {\r\n        setSingleSelectedOption(dropdown, choice);\r\n        applySingleSelection(dropdown, value);\r\n      } else if (!isMulti) {\r\n        setSingleSelectedOption(dropdown, choice); // Also set option for regular single selection\r\n        applySingleSelection(dropdown, value);\r\n      }\r\n\r\n      closeDropdown(dropdown);\r\n    });\r\n\r\n    menu.addEventListener("change", (event) => {\r\n      const input = event.target.closest(".ux4g-dropdown-option-input");\r\n      if (!input) return;\r\n\r\n      if (isMulti) {\r\n        renderMultiSelection(dropdown);\r\n        return;\r\n      }\r\n\r\n      if (input.checked && !isMulti) {\r\n        menu.querySelectorAll(".ux4g-dropdown-option-input").forEach((item) => {\r\n          if (item !== input) item.checked = false;\r\n        });\r\n      }\r\n\r\n      applySingleSelection(dropdown, input.checked ? getInputLabel(input) : "");\r\n      closeDropdown(dropdown);\r\n    });\r\n\r\n    menu.addEventListener("click", (event) =>
1 {\r\n      const row = event.target.closest(".ux4g-list-item-row");\r\n      if (!row) return;\r\n\r\n      const isActionDropdown =\r\n        dropdown.classList.contains("ux4g-dropdown-button") ||\r\n        dropdown.classList.contains("ux4g-dropdown-overflow");\r\n\r\n      if (isActionDropdown && !row.hasAttribute("ux4g-dropdown-choice")) {\r\n        closeDropdown(dropdown);\r\n      }\r\n    });\r\n\r\n    if (isMulti) {\r\n      const searchInput = dropdown.querySelector("[ux4g-dropdown-search]");\r\n      if (searchInput) {\r\n        const icon = searchInput.previousElementSibling;\r\n        if (icon && icon.classList.contains("ux4g-icon-outlined") && !searchInput.closest(".ux4g-dropdown-input-wrap")) {\r\n          const wrapper = document.createElement("span");\r\n          wrapper.className = "ux4g-dropdown-input-wrap";\r\n          icon.parentNode.insertBefore(wrapper, icon);\r\n          wrapper.appendChild(icon);\r\n          wrapper.appendChild(searchInput);\r\n        }\r\n      }\r\n      renderMultiSelection(dropdown);\r\n      return;\r\n    }\r\n\r\n    const preselectedSingle = menu.querySelector(\r\n      ".ux4g-dropdown-single-option.is-selected, .ux4g-dropdown-single-option[aria-selected=\'true\']"\r\n    );\r\n    if (preselectedSingle) {\r\n      setSingleSelectedOption(dropdown, preselectedSingle);\r\n      applySingleSelection(dropdown, getChoiceLabel(preselectedSingle));\r\n      return;\r\n    }\r\n\r\n    const preselectedChoice = menu.querySelector("[ux4g-dropdown-choice][aria-selected=\'true\']");\r\n    if (preselectedChoice) {\r\n      applySingleSelection(dropdown, getChoiceLabel(preselectedChoice));\r\n      return;\r\n    }\r\n\r\n    const preselectedInput = menu.querySelector(".ux4g-dropdown-option-input:checked");\r\n    applySingleSelection(dropdown, preselectedInput ? getInputLabel(preselectedInput) : "");\r\n  });\r\n\r\n  document.addEventListener("click", (event) => {\r\n    // Dynamically query open dropdowns to support frameworks that recreate DOM nodes\r\n    const openDropdowns = document.querySelectorAll(".ux4g-dropdown.is-open");\r\n    openDropdowns.forEach((dropdown) => {\r\n      if (!dropdown.contains(event.target)) {\r\n        dropdown.classList.remove("is-open");\r\n        const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n        if (control) control.setAttribute("aria-expanded", "false");\r\n      }\r\n    });\r\n  });\r\n\r\n  document.addEventListener("keydown", (event) => {\r\n    if (event.key === "Escape") {\r\n      const openDropdowns = document.querySelectorAll(".ux4g-dropdown.is-open");\r\n      openDropdowns.forEach((dropdown) => {\r\n        dropdown.classList.remove("is-open");\r\n        const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n        if (control) control.setAttribute("aria-expanded", "false");\r\n      });\r\n    }\r\n  });\r\n};\r\n\r\nwindow.ux4gDropdownInit = ux4gDropdownInit;\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || [];\r\nwindow.ux4gCustomInitList.push(() => ux4gDropdownInit(document));\r\n\r\n\r\n/* =========================================\r\nDROPDOWN SEARCH\r\n========================================= */\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  document.querySelectorAll("[ux4g-dropdown-search]").forEach((input) => {\r\n\r\n    const dropdown = input.closest(".ux4g-dropdown");\r\n    const menu = dropdown.querySelector(".ux4g-dropdown-menu");\r\n\r\n    input.addEventListener("focus", () => {\r\n      dropdown.classList.add("is-open");\r\n      if (window.ux4g && window.ux4g.repositionMenu) {\r\n        window.ux4g.repositionMenu(dropdown, menu);\r\n      }\r\n    });\r\n\r\n    input.addEventListener("input", () => {\r\n      const value = input.value;\r\n      const filterMode = dropdown.getAttribute("ux4g-dropdown-filter") || "contains";\r\n\r\n      dropdown.classList.add("is-open");\r\n      if (window.ux4g && window.ux4g.repositionMenu) {\r\n        window.ux4g.repositionMenu(dropdown, menu);\r\n      }\r\n\r\n      const options = dropdown.querySelectorAll(\r\n        ".ux4g-dropdown-single-option, .ux4g-dropdown-option"\r\n      );\r\n\r\n      options.forEach(option => {\r\n        const originalText = option.dataset.originalText || option.textContent.trim();\r\n        if (!option.dataset.originalText) option.dataset.originalText = originalText;\r\n\r\n        const isMatch = window.ux4g.filterCore.matches(originalText, value, filterMode);\r\n        option.style.display = isMatch ? "" : "none";\r\n\r\n        // Optional: Add highlighting for Dropdown Search too\r\n        const labelNode = option.querySelector(".ux4g-checkbox-label, .ux4g-dropdown-option-title, .ux4g-list-item-start");\r\n        if (labelNode) {\r\n          if (value && isMatch) {\r\n            labelNode.innerHTML = window.ux4g.filterCore.highlight(originalText, value, filterMode);\r\n          } else {\r\n            labelNode.textContent = originalText;\r\n          }\r\n        }\r\n      });\r\n    });\r\n\r\n    // Sync disabled state\r\n    const control = dropdown.querySelector(".ux4g-dropdown-control");\r\n    if (control && (control.disabled || control.getAttribute("aria-disabled") === "true")) {\r\n      input.disabled = true;\r\n    }\r\n  });\r\n});\r\n\r\n/* ========================================================= combobox js ========================================================= */\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const comboboxs = Array.from(document.querySelectorAll(".ux4g-combobox"));\r\n  if (!comboboxs.length) return;\r\n\r\n  const closeCombobox = (combobox) => {\r\n    combobox.classList.remove("is-open");\r\n    const control = combobox.querySelector(".ux4g-combobox-control");\r\n    if (control) control.setAttribute("aria-expanded", "false");\r\n  };\r\n\r\n  const openCombobox = (combobox) => {\r\n    comboboxs.forEach((item) => {\r\n      if (item !== combobox) closeCombobox(item);\r\n    });\r\n    combobox.classList.add("is-open");\r\n    const control = combobox.querySelector(".ux4g-combobox-control");\r\n    if (control) control.setAttribute("aria-expanded", "true");\r\n\r\n    const menu = combobox.querySelector(".ux4g-combobox-menu");\r\n    if (menu && window.ux4g && window.ux4g.repositionMenu) {\r\n      window.ux4g.repositionMenu(combobox, menu);\r\n    }\r\n  };\r\n\r\n  const setControlText = (combobox, value) => {\r\n    const searchInput = combobox.querySelector("[ux4g-combobox-search]");\r\n    if (searchInput) {\r\n      if (combobox.classList.contains("ux4g-combobox-single")) {\r\n        searchInput.value = value || "";\r\n      } else {\r\n        searchInput.value = "";\r\n      }\r\n      return;\r\n    }\r\n\r\n    const valueNode = combobox.querySelector("[ux4g-combobox-value]");\r\n    const hasValue = Boolean(value && String(value).trim());\r\n    if (!valueNode) return;\r\n    const placeholder = valueNode.getAttribute("data-placeholder") || "Please select..";\r\n    valueNode.textContent = hasValue ? value : placeholder;\r\n    valueNode.classList.toggle("is-placeholder", !hasValue);\r\n  };\r\n\r\n  const getInputLabel = (input) => {\r\n    if (!input) return "";\r\n    if (input.dataset.label) return input.dataset.label;\r\n    if (input.value) return input.value;\r\n    const option = input.closest(".ux4g-combobox-option");\r\n    const text = option?.querySelector(".ux4g-checkbox-label, .ux4g-combobox-option-title");\r\n    return text?.textContent?.trim() || "";\r\n  };\r\n\r\n  const getChoiceLabel = (choice) => {\r\n    if (!choice) return "";\r\n    return (choice.getAttribute("ux4g-combobox-choice") || choice.textContent || "").trim();\r\n  };\r\n\r\n  const applySingleSelection = (combobox, value) => {\r\n    const chipsNode = combobox.querySelector("[ux4g-combobox-chips]");\r\n    combobox.classList.remove("has-selection");\r\n    setControlText(combobox, value);\r\n    if (!chipsNode) return;\r\n    chipsNode.innerHTML = "";\r\n  };\r\n\r\n  const setSingleSelectedOption = (combobox, selectedOption) => {\r\n    const options = combobox.querySelectorAll(".ux4g-combobox-single-option");\r\n    options.forEach((option) => {\r\n      const isSelected = option === selectedOption;\r\n      option.classList.toggle("is-selected", isSelected);\r\n      option.classList.toggle("active", isSelected);\r\n      option.setAttribute("aria-selected", String(isSelected));\r\n      const listItem = option.closest(".ux4g-list-item");\r\n      if (listItem) listItem.setAttribute("aria-selected", String(isSelected));\r\n    });\r\n  };\r\n\r\n  const renderMultiSelection = (combobox) => {\r\n    const chipsNode = combobox.querySelector("[ux4g-combobox-chips]");\r\n    const checkedInputs = Array.from(\r\n      combobox.querySelectorAll(".ux4g-combobox-option-input:checked")\r\n    );\r\n    const options = Array.from(combobox.querySelectorAll(".ux4g-combobox-option"));\r\n\r\n    const hasSelection = checkedInputs.length > 0;\r\n    combobox.classList.toggle("has-selection", hasSelection && Boolean(chipsNode));\r\n    options.forEach((option) => {\r\n      const input = option.querySelector(".ux4g-combobox-option-input");\r\n      const isSelected = Boolean(input?.checked);\r\n      option.classList.toggle("is-selected", isSelected);\r\n      option.classList.toggle("active", isSelected);\r\n      option.setAttribute("aria-selected", String(isSelected));\r\n    });\r\n\r\n    setControlText(combobox, "");\r\n    if (!chipsNode) return;\r\n    chipsNode.style.display = "contents";\r\n    chipsNode.innerHTML = "";\r\n    if (!chipsNode || !hasSelection) return;
1\r\n\r\n    let chipSizeClass = "ux4g-input-chip-sm";\r\n    if (combobox.classList.contains("ux4g-combobox-sm")) chipSizeClass = "ux4g-input-chip-xs";\r\n    if (combobox.classList.contains("ux4g-combobox-lg")) chipSizeClass = "ux4g-input-chip";\r\n\r\n    checkedInputs.forEach((input) => {\r\n      const label = getInputLabel(input);\r\n      if (!label) return;\r\n\r\n      const chip = document.createElement("span");\r\n      chip.className = `${chipSizeClass} ux4g-combobox-chip`;\r\n      chip.setAttribute("role", "button");\r\n      chip.setAttribute("tabindex", "0");\r\n      chip.setAttribute("aria-label", `Remove ${label}`);\r\n      chip.setAttribute("data-input-id", input.id);\r\n      chip.innerHTML = `<span class="ux4g-icon-outlined" aria-hidden="true">token</span><span>${label}</span><span class="ux4g-icon-outlined" aria-hidden="true">close</span>`;\r\n\r\n      const closeBtn = chip.querySelector(".ux4g-icon-outlined:last-child");\r\n\r\n      const clearSelection = (event) => {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n        input.checked = false;\r\n        renderMultiSelection(combobox);\r\n      };\r\n\r\n      chip.addEventListener("mousedown", (event) => {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n      });\r\n\r\n      if (closeBtn) {\r\n        closeBtn.addEventListener("click", clearSelection);\r\n      }\r\n\r\n      chip.addEventListener("keydown", (event) => {\r\n        if (event.key === "Enter" || event.key === " ") {\r\n          clearSelection(event);\r\n        }\r\n      });\r\n\r\n      chipsNode.appendChild(chip);\r\n    });\r\n  };\r\n\r\n  const DEBOUNCE_DELAY = 150;\r\n  const debounce = (fn, delay) => {\r\n    let t;\r\n    return (...args) => {\r\n      clearTimeout(t);\r\n      t = setTimeout(() => fn(...args), delay);\r\n    };\r\n  };\r\n\r\n  function toggleNoResults(menu, show) {\r\n    let el = menu.querySelector(".ux4g-combobox-no-results");\r\n    if (show) {\r\n      if (!el) {\r\n        el = document.createElement("div");\r\n        el.className = "ux4g-combobox-no-results ux4g-p-s ux4g-text-center ux4g-text-muted";\r\n        el.textContent = "No results found";\r\n        menu.appendChild(el);\r\n      }\r\n      el.style.display = "";\r\n    } else if (el) {\r\n      el.style.display = "none";\r\n    }\r\n  }\r\n\r\n  comboboxs.forEach((combobox, index) => {\r\n    const control = combobox.querySelector(".ux4g-combobox-control");\r\n    const menu = combobox.querySelector(".ux4g-combobox-menu");\r\n    const input = combobox.querySelector("[ux4g-combobox-search]");\r\n    const caret = combobox.querySelector(".ux4g-combobox-caret");\r\n\r\n    if (!control || !menu) return;\r\n\r\n    // Ensure all focusable descendants inside a <button> control are removed\r\n    // from tab order to avoid nested-interactive accessibility violations.\r\n    if (control.tagName === "BUTTON") {\r\n      control.querySelectorAll("input, textarea, select, button").forEach((el) => {\r\n        el.setAttribute("tabindex", "-1");\r\n      });\r\n    }\r\n\r\n    if (!control.id) {\r\n      control.id = `ux4g-combobox-control-${index + 1}`;\r\n    }\r\n\r\n    const popupRole = menu.getAttribute("role") === "menu" ? "menu" : "listbox";\r\n    control.setAttribute("aria-haspopup", popupRole);\r\n    control.setAttribute("aria-expanded", "false");\r\n    menu.setAttribute("aria-labelledby", control.id);\r\n\r\n    const isSingle = combobox.classList.contains("ux4g-combobox-single");\r\n    const isMulti = combobox.classList.contains("ux4g-combobox-multi");\r\n    const filterMode = combobox.getAttribute("ux4g-combobox-filter") || "contains";\r\n\r\n    const comboboxInputs = Array.from(menu.querySelectorAll(".ux4g-combobox-option-input"));\r\n    comboboxInputs.forEach((input, inputIndex) => {\r\n      if (!input.id) {\r\n        input.id = `${control.id}-option-${inputIndex + 1}`;\r\n      }\r\n    });\r\n\r\n    const options = isMulti\r\n      ? Array.from(combobox.querySelectorAll(".ux4g-combobox-option"))\r\n      : Array.from(combobox.querySelectorAll(".ux4g-combobox-single-option"));\r\n\r\n    // Store original text for filtering\r\n    options.forEach((option) => {\r\n      let labelNode = isMulti\r\n        ? option.querySelector(".ux4g-checkbox-label")\r\n        : option.querySelector(".ux4g-list-item-start");\r\n\r\n      option.dataset.originalText = labelNode\r\n        ? labelNode.textContent.trim()\r\n        : option.textContent.trim();\r\n    });\r\n\r\n    const handleFilter = () => {\r\n      if (!input) return;\r\n      const value = input.value;\r\n      let visibleCount = 0;\r\n\r\n      options.forEach((option) => {\r\n        const originalText = option.dataset.originalText;\r\n        const isMatch = window.ux4g.filterCore.matches(originalText, value, filterMode);\r\n\r\n        option.style.display = isMatch ? "" : "none";\r\n\r\n        const labelNode = isMulti\r\n          ? option.querySelector(".ux4g-checkbox-label")\r\n          : option.querySelector(".ux4g-list-item-start");\r\n\r\n       if (labelNode) {\r\n          if (value && isMatch) {\r\n            labelNode.innerHTML = `<span>${window.ux4g.filterCore.highlight(originalText, value, filterMode)}</span>`;\r\n          } else {\r\n            labelNode.textContent = originalText;\r\n          }\r\n        }\r\n        if (isMatch) visibleCount++;\r\n      });\r\n      toggleNoResults(menu, visibleCount === 0 && value.trim());\r\n    };\r\n\r\n    if (input) {\r\n      input.addEventListener("focus", () => openCombobox(combobox));\r\n      input.addEventListener("input", debounce(() => {\r\n        openCombobox(combobox);\r\n        if (isSingle && input.value.trim() === "") {\r\n          setSingleSelectedOption(combobox, null);\r\n          applySingleSelection(combobox, "");\r\n        }\r\n        handleFilter();\r\n      }, DEBOUNCE_DELAY));\r\n    }\r\n\r\n    if (caret) {\r\n      caret.addEventListener("click", (e) => {\r\n        e.stopPropagation();\r\n        combobox.classList.contains("is-open") ? closeCombobox(combobox) : openCombobox(combobox);\r\n      });\r\n    }\r\n\r\n    control.addEventListener("click", (event) => {\r\n      if (control.disabled || control.getAttribute("aria-disabled") === "true") {\r\n        event.preventDefault();\r\n        event.stopPropagation();\r\n        return;\r\n      }\r\n\r\n      if (event.target.closest("[ux4g-combobox-search]")) {\r\n        if (!combobox.classList.contains("is-open")) openCombobox(combobox);\r\n        return;\r\n      }\r\n      event.preventDefault();\r\n      event.stopPropagation();\r\n      if (combobox.classList.contains("is-open")) closeCombobox(combobox);\r\n      else openCombobox(combobox);\r\n    });\r\n\r\n    menu.addEventListener("click", (event) => {\r\n      const choice = event.target.closest("[ux4g-combobox-choice]");\r\n      if (!choice) {\r\n        // Handle Action Combobox closing\r\n        const row 
1= event.target.closest(".ux4g-list-item-row");\r\n        if (row) {\r\n          const isActionCombobox =\r\n            combobox.classList.contains("ux4g-combobox-button") ||\r\n            combobox.classList.contains("ux4g-combobox-overflow");\r\n          if (isActionCombobox) {\r\n            closeCombobox(combobox);\r\n          }\r\n        }\r\n        return;\r\n      }\r\n      event.stopPropagation();\r\n\r\n      const value = getChoiceLabel(choice);\r\n      if (!value) return;\r\n\r\n      if (isSingle) {\r\n        setSingleSelectedOption(combobox, choice);\r\n        applySingleSelection(combobox, value);\r\n        handleFilter(); // Reset highlight\r\n      } else if (!isMulti) {\r\n        applySingleSelection(combobox, value);\r\n      }\r\n      closeCombobox(combobox);\r\n    });\r\n\r\n    menu.addEventListener("change", (event) => {\r\n      const inputEl = event.target.closest(".ux4g-combobox-option-input");\r\n      if (!inputEl) return;\r\n\r\n      if (isMulti) {\r\n        renderMultiSelection(combobox);\r\n        handleFilter();\r\n        return;\r\n      }\r\n\r\n      if (inputEl.checked && !isMulti) {\r\n        menu.querySelectorAll(".ux4g-combobox-option-input").forEach((item) => {\r\n          if (item !== inputEl) item.checked = false;\r\n        });\r\n      }\r\n\r\n      applySingleSelection(combobox, inputEl.checked ? getInputLabel(inputEl) : "");\r\n      closeCombobox(combobox);\r\n    });\r\n\r\n    if (isMulti) {\r\n      if (input) {\r\n        const icon = input.previousElementSibling;\r\n        if (icon && icon.classList.contains("ux4g-icon-outlined") && !input.closest(".ux4g-combobox-input-wrap")) {\r\n          const wrapper = document.createElement("span");\r\n          wrapper.className = "ux4g-combobox-input-wrap";\r\n          icon.parentNode.insertBefore(wrapper, icon);\r\n          wrapper.appendChild(icon);\r\n          wrapper.appendChild(input);\r\n        }\r\n      }\r\n      renderMultiSelection(combobox);\r\n      return;\r\n    }\r\n\r\n    const preselectedSingle = menu.querySelector(\r\n      ".ux4g-combobox-single-option.is-selected, .ux4g-combobox-single-option[aria-selected=\'true\']"\r\n    );\r\n    if (preselectedSingle) {\r\n      setSingleSelectedOption(combobox, preselectedSingle);\r\n      applySingleSelection(combobox, getChoiceLabel(preselectedSingle));\r\n      return;\r\n    }\r\n\r\n    const preselectedChoice = menu.querySelector("[ux4g-combobox-choice][aria-selected=\'true\']");\r\n    if (preselectedChoice) {\r\n      applySingleSelection(combobox, getChoiceLabel(preselectedChoice));\r\n      return;\r\n    }\r\n\r\n    const preselectedInput = menu.querySelector(".ux4g-combobox-option-input:checked");\r\n    if (preselectedInput) {\r\n      applySingleSelection(combobox, getInputLabel(preselectedInput));\r\n    }\r\n  });\r\n\r\n  document.addEventListener("click", (event) => {\r\n    const openComboboxes = document.querySelectorAll(".ux4g-combobox.is-open");\r\n    openComboboxes.forEach((combobox) => {\r\n      if (!combobox.contains(event.target)) {\r\n        combobox.classList.remove("is-open");\r\n        const control = combobox.querySelector(".ux4g-combobox-control");\r\n        if (control) control.setAttribute("aria-expanded", "false");\r\n      }\r\n    });\r\n  });\r\n\r\n  document.addEventListener("keydown", (event) => {\r\n    if (event.key === "Escape") {\r\n      const openComboboxes = document.querySelectorAll(".ux4g-combobox.is-open");\r\n      openComboboxes.forEach((combobox) => {\r\n        combobox.classList.remove("is-open");\r\n        const control = combobox.querySelector(".ux4g-combobox-control");\r\n        if (control) control.setAttribute("aria-expanded", "false");\r\n      });\r\n    }\r\n  });\r\n});\r\n\r\n\r\n/* ========================================================= ux4g Tabs ========================================================= */\r\n\r\n\r\n(function (global) {\r\n  \'use strict\';\r\n\r\n  class UX4GTab {\r\n\r\n    constructor(rootEl, options = {}) {\r\n      if (!(rootEl instanceof HTMLElement)) {\r\n        throw new Error(\'UX4GTab: rootEl must be an HTMLElement\');\r\n      }\r\n      if (rootEl.__ux4gTabInstance) {\r\n        return rootEl.__ux4gTabInstance;\r\n      }\r\n\r\n      this.root = rootEl;\r\n      this.options = Object.assign({ onChange: null }, options);\r\n      rootEl.__ux4gTabInstance = this;\r\n\r\n      this._detectConfig();\r\n      this._cleanInitialState();\r\n      this._bindEvents();\r\n    }\r\n\r\n    /* Detect elements */\r\n    _detectConfig() {\r\n      this.list = this.root.querySelector(\'.ux4g-tab-list\');\r\n      this.items = Array.from(\r\n        this.list.querySelectorAll(\'.ux4g-tab-item:not(.ux4g-tab-more)\')\r\n      );\r\n      this.moreBtns = Array.from(\r\n        this.list.querySelectorAll(\'.ux4g-tab-more\')\r\n      );\r\n      this.panels = Array.from(\r\n        this.root.querySelectorAll(\'.ux4g-tab-panel\')\r\n      );\r\n    }\r\n\r\n    /* Clean any static open state */\r\n    _cleanInitialState() {\r\n      this.root.querySelectorAll(\'.ux4g-tab-dropdown-list.is-open\')\r\n        .forEach(d => d.classList.remove(\'is-open\'));\r\n    }\r\n\r\n    /* Bind events */\r\n    _bindEvents() {\r\n\r\n      /* Regular tabs */\r\n      this.items.forEac
1h(item => {\r\n        item.addEventListener(\'click\', () => this._activateItem(item));\r\n        item.addEventListener(\'keydown\', (e) => {\r\n          if (e.key === \'Enter\') {\r\n            e.preventDefault();\r\n            this._activateItem(item);\r\n          }\r\n        });\r\n      });\r\n\r\n      /* More dropdown */\r\n      this.moreBtns.forEach(moreBtn => {\r\n        const dropdown = moreBtn.querySelector(\'.ux4g-tab-dropdown-list\');\r\n        if (!dropdown) return;\r\n\r\n        moreBtn.addEventListener(\'click\', (e) => {\r\n          const isDropdownClick = e.target.closest(\'.ux4g-tab-dropdown-list\');\r\n\r\n          if (!isDropdownClick) {\r\n            e.stopPropagation();\r\n            this._toggleDropdown(dropdown);\r\n          }\r\n        });\r\n\r\n        // Add Enter key support to open dropdown\r\n        moreBtn.addEventListener(\'keydown\', (e) => {\r\n          if (e.key === \'Enter\') {\r\n            e.preventDefault();\r\n            const isDropdownClick = e.target.closest(\'.ux4g-tab-dropdown-list\');\r\n            if (!isDropdownClick) {\r\n              e.stopPropagation();\r\n              this._toggleDropdown(dropdown);\r\n            }\r\n          }\r\n        });\r\n\r\n        dropdown.querySelectorAll(\'.ux4g-tab-dropdown-item, .ux4g-list-item\')\r\n          .forEach(dItem => {\r\n            dItem.addEventListener(\'click\', (e) => {\r\n              e.stopPropagation();\r\n              this._activateDropdownItem(dItem, moreBtn);\r\n            });\r\n            dItem.addEventListener(\'keydown\', (e) => {\r\n              if (e.key === \'Enter\') {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                this._activateDropdownItem(dItem, moreBtn);\r\n              }\r\n            });\r\n          });\r\n\r\n        // Also ensure ANY click inside the dropdown list closes it\r\n        dropdown.addEventListener(\'click\', (e) => {\r\n          this._closeAllDropdowns();\r\n        });\r\n      });\r\n\r\n      /* Outside click (scoped) */\r\n      document.addEventListener(\'click\', (e) => {\r\n        if (!e.target.closest(\'.ux4g-tab-more\')) {\r\n          this._closeAllDropdowns();\r\n        }\r\n      });\r\n    }\r\n\r\n    /* Activate normal tab */\r\n    _activateItem(item) {\r\n      if (item.classList.contains(\'ux4g-tab-item-disabled\')) return;\r\n\r\n      this._resetActive();\r\n      item.classList.add(\'active\');\r\n\r\n      const panelId = item.dataset.panel;\r\n      if (panelId) this._showPanel(panelId);\r\n\r\n      this._closeAllDropdowns();\r\n      this._emitChange(panelId);\r\n    }\r\n\r\n    /* Activate dropdown item */\r\n    _activateDropdownItem(dItem, moreBtn) {\r\n      this._resetActive();\r\n\r\n      moreBtn.classList.add(\'active\');\r\n      dItem.classList.add(\'active\');\r\n\r\n      const panelId = dItem.dataset.panel;\r\n      if (panelId) this._showPanel(panelId);\r\n\r\n      this._closeAllDropdowns();\r\n      this._emitChange(panelId);\r\n    }\r\n\r\n    /* Reset active states */\r\n    _resetActive() {\r\n      this.list.querySelectorAll(\'.ux4g-tab-item\')\r\n        .forEach(i => i.classList.remove(\'active\'));\r\n\r\n      this.root.querySelectorAll(\'.ux4g-tab-dropdown-item, .ux4g-list-item\')\r\n        .forEach(i => i.classList.remove(\'active\'));\r\n    }\r\n\r\n    /* Show panel */\r\n    _showPanel(panelId) {\r\n      this.panels.forEach(p => p.classList.remove(\'active\'));\r\n      const target = this.root.querySelector(\'#\' + panelId);\r\n      if (target) target.classList.add(\'active\');\r\n    }\r\n\r\n    /* Toggle dropdown */\r\n    _toggleDropdown(dropdown) {\r\n      const isOpen = dropdown.classList.contains(\'is-open\');\r\n      this._closeAllDropdowns();\r\n\r\n      if (!isOpen) {\r\n        dropdown.classList.add(\'is-open\');\r\n      }\r\n    }\r\n\r\n    /* Close dropdowns (scoped globally to all tabs) */\r\n    _closeAllDropdowns() {\r\n      document.querySelectorAll(\'.ux4g-tab-dropdown-list.is-open\')\r\n        .forEach(d => d.classList.remove(\'is-open\'));\r\n    }\r\n\r\n    /* Emit change */\r\n    _emitChange(panelId) {\r\n      if (typeof this.options.onChange === \'function\') {\r\n        this.options.onChange(panelId);\r\n      }\r\n    }\r\n\r\n    /* Init all */\r\n    static initAll(scope = document) {\r\n      return Array.from(scope.querySelectorAll(\'[data-ux4g-tab]\'))\r\n        .map(el => new UX4GTab(el));\r\n    }\r\n  }\r\n\r\n  global.UX4GTab = UX4GTab;\r\n\r\n})(window);\r\n\r\n/* Auto init */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  UX4GTab.initAll();\r\n});\r\n\r\n/* ========================================================= slider js ========================================================= */\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n\r\n  /* =========================================================\r\n     HELPERS\r\n  ========================================================= */\r\n\r\n  const pct = (val, min, max) => ((val - min) / (max - min)) * 100;\r\n\r\n  const buildSteps = (container, min, max, step) => {\r\n    if (!container) return;\r\n\r\n    let html = "";\r\n\r\n    for (let v = min; v <= max; v += step) {\r\n      const p = pct(v, min, max);\r\n\r\n      html += `\r\n        <div class="ux4g-slider-step" data-value="${v}" style="left:${p}%">
1\r\n          <span class="ux4g-slider-step-mark"></span>\r\n          <span class="ux4g-slider-step-label">${v}</span>\r\n        </div>\r\n      `;\r\n    }\r\n\r\n    container.innerHTML = html;\r\n  };\r\n\r\n  /* =========================================================\r\n     SINGLE SLIDERS\r\n  ========================================================= */\r\n\r\n  const singleSliders = document.querySelectorAll(\r\n    ".ux4g-slider:not(.ux4g-slider-dual)"\r\n  );\r\n\r\n  singleSliders.forEach((slider) => {\r\n\r\n    const input = slider.querySelector(".ux4g-slider-input");\r\n    const fill = slider.querySelector(".ux4g-slider-fill");\r\n    const thumb = slider.querySelector(".ux4g-slider-thumb");\r\n    const steps = slider.querySelector(".ux4g-slider-steps");\r\n\r\n    if (!input) return;\r\n\r\n    const valueBox =\r\n      slider.closest(".ux4g-slider-field")?.querySelector(\r\n        ".ux4g-slider-range-box"\r\n      );\r\n    const valueBadge =\r\n      slider.closest(".ux4g-slider-field")?.querySelector(\r\n        ".ux4g-slider-value-badge"\r\n      );\r\n\r\n    const min = parseFloat(input.min) || 0;\r\n    const max = parseFloat(input.max) || 100;\r\n    const step = parseFloat(input.step) || 10;\r\n\r\n    /* Helper: Make badge editable */\r\n    const initBadgeEdit = (badge, targetInput) => {\r\n      if (!badge) return;\r\n      badge.setAttribute("contenteditable", "true");\r\n      badge.style.cursor = "text";\r\n\r\n      // Strict number only entry\r\n      badge.addEventListener("keypress", (e) => {\r\n        if (!/[0-9]/.test(e.key) && e.key !== "Enter") {\r\n          e.preventDefault();\r\n        }\r\n      });\r\n\r\n      badge.addEventListener("keydown", (e) => {\r\n        if (e.key === "Enter") {\r\n          e.preventDefault();\r\n          badge.blur();\r\n        }\r\n      });\r\n\r\n      badge.addEventListener("blur", () => {\r\n        let raw = badge.textContent.replace(/[^0-9]/g, "");\r\n        let val = parseInt(raw, 10);\r\n        if (isNaN(val)) val = parseFloat(targetInput.value);\r\n\r\n        // Clamp 0-100\r\n        val = Math.min(max, Math.max(min, val));\r\n\r\n        targetInput.value = val;\r\n        // Trigger input event to update everything\r\n        targetInput.dispatchEvent(new Event("input"));\r\n\r\n        // Re-apply suffix if needed\r\n        const suffix = badge.textContent.includes("%") ? "%" : "";\r\n        badge.textContent = val + suffix;\r\n      });\r\n    };\r\n\r\n    if (valueBox) initBadgeEdit(valueBox, input);\r\n\r\n    /* Build Steps */\r\n\r\n    buildSteps(steps, min, max, step);\r\n\r\n    const stepEls = slider.querySelectorAll(".ux4g-slider-step");\r\n\r\n    const update = () => {\r\n\r\n      const val = parseFloat(input.value);\r\n      const p = pct(val, min, max);\r\n\r\n      if (fill) fill.style.width = p + "%";\r\n      if (thumb) thumb.style.left = p + "%";\r\n\r\n      // Only update text containers if not currently editing\r\n      const containers = [valueBadge, valueBox];\r\n      containers.forEach(container => {\r\n        if (container && document.activeElement !== container) {\r\n          const suffix = container.textContent.includes("%") ? "%" : "";\r\n          container.textContent = val + suffix;\r\n        }\r\n      });\r\n\r\n      stepEls.forEach((el) => {\r\n        const sv = parseFloat(el.dataset.value);\r\n        el.classList.toggle("is-active", sv <= val);\r\n      });\r\n\r\n    };\r\n\r\n    input.addEventListener("input", update);\r\n\r\n    update();\r\n\r\n  });\r\n\r\n  /* =========================================================\r\n     DUAL RANGE SLIDERS\r\n  ========================================================= */\r\n\r\n  const dualSliders = document.querySelectorAll(".ux4g-slider-dual");\r\n\r\n  dualSliders.forEach((slider) => {\r\n\r\n    const inputMin = slider.querySelector(".ux4g-slider-input-min");\r\n    const inputMax = slider.querySelector(".ux4g-slider-input-max");\r\n\r\n    const fill = slider.querySelector(".ux4g-slider-fill");\r\n    const thumbMin = slider.querySelector(".ux4g-slider-thumb-min");\r\n    const thumbMax = slider.querySelector(".ux4g-slider-thumb-max");\r\n\r\n    const steps = slider.querySelector(".ux4g-slider-steps");\r\n\r\n    const field = slider.closest(".ux4g-slider-field");\r\n\r\n    const minBox = field?.querySelector(".ux4g-slider-range-box:first-of-type, .ux4g-slider-range-box");\r\n    // Actually better to select all and differentiate if multiple exist\r\n    const rangeBoxes = field?.querySelectorAll(".ux4g-slider-range-box");\r\n    const valueBadges = field?.querySelectorAll(".ux4g-slider-value-badge");\r\n\r\n    if (!inputMin || !inputMax) return;\r\n\r\n    const min = parseFloat(inputMin.min) || 0;\r\n    const max = parseFloat(inputMin.max) || 100;\r\n    const step = parseFloat(inputMin.step) || 10;\r\n\r\n    /* Helper: Make box editable */\r\n    const initBoxEdit = (badge, targetInput) => {\r\n      if (!badge) return;\r\n      badge.setAttribute("contenteditable", "true");\r\n      badge.style.cursor = "text";\r\n\r\n      // Strict number only entry\r\n      badge.addEventListener("keypress", (e) => {\r\n        if (!/[0-9]/.test(e.key) && e.key !== "Enter") {\r\n          e.preventDefault();\r\n        }\r\n      });\r\n\r\n      badge.addEventListener("keydown", (e) => {\r\n        if (e.key === "Enter") {\r\n          e.preventDefault();\r\n          badge.blur();\r\n        }\r\n      });\r\n\r\n      badge.addEventListener("blur", () => {\r\n        let raw = badge.textContent.replace(/[^0-9]/g, "");\r\n        let val = parseInt(raw, 10);\r\n        if (isNaN(val)) val = parseFloat(targetInput.value);\r\n\r\n        // Clamp min-max\r\n        val = Math.min(max, Math.max(min, val));\r\n\r\n        targetInput.value = val;\r\n        // Trigger change to validate cross limits\r\n        targetInput.dispatchEvent(new Event("input"));\r\n\r\n        // Re-apply suffix\r\n        const suffix = badge.textContent.includes("%") ? "%" : "";\r\n        badge.textContent = val + suffix;\r\n      });\r\n    };\r\n\r\n    if (rangeBoxes?.[0]) initBoxEdit(rangeBoxes[0], inputMin);\r\n    if (rangeBoxes?.[1]) initBoxEdit(rangeBoxes[1], inputMax);\r\n\r\n    buildSteps(steps, min, max, step);\r\n\r\n    const stepEls = slider.querySelectorAll(".ux4g-slider-step");\r\n\r\n    const update = (e) => {\r\n\r\n      let vMin = parseFloat(inputMin.value);\r\n      let vMax = parseFloat(inputMax.value);\r\n\r\n      /* Prevent crossing */\r\n\r\n      if (e?.target === inputMin && vMin >= vMax) {\r\n        inputMin.value = vMax - step;\r\n        vMin = parseFloat(inputMin.value);\r\n      }
1\r\n\r\n      if (e?.target === inputMax && vMax <= vMin) {\r\n        inputMax.value = vMin + step;\r\n        vMax = parseFloat(inputMax.value);\r\n      }\r\n\r\n      const pMin = pct(vMin, min, max);\r\n      const pMax = pct(vMax, min, max);\r\n\r\n      if (fill) {\r\n        fill.style.left = pMin + "%";\r\n        fill.style.width = (pMax - pMin) + "%";\r\n      }\r\n\r\n      if (thumbMin) thumbMin.style.left = pMin + "%";\r\n      if (thumbMax) thumbMax.style.left = pMax + "%";\r\n\r\n      // Sync dual badges\r\n      if (valueBadges?.[0] && document.activeElement !== valueBadges[0]) {\r\n        valueBadges[0].textContent = vMin + (valueBadges[0].textContent.includes("%") ? "%" : "");\r\n      }\r\n      if (valueBadges?.[1] && document.activeElement !== valueBadges[1]) {\r\n        valueBadges[1].textContent = vMax + (valueBadges[1].textContent.includes("%") ? "%" : "");\r\n      }\r\n\r\n      // Sync dual boxes\r\n      if (rangeBoxes?.[0] && document.activeElement !== rangeBoxes[0]) {\r\n        rangeBoxes[0].textContent = vMin + (rangeBoxes[0].textContent.includes("%") ? "%" : "");\r\n      }\r\n      if (rangeBoxes?.[1] && document.activeElement !== rangeBoxes[1]) {\r\n        rangeBoxes[1].textContent = vMax + (rangeBoxes[1].textContent.includes("%") ? "%" : "");\r\n      }\r\n\r\n      /* Thumb overlap fix */\r\n\r\n      if (pMax - pMin < 10) {\r\n\r\n        inputMin.style.zIndex = pMin > 50 ? "5" : "3";\r\n        inputMax.style.zIndex = pMin > 50 ? "3" : "5";\r\n\r\n      } else {\r\n\r\n        inputMin.style.zIndex = "";\r\n        inputMax.style.zIndex = "";\r\n\r\n      }\r\n\r\n      /* Active steps */\r\n\r\n      stepEls.forEach((el) => {\r\n\r\n        const sv = parseFloat(el.dataset.value);\r\n\r\n        el.classList.toggle(\r\n          "is-active",\r\n          sv >= vMin && sv <= vMax\r\n        );\r\n\r\n      });\r\n\r\n    };\r\n\r\n    inputMin.addEventListener("input", update);\r\n    inputMax.addEventListener("input", update);\r\n\r\n    update();\r\n\r\n  });\r\n\r\n});\r\n\r\n\r\n/* ========================================================= context alert js ========================================================= */\r\n/* Trigger Toast alerts via data attributes */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  document.querySelectorAll(\'[data-ux4g-toggle="toast"]\').forEach(btn => {\r\n    btn.addEventListener(\'click\', () => {\r\n      const position = btn.dataset.ux4gPosition || \'top-right\';\r\n      const variant = btn.dataset.ux4gVariant || btn.dataset.ux4gStatus;\r\n      const title = btn.dataset.ux4gTitle;\r\n      const body = btn.dataset.ux4gBody;\r\n      showContextAlert(position, variant, title, body);\r\n    });\r\n  });\r\n});\r\n\r\nlet alertCount = 0;\r\n\r\n/**\r\n * Shows a Context Alert (Toast) in the specified position with animation\r\n * @param {string} position - \'top-left\', \'top-right\', \'bottom-left\', or \'bottom-right\'\r\n * @param {string} [variant] - Optional: \'info\', \'success\', \'warning\', \'error\', \'none\'\r\n * @param {string} [customTitle] - Optional custom title text\r\n * @param {string} [customBody] - Optional custom body text\r\n */\r\nfunction showContextAlert(position, variant, customTitle, customBody) {\r\n  const statuses = {\r\n    \'info\': { icon: \'info\', title: \'Info \' },\r\n    \'success\': { icon: \'check_circle\', title: \'Success \' },\r\n    \'warning\': { icon: \'warning\', title: \'Warning \' },\r\n    \'error\': { icon: \'error\', title: \'Error \' },\r\n    \'none\': { icon: null, title: \'Alert Title\' }\r\n  };\r\n\r\n  // Determine type (use variant, or cycle through if not provided)\r\n  const types = Object.keys(statuses).filter(t => t !== \'none\');\r\n  const type = variant || types[alertCount++ % types.length];\r\n  const status = statuses[type] || statuses[\'info\'];\r\n\r\n  const title = customTitle || status.title;\r\n  const bodyText = customBody || `This is a ${type} alert shown at the ${position.replace(\'-\', \' \')} corner.`;\r\n\r\n  const containerId = `ux4g-alert-container-${position}`;\r\n  let container = document.getElementById(containerId);\r\n\r\n  if (!container) {\r\n    container = document.createElement(\'div\');\r\n    container.id = containerId;\r\n    container.className = `ux4g-alert-container ux4g-alert-${position}`;\r\n    document.body.appendChild(container);\r\n  }\r\n\r\n  const alert = document.createElement(\'div\');\r\n  const animationClass = position.includes(\'left\') ? \'ux4g-animate-left\' : \'ux4g-animate-right\';\r\n\r\n  // Apply correct status class (fallback to info if variant is \'none\' for styling)\r\n  const statusClass = type === \'none\' ? \'info\' : type;\r\n  alert.className = `ux4g-context-alert ux4g-alert-${statusClass} ${animationClass}`;\r\n\r\n  // Icon Logic: None means no icon HTML\r\n  const iconHtml = status.icon ? `<i class="ux4g-icon ux4g-alert-icon">${status.icon}</i>` : \'\';\r\n\r\n  alert.innerHTML = `\r\n        ${iconHtml}
1\r\n        <span class="ux4g-alert-title">${title}</span>\r\n        <div class="ux4g-alert-actions">\r\n            <button class="ux4g-alert-close" onclick="closeContextAlert(this)">\r\n                <i class="ux4g-icon">close</i>\r\n            </button>\r\n        </div>\r\n        <div class="ux4g-alert-message">${bodyText}</div>\r\n    `;\r\n\r\n  if (position.includes(\'bottom\')) {\r\n    container.insertBefore(alert, container.firstChild);\r\n  } else {\r\n    container.appendChild(alert);\r\n  }\r\n\r\n  setTimeout(() => {\r\n    if (alert.parentNode) closeAlertWithAnimation(alert);\r\n  }, 5000);\r\n}\r\n\r\n/**\r\n * Handles manual close click\r\n */\r\nfunction closeContextAlert(button) {\r\n  const alert = button.closest(\'.ux4g-context-alert\');\r\n  if (alert) {\r\n    closeAlertWithAnimation(alert);\r\n  }\r\n}\r\n\r\n/**\r\n * Closes an alert with a slide-out animation\r\n */\r\nfunction closeAlertWithAnimation(alert) {\r\n  if (!alert) return;\r\n\r\n  const isLeft = alert.classList.contains(\'ux4g-animate-left\');\r\n  alert.style.transition = \'all 0.4s cubic-bezier(0.16, 1, 0.3, 1)\';\r\n  alert.style.transform = isLeft ? \'translateX(-100%)\' : \'translateX(100%)\';\r\n  alert.style.opacity = \'0\';\r\n\r\n  // Remove element after animation completes\r\n  setTimeout(() => {\r\n    if (alert.parentNode) {\r\n      alert.parentNode.removeChild(alert);\r\n    }\r\n  }, 400);\r\n}\r\n\r\n\r\n/* ========================================================= pagination js ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const pageSelects = document.querySelectorAll(".ux4g-page-size select");\r\n\r\n  pageSelects.forEach(select => {\r\n    const wrapper = select.closest(".ux4g-page-size-select-wrapper");\r\n\r\n    const updateState = () => {\r\n      if (wrapper) {\r\n        // If there\'s a selected option that isn\'t empty (or for simplicity, any selection)\r\n        if (select.value) {\r\n          wrapper.classList.add("has-value");\r\n        } else {\r\n          wrapper.classList.remove("has-value");\r\n        }\r\n      }\r\n    };\r\n\r\n    select.addEventListener("change", updateState);\r\n    // Do not run on load, so we show the placeholder icon by default\r\n  });\r\n});\r\n\r\n\r\n// NPS and Emoji Button interactions\r\n// Using global event delegation so it works seamlessly with dynamic HTML, React, Angular, etc.\r\ndocument.addEventListener(\'click\', (e) => {\r\n  // 1. NPS interaction\r\n  const npsBtn = e.target.closest(\'.feedback-nps-button\');\r\n  if (npsBtn) {\r\n    const container = npsBtn.closest(\'.ux4g-feedback-nps-wrapper\') || npsBtn.parentElement;\r\n    const siblings = Array.from(container.querySelectorAll(\'.feedback-nps-button\'));\r\n    const clickedIndex = siblings.indexOf(npsBtn);\r\n\r\n    const isHighestActive = npsBtn.classList.contains(\'active\') &&\r\n      (clickedIndex === siblings.length - 1 || !siblings[clickedIndex + 1]?.classList.contains(\'active\'));\r\n\r\n    if (isHighestActive) {\r\n      siblings.forEach(s => s.classList.remove(\'active\'));\r\n      container.removeAttribute(\'data-nps-rating\');\r\n    } else {\r\n      container.setAttribute(\'data-nps-rating\', clickedIndex);\r\n      siblings.forEach((s, i) => {\r\n        if (i <= clickedIndex) {\r\n          s.classList.add(\'active\');\r\n        } else {\r\n          s.classList.remove(\'active\');\r\n        }\r\n      });\r\n    }\r\n    return;\r\n  }\r\n\r\n  // 2. Emoji interaction\r\n  const emojiBtn = e.target.closest(\'.feedback-emoji-button\');\r\n  if (emojiBtn) {\r\n    const wasActive = emojiBtn.classList.contains(\'active\');\r\n    const container = emojiBtn.closest(\'.ux4g-d-flex\') || document;\r\n    container.querySelectorAll(\'.feedback-emoji-button\').forEach(b => b.classList.remove(\'active\'));\r\n\r\n    if (!wasActive) {\r\n      emojiBtn.classList.add(\'active\');\r\n    }\r\n    return;\r\n  }\r\n\r\n  // 3. Star interaction\r\n  const starBtn = e.target.closest(\'.ux4g-feedback-star\');\r\n  if (starBtn) {\r\n    const container = starBtn.parentElement;\r\n    const siblings = Array.from(container.querySelectorAll(\'.ux4g-feedback-star\'));\r\n    const clickedIndex = siblings.indexOf(starBtn);\r\n\r\n    const isOnlyActive = starBtn.classList.contains(\'active\') &&\r\n      (clickedIndex === siblings.length - 1 || !siblings[clickedIndex + 1]?.classList.contains(\'active\'));
1\r\n\r\n    if (isOnlyActive) {\r\n      siblings.forEach(s => s.classList.remove(\'active\'));\r\n      container.removeAttribute(\'data-rating\');\r\n    } else {\r\n      container.setAttribute(\'data-rating\', clickedIndex + 1);\r\n      siblings.forEach((s, i) => {\r\n        if (i <= clickedIndex) {\r\n          s.classList.add(\'active\');\r\n        } else {\r\n          s.classList.remove(\'active\');\r\n        }\r\n      });\r\n    }\r\n\r\n    // Toggle Submit button state based on rating\r\n    const feedbackCard = starBtn.closest(\'.ux4g-feedback\');\r\n    if (feedbackCard) {\r\n      const submitBtn = feedbackCard.querySelector(\'.ux4g-btn-primary\');\r\n      if (submitBtn) {\r\n        const hasRating = container.hasAttribute(\'data-rating\') && container.getAttribute(\'data-rating\') !== \'\';\r\n        if (hasRating) {\r\n          submitBtn.removeAttribute(\'disabled\');\r\n        } else {\r\n          submitBtn.setAttribute(\'disabled\', \'\');\r\n        }\r\n      }\r\n    }\r\n    return;\r\n  }\r\n\r\n  // 4. Submit button showing success card delegator\r\n  const submitBtn = e.target.closest(\'.ux4g-feedback:not(.ux4g-text-center) .ux4g-btn-primary\');\r\n  if (submitBtn) {\r\n    const ratingCard = submitBtn.closest(\'.ux4g-feedback\');\r\n    if (ratingCard) {\r\n      const container = ratingCard.parentElement;\r\n      if (container) {\r\n        const successCard = container.querySelector(\'.ux4g-feedback.ux4g-text-center\');\r\n        if (successCard) {\r\n          e.preventDefault();\r\n          ratingCard.style.display = \'none\';\r\n          successCard.style.display = \'flex\';\r\n          return;\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  // 5. Close button redirect delegator\r\n  const closeBtn = e.target.closest(\'.feedback-submitted-close-btn\');\r\n  if (closeBtn) {\r\n    e.preventDefault();\r\n    window.location.href = \'./global-service-discovery.html\';\r\n    return;\r\n  }\r\n\r\n  // 6. Submit and Skip Reset interaction\r\n  const resetBtn = e.target.closest(\'.ux4g-feedback .ux4g-btn-primary, .ux4g-feedback .ux4g-btn-text-primary\');\r\n  if (resetBtn) {\r\n    const feedbackContainer = resetBtn.closest(\'.ux4g-feedback\');\r\n    if (feedbackContainer) {\r\n      feedbackContainer.querySelectorAll(\'textarea\').forEach(textarea => {\r\n        textarea.value = \'\';\r\n      });\r\n      feedbackContainer.querySelectorAll(\'.active\').forEach(activeEl => {\r\n        activeEl.classList.remove(\'active\');\r\n      });\r\n    }\r\n  }\r\n});\r\n\r\n// rating enabled btn js\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  // Initialize all feedback cards\' submit buttons on load/open\r\n  const syncAllFeedbackSubmitButtons = () => {\r\n    document.querySelectorAll(\'.ux4g-feedback\').forEach(feedbackCard => {\r\n      const starContainer = feedbackCard.querySelector(\'[data-rating]\');\r\n      const submitBtn = feedbackCard.querySelector(\'.ux4g-btn-primary\');\r\n      if (submitBtn) {\r\n        const hasRating = starContainer && starContainer.hasAttribute(\'data-rating\') && starContainer.getAttribute(\'data-rating\') !== \'\';\r\n        if (hasRating) {\r\n          submitBtn.removeAttribute(\'disabled\');\r\n        } else {\r\n          submitBtn.setAttribute(\'disabled\', \'\');\r\n        }\r\n      }\r\n    });\r\n  };\r\n\r\n  syncAllFeedbackSubmitButtons();\r\n\r\n  // Also sync when modals/popups are shown/opened\r\n  document.addEventListener(\'click\', (e) => {\r\n    const trigger = e.target.closest(\'[data-modal-target], [data-target], .open-modal-btn, .modal-backdrop-btn-trigger\');\r\n    if (trigger) {\r\n      setTimeout(syncAllFeedbackSubmitButtons, 300);\r\n    }\r\n  });\r\n});\r\n\r\n\r\n/* ========================================================= carousel js ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const carousels = document.querySelectorAll(".ux4g-carousel");
1\r\n\r\n  carousels.forEach(carousel => {\r\n    const slidesContainer = carousel.querySelector(".ux4g-carousel-slides");\r\n    const slides = carousel.querySelectorAll(".ux4g-carousel-slide");\r\n    const slideCount = slides.length;\r\n    const prevBtn = carousel.querySelector(".ux4g-carousel-arrow-prev");\r\n    const nextBtn = carousel.querySelector(".ux4g-carousel-arrow-next");\r\n    const dots = carousel.querySelectorAll(".ux4g-carousel-dot");\r\n\r\n    if (slideCount === 0) return;\r\n\r\n    let currentIndex = 0;\r\n\r\n    // Initialize: find if any slide is already marked as active\r\n    slides.forEach((slide, index) => {\r\n      if (slide.classList.contains("is-active")) {\r\n        currentIndex = index;\r\n      }\r\n    });\r\n\r\n    const updateCarousel = (index) => {\r\n      // Handle looping\r\n      if (index < 0) {\r\n        index = slideCount - 1;\r\n      } else if (index >= slideCount) {\r\n        index = 0;\r\n      }\r\n\r\n      currentIndex = index;\r\n\r\n      // Move slides\r\n      if (slidesContainer) {\r\n        slidesContainer.style.transform = `translateX(-${currentIndex * 100}%)`;\r\n      }\r\n\r\n      // Update slides active state\r\n      slides.forEach((slide, i) => {\r\n        slide.classList.toggle("is-active", i === currentIndex);\r\n        slide.setAttribute("aria-hidden", i !== currentIndex);\r\n      });\r\n\r\n      // Update dots active state\r\n      dots.forEach((dot, i) => {\r\n        dot.classList.toggle("is-active", i === currentIndex);\r\n        dot.setAttribute("aria-current", i === currentIndex ? "step" : "false");\r\n      });\r\n    };\r\n\r\n    // Event Listeners\r\n    if (prevBtn) {\r\n      prevBtn.addEventListener("click", (e) => {\r\n        e.preventDefault();\r\n        updateCarousel(currentIndex - 1);\r\n      });\r\n    }\r\n\r\n    if (nextBtn) {\r\n      nextBtn.addEventListener("click", (e) => {\r\n        e.preventDefault();\r\n        updateCarousel(currentIndex + 1);\r\n      });\r\n    }\r\n\r\n    dots.forEach((dot, index) => {\r\n      dot.addEventListener("click", (e) => {\r\n        e.preventDefault();\r\n        updateCarousel(index);\r\n      });\r\n    });\r\n\r\n    // Initial update to ensure everything is synced\r\n    updateCarousel(currentIndex);\r\n  });\r\n});\r\n\r\n/* ========================================================= range slider js ========================================================= */\r\ndocument.addEventListener("input", (e) => {\r\n  if (e.target.classList.contains("ux4g-slider-input")) {\r\n    const sliderField = e.target.closest(".ux4g-slider-field");\r\n    const slider = e.target.closest(".ux4g-slider");\r\n    if (!slider) return;\r\n\r\n    const isDual = slider.classList.contains("ux4g-slider-dual");\r\n    const fill = slider.querySelector(".ux4g-slider-fill");\r\n\r\n    if (!isDual) {\r\n      const thumb = slider.querySelector(".ux4g-slider-thumb");\r\n      const percent = ((e.target.value - e.target.min) / (e.target.max - e.target.min)) * 100;\r\n      if (fill) fill.style.width = percent + "%";\r\n      if (thumb) thumb.style.left = percent + "%";\r\n\r\n      if (sliderField) {\r\n        const badge = sliderField.querySelector(".ux4g-slider-value-badge");\r\n        if (badge) badge.textContent = e.target.value + "%";\r\n      }\r\n    } else {\r\n      const inputMin = slider.querySelector(".ux4g-slider-input-min");\r\n      const inputMax = slider.querySelector(".ux4g-slider-input-max");\r\n      const thumbMin = slider.querySelector(".ux4g-slider-thumb-min");\r\n      const thumbMax = slider.querySelector(".ux4g-slider-thumb-max");\r\n\r\n      let min = parseFloat(inputMin.value);\r\n      let max = parseFloat(inputMax.value);\r\n      const rangeMin = parseFloat(inputMin.min);\r\n      const rangeMax = parseFloat(inputMin.max);\r\n\r\n      if (e.target.classList.contains("ux4g-slider-input-min")) {\r\n        if (min > max) {\r\n          min = max;\r\n          inputMin.value = min;\r\n        }\r\n      } else {\r\n        if (max < min) {\r\n          max = min;\r\n          inputMax.value = max;\r\n        }\r\n      }\r\n\r\n      const left = ((min - rangeMin) / (rangeMax - rangeMin)) * 100;\r\n      const width = ((max - min) / (rangeMax - rangeMin)) * 100;\r\n\r\n      if (fill) {\r\n        fill.style.left = left + "%";\r\n        fill.style.width = width + "%";\r\n      }\r\n      if (thumbMin) thumbMin.style.left = left + "%";\r\n      if (thumbMax) thumbMax.style.left = (left + width) + "%";\r\n\r\n      if (sliderField) {\r\n        const badges = sliderField.querySelectorAll(".ux4g-slider-value-badge");\r\n        if (badges.length >= 2) {\r\n          badges[0].textContent = min + "%";\r\n          badges[1].textContent = max + "%";\r\n        }\r\n      }\r\n    }\r\n  }\r\n});\r\n\r\n\r\n/********************************* UX4G DatePicker & TimePicker JS **
1*********************************/\r\n\r\n(function (global) {\r\n  "use strict";\r\n\r\n  const makeKeyboardClickable = (el) => {\r\n    if (!el) return;\r\n    if (el.tagName !== \'BUTTON\' && el.tagName !== \'INPUT\') {\r\n      if (!el.hasAttribute(\'tabindex\')) el.setAttribute(\'tabindex\', \'0\');\r\n      el.addEventListener(\'keydown\', (e) => {\r\n        if (e.key === \'Enter\' || e.key === \' \') {\r\n          e.preventDefault();\r\n          el.click();\r\n        }\r\n      });\r\n    }\r\n  };\r\n\r\n  // Shared Backdrop\r\n  let backdrop = document.querySelector(\'.ux4g-date-picker-backdrop\');\r\n  const getBackdrop = () => {\r\n    if (!backdrop) {\r\n      backdrop = document.createElement(\'div\');\r\n      backdrop.className = \'ux4g-date-picker-backdrop\';\r\n      document.body.appendChild(backdrop);\r\n    }\r\n    return backdrop;\r\n  };\r\n\r\n  const isMobile = () => window.innerWidth <= 576;\r\n  const initializedDatePickers = new WeakSet();\r\n  const initializedRangeDatePickers = new WeakSet();\r\n  const initializedTimePickers = new WeakSet();\r\n\r\n  const adjustDropdownPosition = (dropdown, container) => {\r\n    if (!dropdown || !container) return;\r\n    const viewportGap = 8;\r\n    dropdown.style.top = \'\';\r\n    dropdown.style.bottom = \'\';\r\n    dropdown.style.left = \'\';\r\n    dropdown.style.right = \'\';\r\n    dropdown.style.width = \'\';\r\n    dropdown.style.maxHeight = \'\';\r\n    dropdown.style.overflowX = \'\';\r\n    dropdown.style.overflowY = \'\';\r\n    dropdown.style.marginTop = \'\';\r\n    dropdown.style.marginBottom = \'\';\r\n    const containerRect = container.getBoundingClientRect();\r\n    const dropdownRect = dropdown.getBoundingClientRect();\r\n    const windowHeight = window.innerHeight || document.documentElement.clientHeight;\r\n    const windowWidth = window.innerWidth || document.documentElement.clientWidth;\r\n\r\n    // Anchor to the actual input rather than the container\'s bounding box. Using\r\n    // the container edge can create artificial gaps when the container is made\r\n    // taller for layout reasons.\r\n    const trigger = container.querySelector(\'.ux4g-date-picker-input:focus, .ux4g-time-picker-input:focus\') ||\r\n                      container.querySelector(\'.ux4g-date-picker-input, .ux4g-time-picker-input\') ||\r\n                      container;\r\n    const triggerRect = trigger.getBoundingClientRect();\r\n\r\n    const spaceBelow = windowHeight - triggerRect.bottom - viewportGap;\r\n    const spaceAbove = triggerRect.top - viewportGap;\r\n    const openAbove = spaceBelow < dropdownRect.height && spaceAbove > spaceBelow;\r\n    const width = Math.min(containerRect.width, windowWidth - (viewportGap * 2));\r\n    const left = Math.min(\r\n      Math.max(containerRect.left, viewportGap),\r\n      Math.max(windowWidth - width - viewportGap, viewportGap)\r\n    );\r\n\r\n    // Fixed positioning escapes overflow/scroll containers (including Storybook\r\n    // preview wrappers) while keeping the popup anchored to its input.\r\n    dropdown.style.position = \'fixed\';\r\n    dropdown.style.width = `${width}px`;\r\n    dropdown.style.left = `${left}px`;\r\n    dropdown.style.right = \'auto\';\r\n    if (openAbove) {\r\n      const topPos = Math.max(viewportGap, triggerRect.top - dropdownRect.height - viewportGap);\r\n      dropdown.style.top = `${topPos}px`;\r\n    } else {\r\n      dropdown.style.top = `${triggerRect.bottom + viewportGap}px`;\r\n    }\r\n    dropdown.style.bottom = \'auto\';\r\n  };\r\n\r\n  const resetDropdownPosition = (dropdown) => {\r\n    if (!dropdown) return;\r\n    [\'position\', \'top\', \'bottom\', \'left\', \'right\', \'width\', \'maxHeight\',\r\n      \'overflowX\', \'overflowY\', \'marginTop\', \'marginBottom\']\r\n      .forEach(property => { dropdown.style[property] = \'\'; });\r\n  };\r\n\r\n  const repositionOpenDropdowns = () => {\r\n    if (isMobile()) return;\r\n    document.querySelectorAll(\'.ux4g-date-picker-dropdown.is-open, .ux4g-time-picker-dropdown.is-open\')\r\n      .forEach(dropdown => {\r\n        const container = dropdown.closest(\'.ux4g-date-range-picker, .ux4g-date-picker-container, .ux4g-time-picker-container\');\r\n        adjustDropdownPosition(dropdown, container);\r\n      });\r\n  };\r\n\r\n  window.addEventListener(\'resize\', repositionOpenDropdowns);\r\n  window.addEventListener(\'scroll\', repositionOpenDropdowns, true);\r\n\r\n  class DatePicker {\r\n    constructor(container) {\r\n      this.container = container;\r\n      this.input = container.querySelector(\'.ux4g-date-picker-input\');\r\n      this.dropdown = container.querySelector(\'.ux4g-date-picker-dropdown\');\r\n      this.calendarGrid = container.querySelector(\'.ux4g-date-picker-grid\');\r\n      this.monthLabel = container.querySelector(\'.ux4g-date-picker-current\');\r\n\r\n      const navBtns = container.querySelectorAll(\'.ux4g-date-picker-nav-btn\');\r\n      this.prevBtn = navBtns[0];\r\n      this.nextBtn = navBtns[1];\r\n\r\n      this.confirmBtn = container.querySelector(\'.ux4g-btn-primary\');\r\n      this.cancelBtn = container.querySelector(\'.ux4g-btn-outline-neutral\');\r\n\r\n      this.currentDate = new Date();\r\n      this.viewDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);\r\n      this.selectedDate = null;\r\n      this.tempSelectedDate = null;\r\n\r\n      this.isSelectingYearMonth = false;\r\n\r\n      this._init();\r\n    }\r\n\r\n    _init() {\r\n      if (!this.input || !this.dropdown) return;\r\n\r\n      if (this.input.value) {\r\n        const parts = this.input.value.split(\'/\');\r\n        if (parts.length === 3) {\r\n          this.selectedDate = new Date(parts[2], parts[1] - 1, parts[0]);\r\n          this.viewDate = new Date(parts[2], parts[1] - 1, 1);\r\n          this.tempSelectedDate = new Date(this.selectedDate);\r\n        }\r\n      }\r\n\r\n      // Keyboard accessibility\r\n      this.input.addEventListener(\'keydown\', (e) => {\r\n        if (e.key === \'Enter\' || e.key === \' \') {\r\n          e.preventDefault();\r\n          this.open();\r\n        }\r\n      });
1\r\n\r\n      this.input.addEventListener(\'focus\', (e) => {\r\n        this.open();\r\n      });\r\n\r\n      this.input.addEventListener(\'click\', (e) => {\r\n        e.stopPropagation();\r\n        this.open();\r\n      });\r\n\r\n      if (this.prevBtn) {\r\n        makeKeyboardClickable(this.prevBtn);\r\n        this.prevBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.changeYearRange(-8);\r\n          } else {\r\n            this.changeMonth(-1);\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.nextBtn) {\r\n        makeKeyboardClickable(this.nextBtn);\r\n        this.nextBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.changeYearRange(8);\r\n          } else {\r\n            this.changeMonth(1);\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.monthLabel) {\r\n        makeKeyboardClickable(this.monthLabel);\r\n        this.monthLabel.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.isSelectingYearMonth = !this.isSelectingYearMonth;\r\n          this.render();\r\n          setTimeout(() => {\r\n            if (this.isSelectingYearMonth) {\r\n              const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n              let el = calendarContainer.querySelector(\'.ux4g-date-picker-year-item.is-selected\') || calendarContainer.querySelector(\'.ux4g-date-picker-year-item\');\r\n              if (el) el.focus();\r\n            } else {\r\n              let el = this.calendarGrid.querySelector(\'.is-selected\') || this.calendarGrid.querySelector(\'.is-today\') || this.calendarGrid.querySelector(\'.ux4g-date-picker-day:not(.is-muted)\');\r\n              if (el) el.focus();\r\n            }\r\n          }, 0);\r\n        });\r\n      }\r\n\r\n      if (this.confirmBtn) {\r\n        makeKeyboardClickable(this.confirmBtn);\r\n        this.confirmBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.isSelectingYearMonth = false;\r\n            this.render();\r\n            setTimeout(() => {\r\n              let el = this.calendarGrid.querySelector(\'.is-selected\') || this.calendarGrid.querySelector(\'.is-today\') || this.calendarGrid.querySelector(\'.ux4g-date-picker-day:not(.is-muted)\');\r\n              if (el) el.focus();\r\n            }, 0);\r\n          } else {\r\n            this.confirmSelection();\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.cancelBtn) {\r\n        makeKeyboardClickable(this.cancelBtn);\r\n        this.cancelBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.cancelSelection();\r\n        });\r\n      }\r\n\r\n      document.addEventListener(\'click\', (e) => {\r\n        if (!this.container.contains(e.target) && !getBackdrop().contains(e.target)) {\r\n          this.close();\r\n        }\r\n      });\r\n\r\n      getBackdrop().addEventListener(\'click\', () => {\r\n        this.close();\r\n      });\r\n\r\n      this.render();\r\n    }\r\n\r\n    open() {\r\n      if (this.dropdown) {\r\n        this.tempSelectedDate = this.selectedDate ? new Date(this.selectedDate) : null;\r\n        this.isSelectingYearMonth = false;\r\n        this.dropdown.classList.add(\'is-open\');\r\n        if (isMobile()) {\r\n          getBackdrop().classList.add(\'is-active\');\r\n          document.body.style.overflow = \'hidden\';\r\n        } else {\r\n          adjustDropdownPosition(this.dropdown, this.container);\r\n        }\r\n        this.render();\r\n      }\r\n    }\r\n\r\n    close() {\r\n      if (this.dropdown) {\r\n        this.dropdown.classList.remove(\'is-open\');\r\n        resetDropdownPosition(this.dropdown);\r\n        getBackdrop().classList.remove(\'is-active\');\r\n        document.body.style.overflow = \'\';\r\n      }\r\n    }\r\n\r\n    confirmSelection() {\r\n      this.selectedDate = this.tempSelectedDate ? new Date(this.tempSelectedDate) : null;\r\n      if (this.selectedDate) {\r\n        const day = String(this.selectedDate.getDate()).padStart(2, \'0\');
1\r\n        const month = String(this.selectedDate.getMonth() + 1).padStart(2, \'0\');\r\n        const year = this.selectedDate.getFullYear();\r\n        this.input.value = `${day}/${month}/${year}`;\r\n      } else {\r\n        this.input.value = \'\';\r\n      }\r\n      this.close();\r\n    }\r\n\r\n    cancelSelection() {\r\n      this.tempSelectedDate = this.selectedDate ? new Date(this.selectedDate) : null;\r\n      this.close();\r\n    }\r\n\r\n    changeMonth(delta) {\r\n      this.viewDate.setMonth(this.viewDate.getMonth() + delta);\r\n      this.render();\r\n    }\r\n\r\n    changeYearRange(delta) {\r\n      this.viewDate.setFullYear(this.viewDate.getFullYear() + delta);\r\n      this.render();\r\n    }\r\n\r\n    render() {\r\n      if (this.isSelectingYearMonth) {\r\n        this.renderYearMonthSelection();\r\n      } else {\r\n        this.renderCalendar();\r\n      }\r\n    }\r\n\r\n    renderCalendar() {\r\n      const year = this.viewDate.getFullYear();\r\n      const month = this.viewDate.getMonth();\r\n      const monthNames = ["January", "February", "March", "April", "May", "June",\r\n        "July", "August", "September", "October", "
1November", "December"\r\n      ];\r\n\r\n      if (this.monthLabel) {\r\n        this.monthLabel.innerHTML = `${monthNames[month]} ${year} <span class="ux4g-icon-outlined ux4g-fs-18">keyboard_arrow_down</span>`;\r\n      }\r\n\r\n      const calendarHtml = `\r\n                <div class="ux4g-date-picker-weekdays">\r\n                    <div class="ux4g-date-picker-weekday">Mo</div>\r\n                    <div class="ux4g-date-picker-weekday">Tu</div>\r\n                    <div class="ux4g-date-picker-weekday">We</div>\r\n                    <div class="ux4g-date-picker-weekday">Th</div>\r\n                    <div class="ux4g-date-picker-weekday">Fr</div>\r\n                    <div class="ux4g-date-picker-weekday">Sa</div>\r\n                    <div class="ux4g-date-picker-weekday">Su</div>\r\n                </div>\r\n                <div class="ux4g-date-picker-grid"></div>\r\n            `;\r\n\r\n      const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n      calendarContainer.innerHTML = calendarHtml;\r\n      this.calendarGrid = calendarContainer.querySelector(\'.ux4g-date-picker-grid\');\r\n\r\n      const firstDayOfMonth = new Date(year, month, 1).getDay();\r\n      const daysInMonth = new Date(year, month + 1, 0).getDate();\r\n      let startDay = firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1;\r\n      const prevMonthLastDay = new Date(year, month, 0).getDate();\r\n\r\n      let html = \'\';\r\n      for (let i = startDay - 1; i >= 0; i--) {\r\n        html += `<div class="ux4g-date-picker-day is-muted">${prevMonthLastDay - i}</div>`;\r\n      }\r\n\r\n      for (let i = 1; i <= daysInMonth; i++) {\r\n        const date = new Date(year, month, i);\r\n        const isToday = date.toDateString() === this.currentDate.toDateString();\r\n        const isSelected = this.tempSelectedDate && date.toDateString() === this.tempSelectedDate.toDateString();\r\n\r\n        let classes = \'ux4g-date-picker-day\';\r\n        if (isToday) classes += \' is-today\';\r\n        if (isSelected) classes += \' is-selected\';\r\n\r\n        html += `<div class="${classes}" data-date="${i}" tabindex="0">${i}</div>`;\r\n      }\r\n\r\n      const totalCells = 42;\r\n      const remainingCells = totalCells - (startDay + daysInMonth);\r\n      for (let i = 1; i <= remainingCells; i++) {\r\n        html += `<div class="ux4g-date-picker-day is-muted">${i}</div>`;\r\n      }\r\n\r\n      this.calendarGrid.innerHTML = html;\r\n      this.calendarGrid.querySelectorAll(\'.ux4g-date-picker-day:not(.is-muted)\').forEach(dayEl => {\r\n        makeKeyboardClickable(dayEl);\r\n        dayEl.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          const day = e.target.dataset.date;\r\n          this.selectDate(new Date(year, month, day));\r\n        });\r\n      });\r\n\r\n      if (this.confirmBtn) {\r\n        this.confirmBtn.innerHTML = \'Confirm\';\r\n        this.confirmBtn.disabled = !this.tempSelectedDate;\r\n      }\r\n    }\r\n\r\n    renderYearMonthSelection() {\r\n      const currentYear = this.viewDate.getFullYear();\r\n      const startYear = Math.floor(currentYear / 8) * 8;\r\n      const endYear = startYear + 7;\r\n\r\n      if (this.monthLabel) {\r\n        this.monthLabel.innerHTML = `${startYear}-${endYear} <span class="ux4g-icon-outlined ux4g-fs-18">keyboard_arrow_down</span>`;\r\n      }\r\n\r\n      let html = \'<div class="ux4g-date-picker-selection-view">\';\r\n      html += \'<div class="ux4g-date-picker-year-grid">\';\r\n      for (let y = startYear; y <= endYear; y++) {\r\n        const isSelected = y === this.viewDate.getFullYear();\r\n        html += `<div class="ux4g-date-picker-year-item ${isSelected ? \'is-selected\' : \'\'}" data-year="${y}" tabindex="0">${y}</div>`;\r\n      }\r\n      html += \'</div>\';\r\n\r\n      const monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];\r\n      html += \'<div class="ux4g-date-picker-month-grid">\';\r\n      monthNamesShort.forEach((m, i) => {\r\n        const isSelected = i === this.viewDate.getMonth();\r\n        html += `<div class="ux4g-date-picker-month-item ${isSelected ? \'is-selected\' : \'\'}" data-month="${i}" tabindex="0">${m}</div>`;\r\n      });\r\n      html += \'</div></div>\';\r\n\r\n      const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n      calendarContainer.innerHTML = html;\r\n\r\n      calendarContainer.querySelectorAll(\'.ux4g-date-picker-year-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.viewDate.setFullYear(parseInt(e.target.dataset.year));\r\n          this.renderYearMonthSelection();\r\n          setTimeout(() => {\r\n            const selectedMonth = this.container.querySelector(\'.ux4g-date-picker-month-item.is-selected\');\r\n            if (selectedMonth) selectedMonth.focus();\r\n          }, 0);\r\n        });\r\n      });\r\n\r\n      calendarContainer.querySelectorAll(\'.ux4g-date-picker-month-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.viewDate.setMonth(parseInt(e.target.dataset.month));\r\n          this.renderYearMonthSelection();\r\n          if (this.confirmBtn) setTimeout(() => this.confirmBtn.focus(), 0);\r\n        });\r\n      });\r\n\r\n      if (this.confirmBtn) {\r\n        this.confirmBtn.innerHTML = \'Select date\';\r\n        this.confirmBtn.disabled = false;\r\n      }\r\n    }\r\n\r\n    selectDate(date) {\r\n      this.tempSelectedDate = date;\r\n      this.render();\r\n      if (this.confirmBtn && !this.confirmBtn.disabled) {\r\n        setTimeout(() => this.confirmBtn.focus(), 0);\r\n      }\r\n    }\r\n  }\r\n\r\n  class RangeDatePicker {\r\n    constructor(container) {\r\n      this.container = container;\r\n      this.inputs = container.querySelectorAll(\'.ux4g-date-picker-input\');\r\n      this.dropdown = container.querySelector(\'.ux4g-date-picker-dropdown\');\r\n      this.calendarGrid = container.querySelector(\'.ux4g-date-picker-grid\');\r\n      this.monthLabel = container.querySelector(\'.ux4g-date-picker-current\');\r\n\r\n      const navBtns = container.querySelectorAll(\'.ux4g-date-picker-nav-btn\');\r\n      this.prevBtn = navBtns[0];\r\n      this.nextBtn = navBtns[1];\r\n\r\n      this.confirmBtn = container.querySelector(\'.ux4g-btn-primary\');\r\n      this.cancelBtn = container.querySelector(\'.ux4g-btn-outline-neutral\');\r\n\r\n      this.currentDate = new Date();\r\n      this.viewDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);\r\n      this.startDate = null;\r\n      this.endDate = null;\r\n      this.tempStartDate = null;\r\n      this.tempEndDate = null;\r\n      this.selectingEnd = false;\r\n      this.isSelectingYearMonth = false;\r\n\r\n      this._init();\r\n    }\r\n\r\n    _init() {\r\n      if (!this.inputs.length || !this.dropdown) return;
1\r\n\r\n      this.inputs.forEach(input => {\r\n        // Keyboard accessibility\r\n        input.addEventListener(\'keydown\', (e) => {\r\n          if (e.key === \'Enter\' || e.key === \' \') {\r\n            e.preventDefault();\r\n            this.open();\r\n          }\r\n        });\r\n\r\n        input.addEventListener(\'focus\', (e) => {\r\n          this.open();\r\n        });\r\n\r\n        input.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.open();\r\n        });\r\n      });\r\n\r\n      if (this.prevBtn) {\r\n        makeKeyboardClickable(this.prevBtn);\r\n        this.prevBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.changeYearRange(-8);\r\n          } else {\r\n            this.changeMonth(-1);\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.nextBtn) {\r\n        makeKeyboardClickable(this.nextBtn);\r\n        this.nextBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.changeYearRange(8);\r\n          } else {\r\n            this.changeMonth(1);\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.monthLabel) {\r\n        makeKeyboardClickable(this.monthLabel);\r\n        this.monthLabel.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.isSelectingYearMonth = !this.isSelectingYearMonth;\r\n          this.render();\r\n          setTimeout(() => {\r\n            if (this.isSelectingYearMonth) {\r\n              const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n              let el = calendarContainer.querySelector(\'.ux4g-date-picker-year-item.is-selected\') || calendarContainer.querySelector(\'.ux4g-date-picker-year-item\');\r\n              if (el) el.focus();\r\n            } else {\r\n              let el = this.calendarGrid.querySelector(\'.is-range-start\') || this.calendarGrid.querySelector(\'.is-selected\') || this.calendarGrid.querySelector(\'.is-today\') || this.calendarGrid.querySelector(\'.ux4g-date-picker-day:not(.is-muted)\');\r\n              if (el) el.focus();\r\n            }\r\n          }, 0);\r\n        });\r\n      }\r\n\r\n      if (this.confirmBtn) {\r\n        makeKeyboardClickable(this.confirmBtn);\r\n        this.confirmBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (this.isSelectingYearMonth) {\r\n            this.isSelectingYearMonth = false;\r\n            this.render();\r\n            setTimeout(() => {\r\n              let el = this.calendarGrid.querySelector(\'.is-range-start\') || this.calendarGrid.querySelector(\'.is-selected\') || this.calendarGrid.querySelector(\'.is-today\') || this.calendarGrid.querySelector(\'.ux4g-date-picker-day:not(.is-muted)\');\r\n              if (el) el.focus();\r\n            }, 0);\r\n          } else {\r\n            this.confirmSelection();\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.cancelBtn) {\r\n        this.cancelBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.cancelSelection();\r\n        });\r\n      }\r\n\r\n      document.addEventListener(\'click\', (e) => {\r\n        if (!this.container.contains(e.target) && !getBackdrop().contains(e.target)) {\r\n          this.close();\r\n        }\r\n      });\r\n\r\n      getBackdrop().addEventListener(\'click\', () => {\r\n        this.close();\r\n      });\r\n\r\n      this.render();\r\n    }\r\n\r\n    open() {\r\n      if (this.dropdown) {\r\n        this.tempStartDate = this.startDate ? new Date(this.startDate) : null;\r\n        this.tempEndDate = this.endDate ? new Date(this.endDate) : null;\r\n        this.selectingEnd = this.tempStartDate && !this.tempEndDate;\r\n        this.isSelectingYearMonth = false;\r\n        this.dropdown.classList.add(\'is-open\');\r\n        if (isMobile()) {\r\n          getBackdrop().classList.add(\'is-active\');\r\n          document.body.style.overflow = \'hidden\';\r\n        } else {\r\n          adjustDropdownPosition(this.dropdown, this.container);\r\n        }\r\n        this.render();\r\n      }\r\n    }\r\n\r\n    close() {\r\n      if (this.dropdown) {\r\n        this.dropdown.classList.remove(\'is-open\');\r\n        resetDropdownPosition(this.dropdown);\r\n        getBackdrop().classList.remove(\'is-active\');\r\n        document.body.style.overflow = \'\';\r\n      }\r\n    }\r\n\r\n    confirmSelection() {\r\n      this.startDate = this.tempStartDate ? new Date(this.tempStartDate) : null;\r\n      this.endDate = this.tempEndDate ? new Date(this.tempEndDate) : null;\r\n      this.updateInputs();\r\n      this.close();\r\n    }\r\n\r\n    cancelSelection() {\r\n      this.tempStartDate = this.startDate ? new Date(this.tempStartDate) : null;\r\n      this.tempEndDate = this.endDate ? new Date(this.endDate) : null;\r\n      this.close();\r\n    }\r\n\r\n    changeMonth(delta) {\r\n      this.viewDate.setMonth(this.viewDate.getMonth() + delta);\r\n      this.render();\r\n    }\r\n\r\n    changeYearRange(delta) {\r\n      this.viewDate.setFullYear(this.viewDate.getFullYear() + delta);\r\n      this.render();\r\n    }\r\n\r\n    render() {\r\n      if (this.isSelectingYearMonth) {\r\n        this.renderYearMonthSelection();\r\n      }
1 else {\r\n        this.renderCalendar();\r\n      }\r\n    }\r\n\r\n    renderCalendar() {\r\n      const year = this.viewDate.getFullYear();\r\n      const month = this.viewDate.getMonth();\r\n      const monthNames = ["January", "February", "March", "April", "May", "June",\r\n        "July", "August", "September", "October", "November", "December"\r\n      ];\r\n\r\n      if (this.monthLabel) {\r\n        this.monthLabel.innerHTML = `${monthNames[month]} ${year} <span class="ux4g-icon-outlined ux4g-fs-18">keyboard_arrow_down</span>`;\r\n      }\r\n\r\n      const calendarHtml = `\r\n                <div class="ux4g-date-picker-weekdays">\r\n                    <div class="ux4g-date-picker-weekday">Mo</div>\r\n                    <div class="ux4g-date-picker-weekday">Tu</div>\r\n                    <div class="ux4g-date-picker-weekday">We</div>\r\n                    <div class="ux4g-date-picker-weekday">Th</div>\r\n                    <div class="ux4g-date-picker-weekday">Fr</div>\r\n                    <div class="ux4g-date-picker-weekday">Sa</div>\r\n                    <div class="ux4g-date-picker-weekday">Su</div>\r\n                </div>\r\n                <div class="ux4g-date-picker-grid"></div>\r\n            `;\r\n\r\n      const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n      calendarContainer.innerHTML = calendarHtml;\r\n      this.calendarGrid = calendarContainer.querySelector(\'.ux4g-date-picker-grid\');\r\n\r\n      const firstDayOfMonth = new Date(year, month, 1).getDay();\r\n      const daysInMonth = new Date(year, month + 1, 0).getDate();\r\n      let startDay = firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1;\r\n      const prevMonthLastDay = new Date(year, month, 0).getDate();\r\n\r\n      let html = \'\';\r\n      for (let i = startDay - 1; i >= 0; i--) {\r\n        html += `<div class="ux4g-date-picker-day is-muted">${prevMonthLastDay - i}</div>`;\r\n      }\r\n\r\n      for (let i = 1; i <= daysInMonth; i++) {\r\n        const date = new Date(year, month, i);\r\n        const isToday = date.toDateString() === this.currentDate.toDateString();\r\n\r\n        let classes = \'ux4g-date-picker-day\';\r\n        if (isToday) classes += \' is-today\';\r\n\r\n        if (this.tempStartDate && date.toDateString() === this.tempStartDate.toDateString()) {\r\n          classes += \' is-selected is-range-start\';\r\n        } else if (this.tempEndDate && date.toDateString() === this.tempEndDate.toDateString()) {\r\n          classes += \' is-selected is-range-end\';\r\n        } else if (this.tempStartDate && this.tempEndDate && date > this.tempStartDate && date < this.tempEndDate) {\r\n          classes += \' is-in-range\';\r\n        }\r\n\r\n        html += `<div class="${classes}" data-date="${i}" tabindex="0">${i}</div>`;\r\n      }\r\n\r\n      const totalCells = 42;\r\n      const remainingCells = totalCells - (startDay + daysInMonth);\r\n      for (let i = 1; i <= remainingCells; i++) {\r\n        html += `<div class="ux4g-date-picker-day is-muted">${i}</div>`;\r\n      }\r\n\r\n      this.calendarGrid.innerHTML = html;\r\n      this.calendarGrid.querySelectorAll(\'.ux4g-date-picker-day:not(.is-muted)\').forEach(dayEl => {\r\n        makeKeyboardClickable(dayEl);\r\n        dayEl.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          const day = e.target.dataset.date;\r\n          this.handleDateSelection(new Date(year, month, day));\r\n        });\r\n      });\r\n\r\n      if (this.confirmBtn) {\r\n        this.confirmBtn.innerHTML = \'Confirm\';\r\n        this.confirmBtn.disabled = !this.tempStartDate || !this.tempEndDate;\r\n      }\r\n    }\r\n\r\n    renderYearMonthSelection() {\r\n      const currentYear = this.viewDate.getFullYear();\r\n      const startYear = Math.floor(currentYear / 8) * 8;\r\n      const endYear = startYear + 7;\r\n\r\n      if (this.monthLabel) {\r\n        this.monthLabel.innerHTML = `${startYear}-${endYear} <span class="ux4g-icon-outlined ux4g-fs-18">keyboard_arrow_down</span>`;\r\n      }\r\n\r\n      let html = \'<div class="ux4g-date-picker-selection-view">\';\r\n      html += \'<div class="ux4g-date-picker-year-grid">\';\r\n      for (let y = startYear; y <= endYear; y++) {\r\n        const isSelected = y === this.viewDate.getFullYear();\r\n        html += `<div class="ux4g-date-picker-year-item ${isSelected ? \'is-selected\' : \'\'}" data-year="${y}" tabindex="0">${y}</div>`;\r\n      }\r\n      html += \'</div>\';\r\n\r\n      const monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];\r\n      html += \'<div class="ux4g-date-picker-month-grid">\';\r\n      monthNamesShort.forEach((m, i) => {\r\n        const isSelected = i === this.viewDate.getMonth();\r\n        html += `<div class="ux4g-date-picker-month-item ${isSelected ? \'is-selected\' : \'\'}" data-month="${i}" tabindex="0">${m}</div>`;\r\n      });\r\n      html += \'</div></div>\';\r\n\r\n      const calendarContainer = this.container.querySelector(\'.ux4g-date-picker-calendar\');\r\n      calendarContainer.innerHTML = html;\r\n\r\n      calendarContainer.querySelectorAll(\'.ux4g-date-picker-year-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.viewDate.setFullYear(parseInt(e.target.dataset.year));\r\n          this.renderYearMonthSelection();\r\n          setTimeout(() => {\r\n            const selectedMonth = this.container.querySelector(\'.ux4g-date-picker-month-item.is-selected\');\r\n            if (selectedMonth) selectedMonth.focus();\r\n          }, 0);\r\n        });\r\n      });\r\n\r\n      calendarContainer.querySelectorAll(\'.ux4g-date-picker-month-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.viewDate.setMonth(parseInt(e.target.dataset.month));\r\n          this.renderYearMonthSelection();\r\n          if (this.confirmBtn) setTimeout(() => this.confirmBtn.focus(), 0);\r\n        });\r\n      });\r\n\r\n      if (this.confirmBtn) {\r\n        this.confirmBtn.innerHTML = \'Select date\';\r\n        this.confirmBtn.disabled = false;\r\n      }\r\n    }\r\n\r\n    handleDateSelection(date) {\r\n      if (!this.tempStartDate || (this.tempStartDate && this.tempEndDate)) {\r\n        this.tempStartDate = date;\r\n        this.tempEndDate = null;\r\n        this.selectingEnd = true;\r\n      } else if (this.selectingEnd) {\r\n        if (date < this.tempStartDate) {\r\n          this.tempEndDate = this.tempStartDate;\r\n          this.tempStartDate = date;\r\n        } else {\r\n          this.tempEndDate = date;\r\n        }\r\n        this.selectingEnd = false;\r\n      }\r\n      this.render();\r\n      if (!this.selectingEnd && this.confirmBtn && !this.confirmBtn.disabled) {\r\n        setTimeout(() => this.confirmBtn.focus(), 0);\r\n      } else if (this.selectingEnd) {\r\n        setTimeout(() => {\r\n          const selectedEl = this.calendarGrid.querySelector(\'.is-range-start\');\r\n          if (selectedEl) selectedEl.focus();\r\n        }, 0);\r\n      }\r\n    }\r\n\r\n    updateInputs() {\r\n      if (this.startDate) {\r\n        const d = String(this.startDate.getDate()).padStart(2, \'0\');
1\r\n        const m = String(this.startDate.getMonth() + 1).padStart(2, \'0\');\r\n        const y = this.startDate.getFullYear();\r\n        this.inputs[0].value = `${d}/${m}/${y}`;\r\n      } else {\r\n        this.inputs[0].value = \'\';\r\n      }\r\n      if (this.endDate) {\r\n        const d = String(this.endDate.getDate()).padStart(2, \'0\');\r\n        const m = String(this.endDate.getMonth() + 1).padStart(2, \'0\');\r\n        const y = this.endDate.getFullYear();\r\n        this.inputs[1].value = `${d}/${m}/${y}`;\r\n      } else {\r\n        this.inputs[1].value = \'\';\r\n      }\r\n    }\r\n  }\r\n\r\n  class TimePicker {\r\n    constructor(container) {\r\n      this.container = container;\r\n      this.input = container.querySelector(\'.ux4g-time-picker-input\');\r\n      this.dropdown = container.querySelector(\'.ux4g-time-picker-dropdown\');\r\n      this.hhColumn = container.querySelector(\'[data-column="hh"]\');\r\n      this.mmColumn = container.querySelector(\'[data-column="mm"]\');\r\n      this.ampmBtns = container.querySelectorAll(\'.ux4g-time-picker-ampm-btn\');\r\n      this.confirmBtn = container.querySelector(\'.ux4g-btn-primary\');\r\n      this.cancelBtn = container.querySelector(\'.ux4g-btn-outline-neutral\');\r\n\r\n      this.selectedHH = null;\r\n      this.selectedMM = null;\r\n      this.selectedAMPM = "PM";\r\n\r\n      this.tempHH = null;\r\n      this.tempMM = null;\r\n\r\n      this._init();\r\n    }\r\n\r\n    _init() {\r\n      if (!this.input || !this.dropdown) return;\r\n\r\n      // Keyboard accessibility\r\n      this.input.addEventListener(\'keydown\', (e) => {\r\n        if (e.key === \'Enter\' || e.key === \' \') {\r\n          e.preventDefault();\r\n          this.open();\r\n        }\r\n      });\r\n\r\n      this.input.addEventListener(\'focus\', (e) => {\r\n        this.open();\r\n      });\r\n\r\n      this.input.addEventListener(\'click\', (e) => {\r\n        e.stopPropagation();\r\n        this.open();\r\n      });\r\n\r\n      this.ampmBtns.forEach(btn => {\r\n        makeKeyboardClickable(btn);\r\n        btn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.selectedAMPM = e.target.dataset.value;\r\n          this.updateAMPMUI();\r\n        });\r\n      });\r\n\r\n      if (this.confirmBtn) {\r\n        makeKeyboardClickable(this.confirmBtn);\r\n        this.confirmBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          if (!this.confirmBtn.disabled) {\r\n            this.confirmSelection();\r\n          }\r\n        });\r\n      }\r\n\r\n      if (this.cancelBtn) {\r\n        makeKeyboardClickable(this.cancelBtn);\r\n        this.cancelBtn.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.close();\r\n        });\r\n      }\r\n\r\n      document.addEventListener(\'click\', (e) => {\r\n        if (!this.container.contains(e.target) && !getBackdrop().contains(e.target)) {\r\n          this.close();\r\n        }\r\n      });\r\n\r\n      this.renderColumns();\r\n      this.updateAMPMUI();\r\n      this.validate();\r\n    }\r\n\r\n    open() {\r\n      this.tempHH = this.selectedHH;\r\n      this.tempMM = this.selectedMM;\r\n\r\n      this.dropdown.classList.add(\'is-open\');\r\n      if (isMobile()) {\r\n        getBackdrop().classList.add(\'is-active\');\r\n        document.body.style.overflow = \'hidden\';\r\n      } else {\r\n        adjustDropdownPosition(this.dropdown, this.container);\r\n      }\r\n\r\n      this.renderColumns();\r\n      this.scrollToSelected();\r\n      this.validate();\r\n    }\r\n\r\n    close() {\r\n      this.dropdown.classList.remove(\'is-open\');\r\n      resetDropdownPosition(this.dropdown);\r\n      getBackdrop().classList.remove(\'is-active\');\r\n      document.body.style.overflow = \'\';\r\n    }\r\n\r\n    validate() {\r\n      if (this.confirmBtn) {\r\n        this.confirmBtn.disabled = !(this.tempHH && this.tempMM);\r\n      }\r\n    }\r\n\r\n    confirmSelection() {\r\n      this.selectedHH = this.tempHH;\r\n      this.selectedMM = this.tempMM;\r\n      this.input.value = `${this.selectedHH} : ${this.selectedMM} ${this.selectedAMPM}`;\r\n      this.close();\r\n    }\r\n\r\n    updateAMPMUI() {\r\n      this.ampmBtns.forEach(btn => {\r\n        btn.classList.toggle(\'is-active\', btn.dataset.value === this.selectedAMPM);\r\n      });\r\n    }\r\n\r\n    renderColumns() {\r\n      // Hours (1-12)\r\n      let hhHtml = \'<div class="ux4g-time-picker-col-header">HH</div>\';\r\n      for (let i = 1; i <= 12; i++) {\r\n        const val = String(i).padStart(2, \'0\');\r\n        const isSelected = val === this.tempHH;\r\n        hhHtml += `<div class="ux4g-time-picker-item ${isSelected ? \'is-selected\' : \'\'}" data-value="${val}" tabindex="0">${val}</div>`;\r\n      }\r\n      this.hhColumn.innerHTML = hhHtml;\r\n\r\n      // Minutes (0-55, step 5)\r\n      let mmHtml = \'<div class="ux4g-time-picker-col-header">MM</div>\';\r\n      for (let i = 0; i < 60; i += 5) {\r\n        const val = String(i).padStart(2, \'0\');\r\n        const isSelected = val === this.tempMM;\r\n        mmHtml += `<div class="ux4g-time-picker-item ${isSelected ? \'is-selected\' : \'\'}" data-value="${val}" tabindex="0">${val}</div>`;\r\n      }\r\n      this.mmColumn.innerHTML = mmHtml;\r\n\r\n      // Click events\r\n      this.hhColumn.querySelectorAll(\'.ux4g-time-picker-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.tempHH = e.target.dataset.value;\r\n          this.updateColumnSelection(this.hhColumn, this.tempHH);\r\n          this.validate();\r\n          if (!this.confirmBtn.disabled) {\r\n            setTimeout(() => this.confirmBtn.focus(), 0);\r\n          } else if (!this.tempMM) {\r\n            const firstMM = this.mmColumn.querySelector(\'.ux4g-time-picker-item\');\r\n            if (firstMM) setTimeout(() => firstMM.focus(), 0);\r\n          }\r\n        });\r\n      });\r\n\r\n      this.mmColumn.querySelectorAll(\'.ux4g-time-picker-item\').forEach(el => {\r\n        makeKeyboardClickable(el);\r\n        el.addEventListener(\'click\', (e) => {\r\n          e.stopPropagation();\r\n          this.tempMM = e.target.dataset.value;\r\n          this.updateColumnSelection(this.mmColumn, this.tempMM);\r\n          this.validate();\r\n          if (!this.confirmBtn.disabled) {\r\n            setTimeout(() => this.confirmBtn.focus(), 0);\r\n          }\r\n        });\r\n      });\r\n    }\r\n\r\n    updateColumnSelection(column, value) {\r\n      column.querySelectorAll(\'.ux4g-time-picker-item\').forEach(el => {\r\n        el.classList.toggle(\'is-selected\', el.dataset.value === value);\r\n      });\r\n    }\r\n\r\n    scrollToSelected() {\r\n      const columns = [this.hhColumn, this.mmColumn];\r\n      columns.forEach(col => {\r\n        const selected = col.querySelector(\'.is-selected\');\r\n        if (selected) {\r\n          col.scrollTop = selected.offsetTop - col.offsetTop - 80;\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  const init = () => {\r\n    document.querySelectorAll(\'.ux4g-date-picker-container\').forEach(container => {\r\n      if (!container.closest(\'.ux4g-date-range-picker\') && !initializedDatePickers.has(container)) {\r\n        initializedDatePickers.add(container);\r\n        new DatePicker(container);\r\n      }\r\n    });\r\n    document.querySelectorAll(\'.ux4g-date-range-picker\').forEach(container => {\r\n      if (!initializedRangeDatePickers.has(container)) {\r\n        initializedRangeDatePickers.add(container);\r\n        new RangeDatePicker(container);\r\n      }\r\n    });\r\n    document.querySelectorAll(\'.ux4g-time-picker-container\').forEach(container => {\r\n      if (!initializedTimePickers.has(container)) {\r\n        initializedTimePickers.add(container);\r\n        new TimePicker(container);\r\n      }\r\n    });\r\n  };\r\n\r\n  window.ux4gCustomInitList = window.ux4gCustomInitList || [];\r\n  window.ux4gCustomInitList.push(init);\r\n\r\n  if (document.readyState === \'loading\') document.addEventListener(\'DOMContentLoaded\', init);\r\n  else init();\r\n\r\n  global.DatePicker = DatePicker;\r\n  global.RangeDatePicker = RangeDatePicker;\r\n  global.TimePicker = TimePicker;\r\n  global.ux4gDateTimePickerInit = init;\r\n\r\n})(window);\r\n\r\n\r\n/********************************* Time Slot JS ***********************************/\r\n\r\nclass TimeSlotCalendar {\r\n    constructor(container) {\r\n        this.container = container;\r\n        this.calendarGrid = container.querySelector(\'.ux4g-time-slot-compact-grid\');\r\n        this.monthLabel = container.querySelector(\'.ux4g-time-slot-compact-month\');\r\n        this.slotTitle = container.querySelector(\'.ux4g-time-slot-compact-desktop-header\');\r\n        this.slotsList = container.querySelector(\'.ux4g-time-slot-compact-list\');\r\n        this.confirmBtn = container.querySelector(\'.ux4g-btn-primary\');\r\n        \r\n        const navBtns = container.querySelectorAll(\'.ux4g-btn-icon\');\r\n        this.prevBtn = navBtns[0];\r\n        this.nextBtn = navBtns[1];\r\n\r\n        this.currentDate = new Date();\r\n        this.viewDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);\r\n        this.selectedDate = new Date(2026, 3, 23); // Default from design: April 23, 2026\r\n\r\n        // Mock Data for Statuses\r\n        this.holidays = [\'202
16-04-09\', \'2026-04-21\'];\r\n        this.weeklyOffs = [0, 6]; // Sunday, Saturday\r\n        this.noSlotsDates = [\'2026-04-08\', \'2026-04-13\'];\r\n\r\n        this._init();\r\n    }\r\n\r\n    _init() {\r\n        if (this.prevBtn) {\r\n            this.prevBtn.addEventListener(\'click\', () => this.changeMonth(-1));\r\n        }\r\n        if (this.nextBtn) {\r\n            this.nextBtn.addEventListener(\'click\', () => this.changeMonth(1));\r\n        }\r\n\r\n        // Cancel Button Reset Logic\r\n        const cancelBtn = this.container.querySelector(\'.ux4g-btn-outline-neutral\');\r\n        if (cancelBtn) {\r\n            cancelBtn.addEventListener(\'click\', () => {\r\n                this.selectedDate = null; // Reset selection\r\n                this.render(); // Re-render calendar to clear highlights\r\n                if (this.slotTitle) this.slotTitle.innerText = "Select a Date"; // Reset slot header\r\n                this.resetSlots(); // Clear slot selection and disable confirm button\r\n            });\r\n        }\r\n\r\n        this.render();\r\n    }\r\n\r\n    changeMonth(delta) {\r\n        this.viewDate.setMonth(this.viewDate.getMonth() + delta);\r\n        this.render();\r\n    }\r\n\r\n    render() {\r\n        this.renderCalendar();\r\n    }\r\n\r\n    renderCalendar() {\r\n        const year = this.viewDate.getFullYear();
1\r\n        const month = this.viewDate.getMonth();\r\n        const monthNames = ["January", "February", "March", "April", "May", "June",\r\n            "July", "August", "September", "October", "November", "December"\r\n        ];\r\n\r\n        // Update Month Label\r\n        if (this.monthLabel) {\r\n            this.monthLabel.innerText = `${monthNames[month]} ${year}`;\r\n        }\r\n\r\n        const firstDayOfMonth = new Date(year, month, 1).getDay();\r\n        const daysInMonth = new Date(year, month + 1, 0).getDate();\r\n        \r\n        // Adjust for Monday start\r\n        let startDay = firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1;\r\n        const prevMonthLastDay = new Date(year, month, 0).getDate();\r\n\r\n        // Clear and rebuild grid\r\n        this.calendarGrid.innerHTML = \'\';\r\n\r\n        // Add Weekday Names\r\n        const days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];\r\n        days.forEach(day => {\r\n            const dayEl = document.createElement(\'div\');\r\n            dayEl.className = \'ux4g-time-slot-day-name\';\r\n            dayEl.innerText = day;\r\n            this.calendarGrid.appendChild(dayEl);\r\n        });\r\n\r\n        // Previous Month Days\r\n        for (let i = startDay - 1; i >= 0; i--) {\r\n            const dateEl = document.createElement(\'div\');\r\n            dateEl.className = \'ux4g-time-slot-date muted\';\r\n            dateEl.innerText = prevMonthLastDay - i;\r\n            this.calendarGrid.appendChild(dateEl);\r\n        }\r\n\r\n        // Current Month Days\r\n        const todayMidnight = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), this.currentDate.getDate());\r\n        for (let i = 1; i <= daysInMonth; i++) {\r\n            const date = new Date(year, month, i);\r\n            const dateStr = date.getFullYear() + \'-\' + String(date.getMonth() + 1).padStart(2, \'0\') + \'-\' + String(i).padStart(2, \'0\');\r\n            const isToday = date.toDateString() === this.currentDate.toDateString();\r\n            const isPast = date < todayMidnight;\r\n            const isSelected = this.selectedDate && date.toDateString() === this.selectedDate.toDateString();\r\n            const isHoliday = this.holidays.includes(dateStr);\r\n            const isWeeklyOff = this.weeklyOffs.includes(date.getDay());\r\n            const isNoSlots = this.noSlotsDates.includes(dateStr);\r\n\r\n            const dateEl = document.createElement(\'div\');\r\n            dateEl.className = \'ux4g-time-slot-date\';\r\n            if (isPast) dateEl.classList.add(\'disabled\');\r\n            if (isToday) dateEl.classList.add(\'today\');\r\n            if (isSelected && !isPast) dateEl.classList.add(\'selected\');\r\n            if (isHoliday) dateEl.classList.add(\'holiday\');\r\n            if (isWeeklyOff) dateEl.classList.add(\'weekly-off\');\r\n            if (isNoSlots) dateEl.classList.add(\'no-slots\');\r\n            \r\n            dateEl.innerText = i;\r\n            dateEl.dataset.date = i;\r\n\r\n            if (!isPast) {\r\n                dateEl.addEventListener(\'click\', () => {\r\n                    this.selectedDate = new Date(year, month, i);\r\n                    this.render();\r\n                    this.updateSlotHeader();\r\n                    this.resetSlots();\r\n                });\r\n            }\r\n\r\n            this.calendarGrid.appendChild(dateEl);\r\n        }\r\n\r\n        // Next Month Days\r\n        const totalCells = 42 + 7; // Including header row\r\n        const currentCells = this.calendarGrid.children.length;\r\n        const remainingCells = totalCells - currentCells;\r\n        for (let i = 1; i <= remainingCells; i++) {\r\n            const dateEl = document.createElement(\'div\');\r\n            dateEl.className = \'ux4g-time-slot-date muted\';\r\n            dateEl.innerText = i;\r\n            this.calendarGrid.appendChild(dateEl);\r\n        }\r\n    }\r\n\r\n    updateSlotHeader() {\r\n        if (this.slotTitle && this.selectedDate) {\r\n            const day = this.selectedDate.getDate();\r\n            const monthNames = ["January", "February", "March", "April", "May", "June",\r\n                "July", "August", "September", "October", "
1November", "December"\r\n            ];\r\n            const month = monthNames[this.selectedDate.getMonth()];\r\n            const year = this.selectedDate.getFullYear();\r\n            this.slotTitle.innerText = `${day}${this.getOrdinal(day)} ${month} ${year}`;\r\n        }\r\n    }\r\n\r\n    resetSlots() {\r\n        // Reset slot selection and disable confirm button\r\n        const slots = this.container.querySelectorAll(\'.ux4g-time-slot-compact-slot-item:not(.disabled)\');\r\n        slots.forEach(s => {\r\n            s.classList.remove(\'selected\');\r\n            s.style.backgroundColor = \'\';\r\n        });\r\n        if (this.confirmBtn) this.confirmBtn.setAttribute(\'disabled\', \'true\');\r\n        \r\n        // Re-attach slot selection listeners\r\n        slots.forEach(slot => {\r\n            slot.addEventListener(\'click\', () => {\r\n                slots.forEach(s => {\r\n                    s.classList.remove(\'selected\');\r\n                    s.style.backgroundColor = \'\';\r\n                });\r\n                slot.classList.add(\'selected\');\r\n                if (this.confirmBtn) this.confirmBtn.removeAttribute(\'disabled\');\r\n            });\r\n        });\r\n    }\r\n\r\n    getOrdinal(n) {\r\n        const s = ["th", "st", "nd", "rd"];\r\n        const v = n % 100;\r\n        return (s[(v - 20) % 10] || s[v] || s[0]);\r\n    }\r\n}\r\n\r\n// Initialize on Load\r\ndocument.addEventListener(\'DOMContentLoaded\', () => {\r\n    // Initialize Compact Calendar\r\n    const compactContainers = document.querySelectorAll(\'.ux4g-time-slot-compact-container, #ux4g-time-slot, [id^="ux4g-time-slot-compact"]\');\r\n    compactContainers.forEach(container => {\r\n        new TimeSlotCalendar(container);\r\n    });\r\n\r\n    // Initialize Weekly Grid Selection\r\n    const weeklyGrids = document.querySelectorAll(\'.ux4g-time-slot-weekly-grid, [id^="ux4g-time-slot-weekly"]\');\r\n    weeklyGrids.forEach(weeklyGrid => {\r\n        const cells = weeklyGrid.querySelectorAll(\'.ux4g-time-slot-cell.available, .ux4g-time-slot-cell.limited\');\r\n        const confirmBtn = weeklyGrid.parentElement.querySelector(\'.ux4g-time-slot-weekly-actions .ux4g-btn-primary\');\r\n        const cancelBtn = weeklyGrid.parentElement.querySelector(\'.ux4g-time-slot-weekly-actions .ux4g-btn-outline-neutral\');\r\n\r\n        cells.forEach(cell => {\r\n            // Store original content to restore later\r\n            const originalHTML = cell.innerHTML;\r\n\r\n            cell.addEventListener(\'click\', () => {\r\n                if (cell.classList.contains(\'selected\')) return;\r\n\r\n                // 1. Restore all other cells to their original state\r\n                cells.forEach(c => {\r\n                    if (c.classList.contains(\'selected\')) {\r\n                        c.classList.remove(\'selected\');\r\n                        if (c._originalContent) {\r\n                            c.innerHTML = c._originalContent;\r\n                        }\r\n                    }\r\n                });\r\n\r\n                // 2. Select this cell\r\n                cell.classList.add(\'selected\');\r\n                cell._originalContent = originalHTML;\r\n                cell.innerHTML = `<span class="ux4g-icon-filled">check_circle</span> Selected`;\r\n\r\n                // 3. Enable Confirm Button\r\n                if (confirmBtn) confirmBtn.removeAttribute(\'disabled\');\r\n            });\r\n        });\r\n\r\n        // Cancel Button logic for Weekly Grid\r\n        if (cancelBtn) {\r\n            cancelBtn.addEventListener(\'click\', () => {\r\n                cells.forEach(c => {\r\n                    if (c.classList.contains(\'selected\')) {\r\n                        c.classList.remove(\'selected\');\r\n                        if (c._originalContent) {\r\n                            c.innerHTML = c._originalContent;\r\n                        }\r\n                    }\r\n                });\r\n                if (confirmBtn) confirmBtn.setAttribute(\'disabled\', \'true\');\r\n            });\r\n        }\r\n\r\n        // Initialize Weekly Grid Mobile Navigation (Dynamic approach)\r\n        const container = weeklyGrid.closest(\'.ux4g-time-slot-weekly-container\');\r\n        if (container) {\r\n            const mobileNav = container.querySelector(\'.ux4g-time-slot-mobile-nav\');\r\n            if (mobileNav) {\r\n                const mobileDateLabel = mobileNav.querySelector(\'.ux4g-time-slot-mobile-date\');\r\n                const navBtns = mobileNav.querySelectorAll(\'.ux4g-btn-icon\');\r\n                const prevBtn = navBtns[0];\r\n                const nextBtn = navBtns[1];\r\n\r\n                // 1. Dynamically assign data-day attributes to cells based on grid position\r\n                // Grid has 8 columns: Time, Mon, Tue, Wed, Thu, Fri, Sat, Sun\r\n                const children = weeklyGrid.children;\r\n                for (let i = 0; i < children.length; i++) {\r\n                    const colIndex = i % 8;\r\n                    if (colIndex > 0) { // Skip Time column\r\n                        children[i].setAttribute(\'data-day\', colIndex - 1);\r\n                    }\r\n                }\r\n\r\n                // 2. Navigation Logic\r\n                let activeDay = 0;\r\n                weeklyGrid.setAttribute(\'data-active-day\', activeDay);\r\n\r\n                const daysData = [\r\n                    { day: "Mon 14 Apr", status: "Today" },\r\n                    { day: "Tue 15 Apr", status: "" },\r\n                    { day: "Wed 16 Apr", status: "" },\r\n                    { day: "Thu 17 Apr", status: "Public Holiday" },\r\n                    { day: "Fri 18 Apr", status: "" },\r\n                    { day: "Sat 19 Apr", status: "Weekly off" },\r\n                    { day: "Sun 20 Apr", status: "Weekly off" }\r\n                ];\r\n\r\n                const updateMobileNav = (index) => {\r\n                    weeklyGrid.setAttribute(\'data-active-day\', index);\r\n                    const data = daysData[index];\r\n                    if (mobileDateLabel) {\r\n                        mobileDateLabel.innerHTML = `\r\n                            <strong>${data.day}</strong>
1\r\n                            ${data.status ? `<span class="${data.status === \'Today\' ? \'ux4g-text-success-600\' : \'ux4g-text-neutral-secondary\'}">${data.status}</span>` : \'\'}\r\n                        `;\r\n                    }\r\n                };\r\n\r\n                if (prevBtn) {\r\n                    prevBtn.addEventListener(\'click\', () => {\r\n                        activeDay = (activeDay > 0) ? activeDay - 1 : 6;\r\n                        updateMobileNav(activeDay);\r\n                    });\r\n                }\r\n\r\n                if (nextBtn) {\r\n                    nextBtn.addEventListener(\'click\', () => {\r\n                        activeDay = (activeDay < 6) ? activeDay + 1 : 0;\r\n                        updateMobileNav(activeDay);\r\n                    });\r\n                }\r\n            }\r\n        }\r\n    });\r\n});\r\n\r\n\r\n\r\n/********************************* Result list JS ***********************************/\r\n\r\n// Accordion Toggle\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  if (window.ux4gResultListAccordionInitialized) return;\r\n  window.ux4gResultListAccordionInitialized = true;\r\n  \r\n  document.addEventListener(\'click\', (e) => {\r\n    const toggle = e.target.closest(\'.ux4g-result-list-accordion-toggle\');\r\n    if (!toggle) return;\r\n\r\n    let content = null;\r\n    \r\n    // 1. Support ID-based target via aria-controls or data-ux-target\r\n    const targetId = toggle.getAttribute(\'aria-controls\') || toggle.getAttribute(\'data-ux-target\');\r\n    if (targetId) {\r\n      const selector = targetId.startsWith(\'#\') ? targetId : `#${targetId}`;\r\n      content = document.querySelector(selector);\r\n    }\r\n    \r\n    // 2. Fallback to structural targeting\r\n    if (!content) {\r\n      const card = toggle.closest(\'.ux4g-result-list\');\r\n      if (card) {\r\n        content = card.querySelector(\'.ux4g-result-list-content\');\r\n      }\r\n    }\r\n\r\n    if (!content) return;\r\n\r\n    const isExpanded = toggle.getAttribute(\'aria-expanded\') === \'true\';\r\n\r\n    if (isExpanded) {\r\n      toggle.setAttribute(\'aria-expanded\', \'false\');\r\n      toggle.innerText = \'expand_more\';\r\n      content.style.display = \'none\';\r\n    } else {\r\n      toggle.setAttribute(\'aria-expanded\', \'true\');\r\n      toggle.innerText = \'expand_less\';\r\n      content.style.display = \'\';\r\n    }\r\n  });\r\n});\r\n\r\n\r\n\r\n/********************************* Mega menu category list JS ***********************************/\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const categoryItems = document.querySelectorAll(\'.ux4g-mega-menu-category-item\');\r\n  const contentBlocks = document.querySelectorAll(\'.ux4g-mega-menu-content\');\r\n\r\n  if (!categoryItems.length || !contentBlocks.length) return;\r\n\r\n  categoryItems.forEach((item, index) => {\r\n    item.addEventListener(\'click\', (e) => {\r\n      e.preventDefault();\r\n\r\n      // Remove active class from all categories\r\n      categoryItems.forEach(cat => cat.classList.remove(\'ux4g-mega-menu-category-item--active\'));\r\n      // Add active class to clicked category\r\n      item.classList.add(\'ux4g-mega-menu-category-item--active\');\r\n\r\n      // Hide all content blocks\r\n      contentBlocks.forEach(block => block.classList.remove(\'ux4g-mega-menu-content--active\'));\r\n\r\n      // Show the corresponding content block by ID matching category-1, category-2, etc.\r\n      const targetId = `category-${index + 1}`;\r\n      const targetBlock = document.getElementById(targetId);\r\n\r\n      if (targetBlock) {\r\n        targetBlock.classList.add(\'ux4g-mega-menu-content--active\');\r\n      }\r\n    });\r\n  });\r\n});\r\n\r\n/* ========================================================= checkbox js ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n\r\n  // 1. Standalone indeterminate checkboxes — add data-ux4g-indeterminate attribute to set on init\r\n  document.querySelectorAll(\'.ux4g-checkbox-input[data-ux4g-indeterminate]\').forEach(input => {\r\n    input.indeterminate = true;\r\n  });\r\n\r\n  // 2. Parent-child checkbox groups — wrap the group in data-ux4g-parent-child.\r\n  //    Mark the select-all input with data-ux4g-select-all.\r\n  //    Mark each child input with data-ux4g-child.\r\n  document.querySelectorAll(\'[data-ux4g-parent-child]\').forEach(container => {\r\n    const parentInput = container.querySelector(\'.ux4g-checkbox-input[data-ux4g-select-all]\');\r\n    const childInputs = Array.from(container.querySelectorAll(\'.ux4g-checkbox-input[data-ux4g-child]\'));\r\n\r\n    if (!parentInput || !childInputs.length) return;\r\n\r\n    function updateParent() {\r\n      const checkedCount = childInputs.filter(cb => cb.checked).length;\r\n      if (checkedCount === 0) {\r\n        parentInput.checked = false;\r\n        parentInput.indeterminate = false;\r\n      } else if (checkedCount === childInputs.length) {\r\n        parentInput.checked = true;\r\n        parentInput.indeterminate = false;\r\n      } else {\r\n        parentInput.checked = false;\r\n        parentInput.indeterminate = true;\r\n      }\r\n    }\r\n\r\n    // Use click (not change) so we can read the children\'s state BEFORE any changes,\r\n    // giving consistent "select all / unselect all" behaviour regardless of browser\r\n    // handling of indeterminate → click → checked transitions.\r\n    parentInput.addEventListener(\'click\', function () {\r\n      const checkedCount = childInputs.filter(cb => cb.checked).length;\r\n      const checkAll = checkedCount < childInputs.length;\r\n      parentInput.checked = checkAll;\r\n      parentInput.indeterminate = false;
1\r\n      childInputs.forEach(cb => { cb.checked = checkAll; });\r\n    });\r\n\r\n    childInputs.forEach(cb => cb.addEventListener(\'change\', updateParent));\r\n    updateParent();\r\n  });\r\n});\r\n\r\n\r\n\r\n\r\n/* ========================================================= \r\n   Aadhaar & PAN Validation Logic\r\n========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || [];\r\nwindow.ux4gCustomInitList.push(() => {\r\n    \r\n    // Helper function to toggle error state\r\n    const toggleErrorState = (input, isError) => {\r\n        const container = input.closest(\'.ux4g-input-container\');\r\n        if (!container) return;\r\n        \r\n        let helper = container.querySelector(\'.ux4g-input-helper\');\r\n\r\n        if (isError) {\r\n            container.classList.add(\'ux4g-input-error\');\r\n            input.setAttribute(\'aria-invalid\', \'true\');\r\n            if (helper) helper.style.display = \'flex\';\r\n        } else {\r\n            container.classList.remove(\'ux4g-input-error\');\r\n            input.removeAttribute(\'aria-invalid\');\r\n            if (helper) helper.style.display = \'none\';\r\n        }\r\n    };\r\n\r\n    // ---------------------------------------------------------\r\n    // Aadhaar Card Input Handling\r\n    // ---------------------------------------------------------\r\n    const handleAadhaar = (e) => {\r\n        const input = e.target;\r\n        if (!input.matches(\'input[id="aadhaarInput"], input[name="aadhaar"]\')) return;\r\n\r\n        let val = input.value.replace(/[^\\d]/g, \'\').substring(0, 12);\r\n        let formatted = \'\';\r\n        for (let i = 0; i < val.length; i++) {\r\n            if (i > 0 && i % 4 === 0) formatted += \' \';\r\n            formatted += val[i];\r\n        }\r\n        if (input.value !== formatted) {\r\n            input.value = formatted;\r\n        }\r\n\r\n        // Validate using HTML5 pattern attribute\r\n        if (input.value.length === 0) {\r\n            toggleErrorState(input, false);\r\n        } else if (!input.checkValidity()) {\r\n            toggleErrorState(input, true);\r\n        } else {\r\n            toggleErrorState(input, false);\r\n        }\r\n    };\r\n\r\n    // ---------------------------------------------------------\r\n    // PAN Card Input Handling\r\n    // ---------------------------------------------------------\r\n    const handlePan = (e) => {\r\n        const input = e.target;\r\n        if (!input.matches(\'input[id="panInput"], input[name="pan"]\')) return;\r\n\r\n        let val = input.value.toUpperCase().replace(/[^A-Z0-9]/g, \'\').substring(0, 10);\r\n        if (input.value !== val) {\r\n            input.value = val;\r\n        }\r\n\r\n        // Validate using HTML5 pattern attribute\r\n        if (input.value.length === 0) {\r\n            toggleErrorState(input, false);\r\n        } else if (!input.checkValidity()) {\r\n            toggleErrorState(input, true);\r\n        } else {\r\n            toggleErrorState(input, false);\r\n        }\r\n    };\r\n\r\n    // Use event delegation to handle dynamically created inputs (e.g. inside Playground)\r\n    document.addEventListener(\'input\', (e) => {\r\n        if (e.target && e.target.tagName === \'INPUT\') {\r\n            handleAadhaar(e);\r\n            handlePan(e);\r\n        }\r\n    });\r\n\r\n    document.addEventListener(\'focusout\', (e) => {\r\n        if (e.target && e.target.tagName === \'INPUT\') {\r\n            handleAadhaar(e);\r\n            handlePan(e);\r\n        }\r\n    });\r\n});\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n    const wrappers = document.querySelectorAll(\'.ux4g-consent-capture-wrapper\');\r\n    \r\n    wrappers.forEach(wrapper => {\r\n        const scrollBox = wrapper.querySelector(\'.ux4g-declaration-content\');\r\n        const hint = wrapper.querySelector(\'.ux4g-declaration-scroll-hint\');\r\n        const checkbox = wrapper.querySelector(\'.ux4g-checkbox-input\');\r\n        const nameInputGroup = wrapper.querySelector(\'.ux4g-input-container\');\r\n        const nameInput = wrapper.querySelector(\'.ux4g-input-input\');\r\n        const submitBtn = wrapper.querySelector(\'.ux4g-consent-decl-btn-wrap .ux4g-btn-primary\');\r\n\r\n        if (!checkbox || !scrollBox || !submitBtn) return;\r\n\r\n        let hasScrolledToBottom = false;\r\n\r\n        function validateForm() {\r\n            const isNameValid = nameInput ? nameInput.value.trim().length > 0 : true;\r\n            const isChecked = checkbox.checked;\r\n\r\n            if (hasScrolledToBottom && isNameValid && isChecked) {\r\n                submitBtn.disabled = false;\r\n            } else {\r\n                submitBtn.disabled = true;\r\n            }\r\n        }\r\n\r\n        scrollBox.addEventListener(\'scroll\', function() {\r\n            if (Math.abs(this.scrollHeight - this.clientHeight - this.scrollTop) <= 10) {\r\n                if (hint) {\r\n                    hint.style.opacity = \'0\';\r\n                    hint.style.pointerEvents = \'none\';\r\n                }\r\n                hasScrolledToBottom = true;\r\n                validateForm();\r\n            }\r\n        });\r\n\r\n        checkbox.addEventListener(\'change\', function() {\r\n            if (nameInputGroup) {\r\n                if (this.checked) {\r\n                    nameInputGroup.classList.remove(\'ux4g-d-none\');\r\n                } else {\r\n                    nameInputGroup.classList.add(\'ux4g-d-none\');\r\n                    if (nameInput) nameInput.value = \'\';\r\n                }\r\n            }\r\n            validateForm();\r\n        });\r\n        \r\n        if (nameInput) {\r\n            nameInput.addEventListener(\'input\', validateForm);\r\n        }\r\n        \r\n        // Initial validation\r\n        validateForm();\r\n    });\r\n});\r\n\r\n/* ========================================================= alert js ========================================================= */\r\n\r\n// Single delegated click handler for alert close (Framework Agnostic)\r\ndocument.addEventListener(\'click\', (e) => {\r\n  const closeBtn = e.target.closest(\'.ux4g-alert-close\');\r\n  if (closeBtn) {\r\n    const alert = closeBtn.closest(\'.ux4g-alert, .ux4g-context-alert\');\r\n    if (alert) {\r\n      alert.style.display = \'none\';\r\n    }\r\n  }\r\n});\r\n\r\n// Auto-dismiss logic using MutationObserver (Works perfectly with React/Angular)\r\nfunction initAutoDismissAlerts() {\r\n  const setAutoDismiss = (alert) =>
1 {\r\n    if (alert.dataset.ux4gDismissTimeout) return; // already set\r\n    const time = parseInt(alert.getAttribute(\'data-auto-dismiss\'), 10);\r\n    if (!isNaN(time) && time > 0) {\r\n      const timerId = setTimeout(() => {\r\n        alert.style.display = \'none\';\r\n      }, time);\r\n      alert.dataset.ux4gDismissTimeout = timerId;\r\n    }\r\n  };\r\n\r\n  // 1. Check existing alerts on page\r\n  document.querySelectorAll(\'.ux4g-alert[data-auto-dismiss], .ux4g-context-alert[data-auto-dismiss]\').forEach(setAutoDismiss);\r\n\r\n  // 2. Watch for dynamically added alerts (React, Angular, etc.)\r\n  const observer = new MutationObserver((mutations) => {\r\n    mutations.forEach(mutation => {\r\n      mutation.addedNodes.forEach(node => {\r\n        if (node.nodeType === 1) { // Element node\r\n          if (node.classList && (node.classList.contains(\'ux4g-alert\') || node.classList.contains(\'ux4g-context-alert\')) && node.hasAttribute(\'data-auto-dismiss\')) {\r\n            setAutoDismiss(node);\r\n          }\r\n          // Also check children if a container was added\r\n          const innerAlerts = node.querySelectorAll ? node.querySelectorAll(\'.ux4g-alert[data-auto-dismiss], .ux4g-context-alert[data-auto-dismiss]\') : [];\r\n          innerAlerts.forEach(setAutoDismiss);\r\n        }\r\n      });\r\n    });\r\n  });\r\n\r\n  observer.observe(document.body, { childList: true, subtree: true });\r\n}\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || [];\r\nwindow.ux4gCustomInitList.push(initAutoDismissAlerts);\r\n\r\n\r\n/* ========================================================= reminder alert close js ========================================================= */\r\n// Delegated event listener for reminder alert close buttons so it works with dynamic frameworks (React, Angular, Next.js)\r\ndocument.addEventListener(\'click\', (e) => {\r\n  const closeBtn = e.target.closest(\'.ux4g-reminder-alert .ux4g-alert-close\');\r\n  if (closeBtn) {\r\n    const alertBox = closeBtn.closest(\'.ux4g-reminder-alert\');\r\n    if (alertBox) {\r\n      alertBox.style.display = \'none\';\r\n    }\r\n        if (isError) {\r\n            container.classList.add(\'ux4g-input-error\');\r\n            input.setAttribute(\'aria-invalid\', \'true\');\r\n            if (helper) helper.style.display = \'flex\';\r\n        } else {\r\n            container.classList.remove(\'ux4g-input-error\');\r\n            input.removeAttribute(\'aria-invalid\');\r\n            if (helper) helper.style.display = \'none\';\r\n        }\r\n    };\r\n\r\n    // ---------------------------------------------------------\r\n    // Aadhaar Card Input Handling\r\n    // ---------------------------------------------------------\r\n    const handleAadhaar = (e) => {\r\n        const input = e.target;\r\n        if (!input.matches(\'input[id="aadhaarInput"], input[name="aadhaar"]\')) return;\r\n\r\n        let val = input.value.replace(/[^\\d]/g, \'\').substring(0, 12);\r\n        let formatted = \'\';\r\n        for (let i = 0; i < val.length; i++) {\r\n            if (i > 0 && i % 4 === 0) formatted += \' \';\r\n            formatted += val[i];\r\n        }\r\n        if (input.value !== formatted) {\r\n            input.value = formatted;\r\n        }\r\n\r\n        // Validate using HTML5 pattern attribute\r\n        if (input.value.length === 0) {\r\n            toggleErrorState(input, false);\r\n        } else if (!input.checkValidity()) {\r\n            toggleErrorState(input, true);\r\n        } else {\r\n            toggleErrorState(input, false);\r\n        }\r\n    };\r\n\r\n    // ---------------------------------------------------------\r\n    // PAN Card Input Handling\r\n    // ---------------------------------------------------------\r\n    const handlePan = (e) => {\r\n        const input = e.target;\r\n        if (!input.matches(\'input[id="panInput"], input[name="pan"]\')) return;\r\n\r\n        let val = input.value.toUpperCase().replace(/[^A-Z0-9]/g, \'\').substring(0, 10);\r\n        if (input.value !== val) {\r\n            input.value = val;\r\n        }\r\n\r\n        // Validate using HTML5 pattern attribute\r\n        if (input.value.length === 0) {\r\n            toggleErrorState(input, false);\r\n        } else if (!input.checkValidity()) {\r\n            toggleErrorState(input, true);\r\n        } else {\r\n            toggleErrorState(input, false);\r\n        }\r\n    };\r\n\r\n    // Use event delegation to handle dynamically created inputs (e.g. inside Playground)\r\n    document.addEventListener(\'input\', (e) => {\r\n        if (e.target && e.target.tagName === \'INPUT\') {\r\n            handleAadhaar(e);\r\n            handlePan(e);\r\n        }\r\n    });
1\r\n\r\n    document.addEventListener(\'focusout\', (e) => {\r\n        if (e.target && e.target.tagName === \'INPUT\') {\r\n            handleAadhaar(e);\r\n            handlePan(e);\r\n        }\r\n    });\r\n});\r\n\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n    const wrappers = document.querySelectorAll(\'.ux4g-consent-capture-wrapper\');\r\n    \r\n    wrappers.forEach(wrapper => {\r\n        const scrollBox = wrapper.querySelector(\'.ux4g-declaration-content\');\r\n        const hint = wrapper.querySelector(\'.ux4g-declaration-scroll-hint\');\r\n        const checkbox = wrapper.querySelector(\'.ux4g-checkbox-input\');\r\n        const nameInputGroup = wrapper.querySelector(\'.ux4g-input-container\');\r\n        const nameInput = wrapper.querySelector(\'.ux4g-input-input\');\r\n        const submitBtn = wrapper.querySelector(\'.ux4g-consent-decl-btn-wrap .ux4g-btn-primary\');\r\n\r\n        if (!checkbox || !scrollBox || !submitBtn) return;\r\n\r\n        let hasScrolledToBottom = false;\r\n\r\n        function validateForm() {\r\n            const isNameValid = nameInput ? nameInput.value.trim().length > 0 : true;\r\n            const isChecked = checkbox.checked;\r\n\r\n            if (hasScrolledToBottom && isNameValid && isChecked) {\r\n                submitBtn.disabled = false;\r\n            } else {\r\n                submitBtn.disabled = true;\r\n            }\r\n        }\r\n\r\n        scrollBox.addEventListener(\'scroll\', function() {\r\n            if (Math.abs(this.scrollHeight - this.clientHeight - this.scrollTop) <= 10) {\r\n                if (hint) {\r\n                    hint.style.opacity = \'0\';\r\n                    hint.style.pointerEvents = \'none\';\r\n                }\r\n                hasScrolledToBottom = true;\r\n                validateForm();\r\n            }\r\n        });\r\n\r\n        checkbox.addEventListener(\'change\', function() {\r\n            if (nameInputGroup) {\r\n                if (this.checked) {\r\n                    nameInputGroup.classList.remove(\'ux4g-d-none\');\r\n                } else {\r\n                    nameInputGroup.classList.add(\'ux4g-d-none\');\r\n                    if (nameInput) nameInput.value = \'\';\r\n                }\r\n            }\r\n            validateForm();\r\n        });\r\n        \r\n        if (nameInput) {\r\n            nameInput.addEventListener(\'input\', validateForm);\r\n        }\r\n        \r\n        // Initial validation\r\n        validateForm();\r\n    });\r\n});\r\n\r\n\r\n\r\n\r\n/* ========================================================= reminder alert close js ========================================================= */\r\n// Delegated event listener for reminder alert close buttons so it works with dynamic frameworks (React, Angular, Next.js)\r\ndocument.addEventListener(\'click\', (e) => {\r\n  const closeBtn = e.target.closest(\'.ux4g-reminder-alert .ux4g-alert-close\');\r\n  if (closeBtn) {\r\n    const alertBox = closeBtn.closest(\'.ux4g-reminder-alert\');\r\n    if (alertBox) {\r\n      alertBox.style.display = \'none\';\r\n    }\r\n  }\r\n});\r\n\r\n\r\n/* ========================================================= list switch JS appended ========================================================= */\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  document.addEventListener(\'click\', (e) => {\r\n    const switchContent = e.target.closest(\'.ux4g-switch-content\');\r\n    if (switchContent) {\r\n      e.preventDefault();\r\n      e.stopPropagation();\r\n      return;\r\n    }\r\n\r\n    const row = e.target.closest(\'.ux4g-list-item-row.ux4g-toggles, span.ux4g-list-item-row, .ux4g-list-item-row-fixed\');\r\n    if (row && e.target.tagName !== \'INPUT\' && !e.target.closest(\'.ux4g-switch, .ux4g-checkbox, .ux4g-radio\')) {\r\n      e.stopPropagation();\r\n    }\r\n  }, true);\r\n});\r\n/* ========================================================= toggle disable JS ========================================================= */\r\n// Generic script to enable/disable target elements based on checkbox state. Works with dynamic HTML, React, Angular, etc.\r\ndocument.addEventListener(\'change\', function(e) {\r\n  if (e.target && e.target.hasAttribute(\'data-ux4g-toggle-disable\')) {\r\n    const targetSelector = e.target.getAttribute(\'data-ux4g-toggle-disable\');
1\r\n    if (targetSelector) {\r\n      const targetEls = document.querySelectorAll(targetSelector);\r\n      targetEls.forEach(el => {\r\n        el.disabled = !e.target.checked;\r\n      });\r\n    }\r\n  }\r\n});\r\n/* ========================================================= filter chip JS ========================================================= */\r\n// Generic script to toggle filter chips (active mode)\r\ndocument.addEventListener(\'click\', (e) => {\r\n  const filterChip = e.target.closest(\'.ux4g-filter-chip-md, .ux4g-filter-chip-sm\');\r\n  if (filterChip) {\r\n    if (filterChip.hasAttribute(\'disabled\') || filterChip.classList.contains(\'ux4g-disabled\')) return;\r\n\r\n    filterChip.classList.toggle(\'active\');\r\n  }\r\n});\r\n\r\n// Execute all registered initialization functions (uses ux4g.js\'s safe init to prevent double-binding)\r\n// Initialize selection state in custom list dropdowns\r\nconst initCustomListDropdowns = () => {\r\n  document.querySelectorAll(\'.ux4g-custom-list-dropdown\').forEach(dropdown => {\r\n    const btn = dropdown.querySelector(\'.ux4g-custom-dropdown-btn\');\r\n    const items = dropdown.querySelectorAll(\'.ux4g-custom-dropdown-item\');\r\n    if (!btn || !items.length) return;\r\n\r\n    const currentValue = btn.getAttribute(\'data-value\');\r\n    const span = btn.querySelector(\'span:first-child\');\r\n    const currentText = span ? span.textContent.trim() : \'\';\r\n\r\n    items.forEach(item => {\r\n      const itemVal = item.getAttribute(\'data-value\');\r\n      const textEl = item.querySelector(\'.ux4g-custom-dropdown-text\');\r\n      const itemText = textEl ? textEl.textContent.trim() : item.textContent.trim();\r\n      \r\n      const isSelected = (currentValue && itemVal === currentValue) || (!currentValue && currentText && itemText === currentText);\r\n      if (isSelected) {\r\n        item.classList.add(\'is-selected\', \'active\');\r\n        item.setAttribute(\'aria-selected\', \'true\');\r\n      } else {\r\n        item.classList.remove(\'is-selected\', \'active\');\r\n        item.setAttribute(\'aria-selected\', \'false\');\r\n      }\r\n    });\r\n  });\r\n};\r\n\r\n// Execute all registered initialization functions\r\nconst ux4gInitAll = () => {\r\n  if (window.ux4gCustomInit) {\r\n    window.ux4gCustomInit();\r\n  } else if (window.ux4gCustomInitList) {\r\n    window.ux4gCustomInitList.forEach(fn => {\r\n      if (typeof fn === \'function\') fn();\r\n    });\r\n  }\r\n};\r\n\r\nconst ux4gCustomInitAllCombined = () => {\r\n  ux4gInitAll();\r\n  initCustomListDropdowns();\r\n};\r\n\r\nif (document.readyState === \'loading\') {\r\n  document.addEventListener(\'DOMContentLoaded\', ux4gCustomInitAllCombined);\r\n} else {\r\n  ux4gCustomInitAllCombined();\r\n}\r\n\r\n\r\n/* ========================================================= custom list dropdown JS ========================================================= */\r\ndocument.addEventListener(\'click\', (e) => {\r\n  // 1. Handle toggle button click\r\n  const btn = e.target.closest(\'.ux4g-custom-dropdown-btn\');\r\n  if (btn) {\r\n    e.stopPropagation();\r\n    const dropdown = btn.closest(\'.ux4g-custom-list-dropdown\');\r\n    if (dropdown) {\r\n      const menu = dropdown.querySelector(\'.ux4g-custom-dropdown-menu\');\r\n      if (menu) {\r\n        const isExpanded = btn.getAttribute(\'aria-expanded\') === \'true\';\r\n        // Close other custom dropdowns\r\n        document.querySelectorAll(\'.ux4g-custom-list-dropdown\').forEach(d => {\r\n          if (d !== dropdown) {\r\n            const otherBtn = d.querySelector(\'.ux4g-custom-dropdown-btn\');\r\n            const otherMenu = d.querySelector(\'.ux4g-custom-dropdown-menu\');\r\n            if (otherBtn) otherBtn.setAttribute(\'aria-expanded\', \'false\');\r\n            if (otherMenu) otherMenu.style.display = \'none\';\r\n          }\r\n        });\r\n        \r\n        btn.setAttribute(\'aria-expanded\', String(!isExpanded));\r\n        menu.style.display = isExpanded ? \'none\' : \'block\';\r\n      }\r\n    }\r\n    return;\r\n  }\r\n\r\n  // 2. Handle item selection\r\n  const item = e.target.closest(\'.ux4g-custom-list-dropdown .ux4g-custom-dropdown-item\');\r\n  if (item) {\r\n    e.stopPropagation();\r\n    const dropdown = item.closest(\'.ux4g-custom-list-dropdown\');\r\n    if (dropdown) {\r\n      const btn = dropdown.querySelector(\'.ux4g-custom-dropdown-btn\');\r\n      const menu = dropdown.querySelector(\'.ux4g-custom-dropdown-menu\');\r\n      \r\n      // Toggle selected class and aria-selected attribute\r\n      const items = dropdown.querySelectorAll(\'.ux4g-custom-dropdown-item\');
1\r\n      items.forEach(el => {\r\n        if (el === item) {\r\n          el.classList.add(\'is-selected\', \'active\');\r\n          el.setAttribute(\'aria-selected\', \'true\');\r\n        } else {\r\n          el.classList.remove(\'is-selected\', \'active\');\r\n          el.setAttribute(\'aria-selected\', \'false\');\r\n        }\r\n      });\r\n\r\n      const span = btn ? btn.querySelector(\'span:first-child\') : null;\r\n      if (span) {\r\n        const textEl = item.querySelector(\'.ux4g-custom-dropdown-text\');\r\n        span.textContent = textEl ? textEl.textContent.trim() : item.textContent.trim();\r\n      }\r\n      if (btn) {\r\n        btn.setAttribute(\'aria-expanded\', \'false\');\r\n        btn.setAttribute(\'data-value\', item.getAttribute(\'data-value\') || \'\');\r\n      }\r\n      if (menu) menu.style.display = \'none\';\r\n    }\r\n    return;\r\n  }\r\n\r\n  // 3. Clicked outside - close all custom dropdowns\r\n  document.querySelectorAll(\'.ux4g-custom-list-dropdown\').forEach(d => {\r\n    const otherBtn = d.querySelector(\'.ux4g-custom-dropdown-btn\');\r\n    const otherMenu = d.querySelector(\'.ux4g-custom-dropdown-menu\');\r\n    if (otherBtn) otherBtn.setAttribute(\'aria-expanded\', \'false\');\r\n    if (otherMenu) otherMenu.style.display = \'none\';\r\n  });\r\n});\r\n\r\n/********************************* Mega Menu Five Category list JS ***********************************/\r\nwindow.ux4gCustomInitList = window.ux4gCustomInitList || []; window.ux4gCustomInitList.push(() => {\r\n  const categoryItems = document.querySelectorAll(\'.ux4g-mega-menu-five-category-item\');\r\n  const contentBlocks = document.querySelectorAll(\'.ux4g-mega-menu-five-content\');\r\n\r\n  if (!categoryItems.length || !contentBlocks.length) return;\r\n\r\n  categoryItems.forEach((item, index) => {\r\n    item.addEventListener(\'click\', (e) => {\r\n      e.preventDefault();\r\n\r\n      // Remove active class from all categories\r\n      categoryItems.forEach(cat => cat.classList.remove(\'ux4g-mega-menu-five-category-item--active\'));\r\n      // Add active class to clicked category\r\n      item.classList.add(\'ux4g-mega-menu-five-category-item--active\');\r\n\r\n      // Hide all content blocks\r\n      contentBlocks.forEach(block => block.classList.remove(\'ux4g-mega-menu-five-content--active\'));\r\n\r\n      // Show the corresponding content block by ID matching five-category-1, five-category-2, etc.\r\n      const targetId = `five-category-${index + 1}`;\r\n      const targetBlock = document.getElementById(targetId);\r\n\r\n      if (targetBlock) {\r\n        targetBlock.classList.add(\'ux4g-mega-menu-five-content--active\');\r\n      }\r\n    });\r\n  });\r\n});\r\n',document.head.appendChild(t)}(),"undefined"!=typeof window&&"undefined"!=typeof MutationObserver){let n=null,e=new MutationObserver(e=>{let t=!1;for(let n of e)if(n.addedNodes.length>0){t=!0;break}t&&(n&&clearTimeout(n),n=setTimeout(()=>{window.ux4g?.init&&window.ux4g.init(document)},50))}),t=()=>{document.body?e.observe(document.body,{childList:!0,subtree:!0}):setTimeout(t,10)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.