UNPKG

highlight-it

Version:

A lightweight syntax highlighting library with themes, line numbers, and copy functionality

3,094 lines 124 kB
/*!
 * HighlightIt v0.2.7
 * https://github.com/TN3W/highlight-it
 * (c) 2025 TN3W
 * Released under the Apache 2.0 License
 */
(function (global) {
  const STYLES_CSS =
    ':root{--hl-background:#1e1e1e;--hl-border:#2d2d2d;--hl-header-bg:#2d2d2d;--hl-text:#d4d4d4;--hl-badge-bg:#3d3d3d;--hl-hover-bg:#3d3d3d;--hl-copied-color:#4ec9b0;--hl-keyword:#569cd6;--hl-string:#ce9178;--hl-comment:#6a9955;--hl-function:#dcdcaa;--hl-number:#b5cea8;--hl-class:#4ec9b0;--hl-params:#9cdcfe;--hl-built-in:#4ec9b0;--hl-tag:#569cd6;--hl-attr:#9cdcfe;--hl-variable:#9cdcfe;--hl-property:#9cdcfe;--hl-operator:#d4d4d4;--hl-punctuation:#d4d4d4;--hl-regexp:#d16969;--hl-doctype:grey;--hl-meta:grey;--hl-name:#569cd6;--hl-selector:#d7ba7d;--hl-attr-value:#ce9178;--hl-constant:#4fc1ff;--hl-symbol:#b5cea8;--hl-important:#569cd6;--hl-deleted:#ce9178;--hl-inserted:#b5cea8;--hl-type:#4ec9b0;--hl-literal:#569cd6;--hl-link:#9cdcfe;--hl-title-function:#dcdcaa;--hl-title-class:#4ec9b0;--hl-title-namespace:#4ec9b0;--hl-text-rgb:212,212,212}.highlightit-theme-light{--hl-background:#fff;--hl-border:#ccc;--hl-header-bg:#e0e0e0;--hl-text:#333;--hl-badge-bg:silver;--hl-hover-bg:#d0d0d0;--hl-copied-color:#0b8043;--hl-keyword:#00f;--hl-string:#a31515;--hl-comment:green;--hl-function:#795e26;--hl-number:#098658;--hl-class:#267f99;--hl-params:#001080;--hl-built-in:#0070c1;--hl-tag:maroon;--hl-attr:red;--hl-variable:#001080;--hl-property:#001080;--hl-operator:#000;--hl-punctuation:#000;--hl-regexp:#811f3f;--hl-doctype:grey;--hl-meta:grey;--hl-name:maroon;--hl-selector:maroon;--hl-attr-value:#00f;--hl-constant:#0070c1;--hl-symbol:#000;--hl-important:#00f;--hl-deleted:#a31515;--hl-inserted:#098658;--hl-type:#267f99;--hl-literal:#00f;--hl-link:#00f;--hl-title-function:#795e26;--hl-title-class:#267f99;--hl-title-namespace:#267f99;--hl-text-rgb:51,51,51}@media (prefers-color-scheme:light){:root.highlightit-theme-auto{--hl-background:#fff;--hl-border:#ccc;--hl-header-bg:#e0e0e0;--hl-text:#333;--hl-badge-bg:silver;--hl-hover-bg:#d0d0d0;--hl-copied-color:#0b8043;--hl-keyword:#00f;--hl-string:#a31515;--hl-comment:green;--hl-function:#795e26;--hl-number:#098658;--hl-class:#267f99;--hl-params:#001080;--hl-built-in:#0070c1;--hl-tag:maroon;--hl-attr:red;--hl-variable:#001080;--hl-property:#001080;--hl-operator:#000;--hl-punctuation:#000;--hl-regexp:#811f3f;--hl-doctype:grey;--hl-meta:grey;--hl-name:maroon;--hl-selector:maroon;--hl-attr-value:#00f;--hl-constant:#0070c1;--hl-symbol:#000;--hl-important:#00f;--hl-deleted:#a31515;--hl-inserted:#098658;--hl-type:#267f99;--hl-literal:#00f;--hl-link:#00f;--hl-title-function:#795e26;--hl-title-class:#267f99;--hl-title-namespace:#267f99;--hl-text-rgb:51,51,51}}.highlightit-container{border:1px solid var(--hl-border);border-radius:6px;overflow:hidden;position:relative}.highlightit-container code[data-theme=light],.highlightit-container pre[data-theme=light],.highlightit-container[data-theme=light]{--hl-background:#fff!important;--hl-border:#ccc!important;--hl-header-bg:#e0e0e0!important;--hl-text:#333!important;--hl-badge-bg:silver!important;--hl-hover-bg:#d0d0d0!important;--hl-copied-color:#0b8043!important;--hl-keyword:#00f!important;--hl-string:#a31515!important;--hl-comment:green!important;--hl-function:#795e26!important;--hl-number:#098658!important;--hl-class:#267f99!important;--hl-params:#001080!important;--hl-built-in:#0070c1!important;--hl-tag:maroon!important;--hl-attr:red!important;--hl-variable:#001080!important;--hl-property:#001080!important;--hl-operator:#000!important;--hl-punctuation:#000!important;--hl-regexp:#811f3f!important;--hl-doctype:grey!important;--hl-meta:grey!important;--hl-name:maroon!important;--hl-selector:maroon!important;--hl-attr-value:#00f!important;--hl-constant:#0070c1!important;--hl-symbol:#000!important;--hl-important:#00f!important;--hl-deleted:#a31515!important;--hl-inserted:#098658!important;--hl-type:#267f99!important;--hl-literal:#00f!important;--hl-link:#00f!important;--hl-title-function:#795e26!important;--hl-title-class:#267f99!important;--hl-title-namespace:#267f99!important}.highlightit-container code[data-theme=dark],.highlightit-container pre[data-theme=dark],.highlightit-container[data-theme=dark]{--hl-background:#1e1e1e!important;--hl-border:#2d2d2d!important;--hl-header-bg:#2d2d2d!important;--hl-text:#d4d4d4!important;--hl-badge-bg:#3d3d3d!important;--hl-hover-bg:#3d3d3d!important;--hl-copied-color:#4ec9b0!important;--hl-keyword:#569cd6!important;--hl-string:#ce9178!important;--hl-comment:#6a9955!important;--hl-function:#dcdcaa!important;--hl-number:#b5cea8!important;--hl-class:#4ec9b0!important;--hl-params:#9cdcfe!important;--hl-built-in:#4ec9b0!important;--hl-tag:#569cd6!important;--hl-attr:#9cdcfe!important;--hl-variable:#9cdcfe!important;--hl-property:#9cdcfe!important;--hl-operator:#d4d4d4!important;--hl-punctuation:#d4d4d4!important;--hl-regexp:#d16969!important;--hl-doctype:grey!important;--hl-meta:grey!important;--hl-name:#569cd6!important;--hl-selector:#d7ba7d!important;--hl-attr-value:#ce9178!important;--hl-constant:#4fc1ff!important;--hl-symbol:#b5cea8!important;--hl-important:#569cd6!important;--hl-deleted:#ce9178!important;--hl-inserted:#b5cea8!important;--hl-type:#4ec9b0!important;--hl-literal:#569cd6!important;--hl-link:#9cdcfe!important;--hl-title-function:#dcdcaa!important;--hl-title-class:#4ec9b0!important;--hl-title-namespace:#4ec9b0!important}.highlightit-header{align-items:center;background:var(--hl-header-bg);color:var(--hl-text);display:flex;font-size:14px;font-weight:600;justify-content:space-between;padding:8px 15px}.highlightit-language{background:var(--hl-badge-bg);border-radius:4px;color:var(--hl-text);font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:12px;padding:2px 8px}.highlightit-button{align-items:center;background:transparent;border:none;border-radius:4px;color:var(--hl-text);cursor:pointer;display:flex;height:28px;justify-content:center;padding:4px 6px;transition:all .2s ease}.highlightit-button:hover{background:var(--hl-hover-bg)}.highlightit-button.copied{color:var(--hl-copied-color)}.highlightit-check-icon,.highlightit-copy-icon,.highlightit-download-icon,.highlightit-share-icon{height:16px;vertical-align:middle;width:16px}.highlightit-original,[data-with-reload][style*="display: none"]{border:0!important;height:0!important;margin:0!important;opacity:0!important;overflow:hidden!important;padding:0!important;pointer-events:none!important;position:absolute!important;visibility:hidden!important;width:0!important;z-index:-9999!important;clip:rect(1px,1px,1px,1px)!important;clip-path:inset(50%)!important}.highlightit-floating-buttons{display:flex;gap:4px;opacity:0;position:absolute;right:8px;top:8px;transition:opacity .2s ease;z-index:10}.highlightit-button.highlightit-floating{background-color:rgba(45,45,45,.8);transition:background-color .2s ease,transform .2s ease}.highlightit-container[data-theme=light] .highlightit-button.highlightit-floating,.highlightit-theme-light .highlightit-button.highlightit-floating,:root.highlightit-theme-auto.system-light-theme .highlightit-button.highlightit-floating{background-color:hsla(0,0%,78%,.8)}.highlightit-no-header:hover .highlightit-floating-buttons,:root.highlightit-touch-device .highlightit-floating-buttons{opacity:1}.highlightit-button.highlightit-floating:hover{background-color:rgba(65,65,65,.9);transform:scale(1.05)}.highlightit-container[data-theme=light] .highlightit-button.highlightit-floating:hover,.highlightit-theme-light .highlightit-button.highlightit-floating:hover,:root.highlightit-theme-auto.system-light-theme .highlightit-button.highlightit-floating:hover{background-color:hsla(0,0%,67%,.9);transform:scale(1.05)}.highlightit-container pre{background-color:var(--hl-background)!important;border-radius:0 0 6px 6px;margin:0;overflow:auto;padding:16px}.highlightit-container pre::-webkit-scrollbar{height:10px;width:10px}.highlightit-theme-dark .highlightit-container pre::-webkit-scrollbar-track,:root:not(.highlightit-theme-light) .highlightit-container pre::-webkit-scrollbar-track{background:#2d2d2d;border-radius:4px}.highlightit-theme-dark .highlightit-container pre::-webkit-scrollbar-thumb,:root:not(.highlightit-theme-light) .highlightit-container pre::-webkit-scrollbar-thumb{background:#3d3d3d;border-radius:4px}.highlightit-theme-dark .highlightit-container pre::-webkit-scrollbar-thumb:hover,:root:not(.highlightit-theme-light) .highlightit-container pre::-webkit-scrollbar-thumb:hover{background:#4d4d4d}:root.highlightit-theme-light .highlightit-container pre::-webkit-scrollbar-track{background:#e0e0e0;border-radius:4px}:root.highlightit-theme-light .highlightit-container pre::-webkit-scrollbar-thumb{background:silver;border-radius:4px}.highlightit-container[data-theme=light] pre::-webkit-scrollbar-thumb:hover,:root.highlightit-theme-light .highlightit-container pre::-webkit-scrollbar-thumb:hover{background:#a0a0a0}.highlightit-theme-dark .highlightit-container pre,:root:not(.highlightit-theme-light) .highlightit-container pre{scrollbar-color:#3d3d3d #2d2d2d;scrollbar-width:thin}:root.highlightit-theme-light .highlightit-container pre{scrollbar-color:silver #e0e0e0;scrollbar-width:thin}html .highlightit-container[data-theme=dark] pre::-webkit-scrollbar-track{background:#2d2d2d!important;border-radius:4px}html .highlightit-container[data-theme=dark] pre::-webkit-scrollbar-thumb{background:#3d3d3d!important;border-radius:4px}html .highlightit-container[data-theme=dark] pre::-webkit-scrollbar-thumb:hover{background:#4d4d4d!important}html .highlightit-container[data-theme=dark] pre{scrollbar-color:#3d3d3d #2d2d2d!important;scrollbar-width:thin!important}html .highlightit-container[data-theme=light] pre::-webkit-scrollbar-track{background:#e0e0e0!important;border-radius:4px}html .highlightit-container[data-theme=light] pre::-webkit-scrollbar-thumb{background:silver!important;border-radius:4px}html .highlightit-container[data-theme=light] pre::-webkit-scrollbar-thumb:hover{background:#a0a0a0!important}html .highlightit-container[data-theme=light] pre{scrollbar-color:silver #e0e0e0!important;scrollbar-width:thin!important}.highlightit-no-header pre{border-radius:6px}.highlightit-container code{color:var(--hl-text);font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:14px;line-height:1.5;margin-left:0;padding:0!important;tab-size:4;-moz-tab-size:4;white-space:pre}.highlightit-has-line-numbers code{margin-left:1em}.highlightit-anchor-highlight{animation:highlightit-anchor-pulse 2s ease-in-out}@keyframes highlightit-anchor-pulse{0%{box-shadow:0 0 0 0 rgba(var(--hl-text-rgb),.2)}70%{box-shadow:0 0 0 10px rgba(var(--hl-text-rgb),0)}to{box-shadow:0 0 0 0 rgba(var(--hl-text-rgb),0)}}.hljs-keyword{color:var(--hl-keyword)}.hljs-string{color:var(--hl-string)}.hljs-comment{color:var(--hl-comment)}.hljs-function{color:var(--hl-function)}.hljs-number{color:var(--hl-number)}.hljs-class,.hljs-title{color:var(--hl-class)}.hljs-params{color:var(--hl-params)}.hljs-built_in{color:var(--hl-built-in)}.hljs-tag{color:var(--hl-tag)}.hljs-name{color:var(--hl-name)}.hljs-attribute{color:var(--hl-attr)}.hljs-attr-value{color:var(--hl-attr-value)}.hljs-doctype{font-style:italic}.hljs-doctag,.hljs-doctype{color:var(--hl-doctype)}.hljs-variable{color:var(--hl-variable)}.hljs-property{color:var(--hl-property)}.hljs-operator{color:var(--hl-operator)}.hljs-punctuation{color:var(--hl-punctuation)}.hljs-regexp{color:var(--hl-regexp)}.hljs-meta{color:var(--hl-meta);font-style:italic}.hljs-selector{color:var(--hl-selector)}.hljs-constant{color:var(--hl-constant);font-weight:700}.hljs-symbol{color:var(--hl-symbol)}.hljs-important{color:var(--hl-important);font-weight:700}.hljs-type{color:var(--hl-type)}.hljs-literal{color:var(--hl-literal)}.hljs-link{color:var(--hl-link);text-decoration:underline}.hljs-deleted{background-color:rgba(255,0,0,.1);color:var(--hl-deleted)}.hljs-inserted{background-color:rgba(0,255,0,.1);color:var(--hl-inserted)}.hljs-title.function_{color:var(--hl-title-function)}.hljs-title.class_{color:var(--hl-title-class)}.hljs-title.namespace{color:var(--hl-title-namespace)}.hljs-selector-tag{color:var(--hl-tag)}.hljs-selector-class,.hljs-selector-id{color:var(--hl-selector)}.hljs-selector-attr{color:var(--hl-attr)}.hljs-selector-pseudo{color:var(--hl-selector);font-style:italic}.hljs-template-variable{font-style:italic}.hljs-subst,.hljs-template-variable{color:var(--hl-variable)}.hljs-section{color:var(--hl-keyword);font-weight:700}.hljs-bullet{color:var(--hl-operator)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-quote{color:var(--hl-string);font-style:italic}.hljs-code{background-color:rgba(0,0,0,.05);border-radius:3px;color:var(--hl-class);padding:.1em .2em}.hljs-keyword.operator{color:var(--hl-operator)}.hljs-attr{color:var(--hl-attr)}.hljs-variable.language_{color:var(--hl-params);font-style:italic}.hljs-built_in.shell{color:var(--hl-keyword)}.hljs-symbol.instance{color:var(--hl-symbol)}.hljs-symbol.class_{color:var(--hl-class)}.language-html .hljs-tag,.language-xml .hljs-tag{color:var(--hl-tag)}.language-css .hljs-property{color:var(--hl-property)}.language-javascript .hljs-keyword,.language-js .hljs-keyword{color:var(--hl-keyword)}.language-ts .hljs-type,.language-typescript .hljs-type{color:var(--hl-type)}.language-php .hljs-variable{color:var(--hl-variable)}.language-diff .hljs-deletion{background-color:rgba(255,0,0,.1);color:var(--hl-deleted)}.language-diff .hljs-addition{background-color:rgba(0,255,0,.1);color:var(--hl-inserted)}.highlightit-has-line-numbers{display:flex;isolation:isolate;overflow:hidden;position:relative}.highlightit-line-numbers{border-right:1px solid var(--hl-border);color:var(--hl-text);display:flex;flex-direction:column;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:14px;line-height:1.5;opacity:.7;padding-right:.5em;position:relative;text-align:right;user-select:none;-webkit-user-select:none;-moz-user-select:none}.highlightit-line-numbers:after{background-color:var(--hl-header-bg);bottom:0;content:"";left:0;opacity:.05;pointer-events:none;position:absolute;right:0;top:0;z-index:-1}.highlightit-has-line-numbers pre{border-radius:0!important;flex:1;margin:0;padding-left:.5em;position:relative}.highlightit-container[data-theme=light] .highlightit-line-numbers,.highlightit-theme-light .highlightit-line-numbers,:root.highlightit-theme-auto.system-light-theme .highlightit-line-numbers{border-right-color:#ccc!important}.highlightit-visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;border:0!important;opacity:.01!important;pointer-events:none!important;white-space:nowrap!important}.highlightit-line-number-container,.highlightit-with-lines .highlightit-line-number{align-items:center;display:flex;height:1.5em;justify-content:flex-end;margin-bottom:0;position:relative}.highlightit-with-lines .highlightit-line-number{padding-right:1em;transition:opacity .2s ease;z-index:1}.highlightit-line-number-shareable{cursor:pointer}.highlightit-container[data-with-share]	.highlightit-line-number-container:hover	.highlightit-line-number,[data-with-share] .highlightit-line-number-container:hover .highlightit-line-number{opacity:0}.highlightit-line-share{align-items:center;background:transparent;border:none;border-radius:3px;color:var(--hl-text);cursor:pointer;display:flex;height:auto;justify-content:center;margin-right:1em;opacity:0;padding:4px;position:absolute;right:0;top:50%;transform:translateY(-50%);transition:opacity .2s ease;width:auto;z-index:2}.highlightit-line-number-container:hover .highlightit-line-share{opacity:.7}.highlightit-line-share:hover{background:var(--hl-hover-bg);opacity:1!important}.highlightit-line-share.copied{background:var(--hl-hover-bg);color:var(--hl-copied-color);opacity:1}.highlightit-line-number-container:has(.highlightit-line-share.copied) .highlightit-line-number{opacity:.3}.highlightit-line-number-container.has-copied-button .highlightit-line-number{opacity:.3}.highlightit-line-share svg{height:14px;width:14px}.highlightit-line-highlight{position:relative}.highlightit-line-highlight-overlay{animation:highlightit-line-pulse 2s ease-in-out;background-color:rgba(var(--hl-text-rgb),.1);bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:1}@keyframes highlightit-line-pulse{0%{background-color:rgba(var(--hl-text-rgb),.2)}70%{background-color:rgba(var(--hl-text-rgb),.1)}to{background-color:rgba(var(--hl-text-rgb),.1)}}';

  function injectCSS(css) {
    const style = document.createElement('style');
    style.textContent = css;
    document.head.appendChild(style);
  }

  // Begin bundled module: polyfills.js
  /**
   * Polyfills and browser compatibility helpers
   */

  const polyfills = {
    supports: {
      requestAnimationFrame: typeof requestAnimationFrame === 'function',
      ResizeObserver: typeof ResizeObserver === 'function',
      MutationObserver: typeof MutationObserver === 'function',
      classList:
        'classList' in document.documentElement &&
        typeof document.documentElement.classList !== 'undefined',
      dataset:
        'dataset' in document.documentElement &&
        typeof document.documentElement.dataset !== 'undefined',
      clipboard: 'clipboard' in navigator,
      clipboardItem: typeof ClipboardItem !== 'undefined',
      touch:
        'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0,
      getBoundingClientRect: 'getBoundingClientRect' in document.documentElement,
      animation: 'Animation' in window && 'animate' in document.documentElement,
      cssHas: (function () {
        try {
          document.querySelector(':has(*)');
          return true;
        } catch {
          return false;
        }
      })(),
      download: typeof document.createElement('a').download !== 'undefined',
      blob: typeof Blob !== 'undefined',
      URL: typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function',
      TextEncoder: typeof TextEncoder !== 'undefined',
      crypto: typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined',
      BigInt: typeof BigInt !== 'undefined',
      padStart: typeof String.prototype.padStart === 'function',
    },

    initStringPadding: function () {
      if (!this.supports.padStart) {
        String.prototype.padStart = function padStart(targetLength, padString) {
          targetLength = targetLength >> 0;
          padString = String(typeof padString !== 'undefined' ? padString : ' ');
          if (this.length >= targetLength) {
            return String(this);
          } else {
            targetLength = targetLength - this.length;
            if (targetLength > padString.length) {
              padString += padString.repeat(targetLength / padString.length);
            }
            return padString.slice(0, targetLength) + String(this);
          }
        };
      }
    },

    objectEntries: function (obj) {
      if (typeof Object.entries === 'function') {
        return Object.entries(obj);
      }

      const entries = [];
      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          entries.push([key, obj[key]]);
        }
      }
      return entries;
    },

    init: function () {
      this.initStringPadding();
    },

    requestAnimationFrame: (function () {
      return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) {
          return window.setTimeout(callback, 1000 / 60);
        }
      );
    })(),

    TextEncoder: (function () {
      if (typeof TextEncoder !== 'undefined') return TextEncoder;

      return class TextEncoder {
        constructor() {
          this.encoding = 'utf-8';
        }

        encode(str) {
          if (str === null || str === undefined) return new Uint8Array();

          const string = String(str);
          let resPos = -1;

          const len = string.length;
          let byteSize = 0;

          for (let i = 0; i < len; i++) {
            const code = string.charCodeAt(i);

            if (code < 0x80) {
              byteSize += 1;
            } else if (code < 0x800) {
              byteSize += 2;
            } else if (code < 0xd800 || code >= 0xe000) {
              byteSize += 3;
            } else {
              i++;
              byteSize += 4;
            }
          }

          const buffer = new Uint8Array(byteSize);

          for (let i = 0; i < len; i++) {
            let codePoint = string.charCodeAt(i);

            if (codePoint >= 0xd800 && codePoint < 0xe000) {
              if (++i >= len) {
                break;
              }
              const second = string.charCodeAt(i);
              if (second >= 0xdc00 && second < 0xe000) {
                codePoint = 0x10000 + ((codePoint - 0xd800) << 10) + (second - 0xdc00);
              } else {
                i--;
              }
            }

            if (codePoint < 0x80) {
              buffer[++resPos] = codePoint;
            } else if (codePoint < 0x800) {
              buffer[++resPos] = 0xc0 | (codePoint >> 6);
              buffer[++resPos] = 0x80 | (codePoint & 0x3f);
            } else if (codePoint < 0x10000) {
              buffer[++resPos] = 0xe0 | (codePoint >> 12);
              buffer[++resPos] = 0x80 | ((codePoint >> 6) & 0x3f);
              buffer[++resPos] = 0x80 | (codePoint & 0x3f);
            } else {
              buffer[++resPos] = 0xf0 | (codePoint >> 18);
              buffer[++resPos] = 0x80 | ((codePoint >> 12) & 0x3f);
              buffer[++resPos] = 0x80 | ((codePoint >> 6) & 0x3f);
              buffer[++resPos] = 0x80 | (codePoint & 0x3f);
            }
          }

          return buffer;
        }
      };
    })(),

    simpleHash: function (str) {
      if (!str) return 'h-000000000000';

      let hash = 0;
      for (let i = 0; i < str.length; i++) {
        const char = str.charCodeAt(i);
        hash = (hash << 5) - hash + char;
        hash = hash & hash;
      }

      const hashStr = Math.abs(hash).toString(16).padStart(12, '0');
      return 'h-' + hashStr.substring(0, 12);
    },

    BigIntPolyfill: (function () {
      if (typeof BigInt !== 'undefined') return null;

      return class BigIntSimulation {
        constructor(value) {
          this.value = String(value);
        }

        static from(value) {
          return new BigIntSimulation(value);
        }

        divide(other) {
          let otherVal = typeof other === 'object' ? parseInt(other.value) : parseInt(other);
          let val = parseInt(this.value);
          let result = Math.floor(val / otherVal);
          return new BigIntSimulation(result);
        }

        modulo(other) {
          let otherVal = typeof other === 'object' ? parseInt(other.value) : parseInt(other);
          let val = parseInt(this.value);
          let result = val % otherVal;
          return result;
        }

        shiftLeft(bits) {
          let val = parseInt(this.value);
          let result = val << bits;
          return new BigIntSimulation(result);
        }

        or(other) {
          let otherVal = typeof other === 'object' ? parseInt(other.value) : parseInt(other);
          let val = parseInt(this.value);
          let result = val | otherVal;
          return new BigIntSimulation(result);
        }

        toString() {
          return this.value;
        }

        valueOf() {
          return parseInt(this.value);
        }
      };
    })(),

    /**
     * MutationObserver polyfill for older browsers
     * This is a simplified version that only supports the options needed by HighlightIt
     */
    MutationObserver: (function () {
      if (typeof MutationObserver !== 'undefined') return MutationObserver;

      return class MutationObserverPolyfill {
        constructor(callback) {
          this.callback = callback;
          this.observed = new Map();
          this.timeout = null;
          this.pollInterval = 100;
        }

        observe(target, options) {
          if (!target || !options) return;

          const snapshot = {
            element: target,
            options: options,
            attributes: this._getAttributes(target),
            characterData: options.characterData ? target.textContent : null,
            childList: options.childList ? this._getChildList(target) : null,
          };

          this.observed.set(target, snapshot);

          if (!this.timeout) {
            this._startPolling();
          }
        }

        disconnect() {
          if (this.timeout) {
            clearTimeout(this.timeout);
            this.timeout = null;
          }
          this.observed.clear();
        }

        takeRecords() {
          return [];
        }

        _startPolling() {
          this.timeout = setTimeout(() => {
            const mutations = [];

            this.observed.forEach((snapshot, target) => {
              if (!document.contains(target)) {
                this.observed.delete(target);
                return;
              }

              if (snapshot.options.attributes) {
                const currentAttributes = this._getAttributes(target);
                const oldAttributes = snapshot.attributes;

                for (const entry of polyfills.objectEntries(oldAttributes)) {
                  const name = entry[0];
                  const value = entry[1];
                  if (!(name in currentAttributes) || currentAttributes[name] !== value) {
                    mutations.push({
                      type: 'attributes',
                      target: target,
                      attributeName: name,
                      oldValue: snapshot.options.attributeOldValue ? value : null,
                    });
                  }
                }

                for (const name in currentAttributes) {
                  if (!(name in oldAttributes)) {
                    mutations.push({
                      type: 'attributes',
                      target: target,
                      attributeName: name,
                      oldValue: null,
                    });
                  }
                }

                snapshot.attributes = currentAttributes;
              }

              if (snapshot.options.characterData) {
                const currentText = target.textContent;
                if (currentText !== snapshot.characterData) {
                  mutations.push({
                    type: 'characterData',
                    target: target,
                    oldValue: snapshot.options.characterDataOldValue
                      ? snapshot.characterData
                      : null,
                  });
                  snapshot.characterData = currentText;
                }
              }

              if (snapshot.options.childList) {
                const currentChildren = this._getChildList(target);
                const oldChildren = snapshot.childList;

                if (currentChildren.length !== oldChildren.length) {
                  mutations.push({
                    type: 'childList',
                    target: target,
                    addedNodes: [],
                    removedNodes: [],
                  });
                }

                snapshot.childList = currentChildren;
              }
            });

            if (mutations.length > 0) {
              this.callback(mutations);
            }

            if (this.observed.size > 0) {
              this._startPolling();
            } else {
              this.timeout = null;
            }
          }, this.pollInterval);
        }

        _getAttributes(element) {
          const result = {};
          const attributes = element.attributes;
          if (attributes) {
            for (let i = 0; i < attributes.length; i++) {
              const attr = attributes[i];
              result[attr.name] = attr.value;
            }
          }
          return result;
        }

        _getChildList(element) {
          return Array.from(element.childNodes);
        }
      };
    })(),

    ResizeObserver: (function () {
      if (typeof ResizeObserver === 'function') return ResizeObserver;

      return class ResizeObserver {
        constructor(callback) {
          this.callback = callback;
          this.observedElements = new Set();
          this.observer = new MutationObserver(this.handleMutation.bind(this));
        }

        observe(element) {
          if (this.observedElements.has(element)) return;
          this.observedElements.add(element);
          this.observer.observe(element, {
            attributes: true,
            attributeFilter: ['style', 'class'],
          });
          this.checkSize(element);
        }

        unobserve(element) {
          this.observedElements.delete(element);
          this.observer.unobserve(element);
        }

        disconnect() {
          this.observer.disconnect();
          this.observedElements.clear();
        }

        handleMutation(mutations) {
          mutations.forEach((mutation) => {
            if (mutation.target && this.observedElements.has(mutation.target)) {
              this.checkSize(mutation.target);
            }
          });
        }

        checkSize(element) {
          const size = {
            width: element.offsetWidth,
            height: element.offsetHeight,
          };
          this.callback([{ target: element, contentRect: size }]);
        }
      };
    })(),

    getBoundingClientRect: function (el) {
      if (!el) return { top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 };

      if (this.supports.getBoundingClientRect) {
        try {
          return el.getBoundingClientRect();
        } catch {
          //
        }
      }

      const rect = {
        top: el.offsetTop,
        left: el.offsetLeft,
        width: el.offsetWidth,
        height: el.offsetHeight,
      };

      rect.right = rect.left + rect.width;
      rect.bottom = rect.top + rect.height;

      let parent = el.offsetParent;
      while (parent) {
        rect.top += parent.offsetTop;
        rect.left += parent.offsetLeft;
        parent = parent.offsetParent;
      }

      rect.top -= window.scrollY || document.documentElement.scrollTop || 0;
      rect.left -= window.scrollX || document.documentElement.scrollLeft || 0;

      return rect;
    },

    classList: {
      add: function (element, className) {
        if (!element) return;

        try {
          if (this.supports.classList) {
            element.classList.add(className);
          } else {
            const classes = (element.className || '').split(' ');
            if (!classes.includes(className)) {
              classes.push(className);
            }
            element.className = classes.join(' ');
          }
        } catch {
          const classes = (element.className || '').split(' ');
          if (!classes.includes(className)) {
            classes.push(className);
          }
          element.className = classes.join(' ');
        }
      },
      remove: function (element, className) {
        if (!element) return;

        try {
          if (this.supports.classList) {
            element.classList.remove(className);
          } else {
            element.className = (element.className || '')
              .split(' ')
              .filter((c) => c !== className)
              .join(' ');
          }
        } catch {
          element.className = (element.className || '')
            .split(' ')
            .filter((c) => c !== className)
            .join(' ');
        }
      },
      contains: function (element, className) {
        if (!element) return false;

        try {
          if (this.supports.classList) {
            return element.classList.contains(className);
          }
          return (element.className || '').split(' ').includes(className);
        } catch {
          return (element.className || '').split(' ').includes(className);
        }
      },
    },

    dataset: {
      get: function (element, key) {
        if (!element) return undefined;

        try {
          if (this.supports.dataset) {
            return element.dataset[key];
          }
          return element.getAttribute(`data-${key}`);
        } catch {
          return element.getAttribute(`data-${key}`);
        }
      },
      set: function (element, key, value) {
        if (!element) return;

        try {
          if (this.supports.dataset) {
            element.dataset[key] = value;
          } else {
            element.setAttribute(`data-${key}`, value);
          }
        } catch {
          element.setAttribute(`data-${key}`, value);
        }
      },
    },

    copyToClipboard: async function (text) {
      if (this.supports.clipboard) {
        try {
          await navigator.clipboard.writeText(text);
          return true;
        } catch {
          //
        }
      }

      if (this.supports.clipboard && this.supports.clipboardItem) {
        try {
          const clipboardItem = new ClipboardItem({
            'text/plain': new Blob([text], { type: 'text/plain' }),
          });
          await navigator.clipboard.write([clipboardItem]);
          return true;
        } catch {
          //
        }
      }

      const textArea = document.createElement('textarea');
      textArea.value = text;
      textArea.style.position = 'fixed';
      textArea.style.left = '-9999px';
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();

      try {
        const success = document.execCommand('copy');
        document.body.removeChild(textArea);
        return success;
      } catch {
        document.body.removeChild(textArea);
        return false;
      }
    },

    downloadFile: function (filename, content, mimeType = 'text/plain') {
      if (this.supports.blob && this.supports.URL) {
        try {
          const blob = new Blob([content], { type: mimeType });
          const url = URL.createObjectURL(blob);

          if (this.supports.download) {
            const link = document.createElement('a');
            link.href = url;
            link.download = filename;
            link.style.display = 'none';
            document.body.appendChild(link);
            link.click();

            setTimeout(() => {
              document.body.removeChild(link);
              URL.revokeObjectURL(url);
            }, 100);

            return true;
          } else {
            window.open(url, '_blank');

            setTimeout(() => {
              URL.revokeObjectURL(url);
            }, 100);

            return true;
          }
        } catch (e) {
          console.error('Error downloading file:', e);
        }
      }

      try {
        const iframeId = 'highlightit-download-iframe';
        let iframe = document.getElementById(iframeId);

        if (!iframe) {
          iframe = document.createElement('iframe');
          iframe.id = iframeId;
          iframe.style.display = 'none';
          document.body.appendChild(iframe);
        }

        const iframeDocument = iframe.contentWindow.document;
        iframeDocument.open('text/html', 'replace');
        iframeDocument.write(content);
        iframeDocument.close();

        iframeDocument.execCommand('SaveAs', true, filename);
        return true;
      } catch (e) {
        console.error('Legacy download failed:', e);
        return false;
      }
    },

    animate: function (element, keyframes, options) {
      if (!element) return null;

      if (this.supports.animation) {
        try {
          return element.animate(keyframes, options);
        } catch {
          //
        }
      }

      const animationId = Date.now().toString(36);
      const duration = options.duration || 1000;

      Object.keys(keyframes[0]).forEach((prop) => {
        element.style[prop] = keyframes[0][prop];
      });

      setTimeout(() => {
        element.style.transition = `all ${duration}ms ${options.easing || 'ease'}`;

        const finalState = keyframes[keyframes.length - 1];
        Object.keys(finalState).forEach((prop) => {
          element.style[prop] = finalState[prop];
        });

        setTimeout(() => {
          element.style.transition = '';
          if (options.fill !== 'forwards') {
            Object.keys(finalState).forEach((prop) => {
              element.style[prop] = '';
            });
          }
        }, duration);
      }, 0);

      return {
        id: animationId,
        cancel: function () {
          element.style.transition = '';
        },
        finished: new Promise((resolve) => {
          setTimeout(resolve, duration);
        }),
      };
    },

    /**
     * Helper to check if a container has an element with a certain class
     * Used as a fallback for browsers that don't support :has() selector
     *
     * @param {HTMLElement} container - The container element to check
     * @param {string} selector - The selector to look for within the container
     * @param {string} className - The class to add/remove from the container
     * @param {boolean} shouldHaveClass - Whether to add or remove the class
     */
    updateHasClass: function (container, selector, className, shouldHaveClass) {
      if (!container || !selector || !className) return;
      if (this.supports.cssHas) return;

      const hasElement = container.querySelector(selector);

      if (shouldHaveClass && hasElement) {
        this.classList.add(container, className);
      } else if (!shouldHaveClass && !hasElement) {
        this.classList.remove(container, className);
      }
    },
  };

  // End bundled module: polyfills.js

  // Begin bundled module: cache.js
  /**
   * Cache for commonly used data in the highlighting process
   */

  const cache = {
    popularLanguages: new Set([
      'javascript',
      'typescript',
      'python',
      'java',
      'html',
      'css',
      'scss',
      'php',
      'ruby',
      'go',
      'rust',
      'c',
      'cpp',
      'csharp',
      'bash',
      'json',
      'markdown',
      'yaml',
      'xml',
    ]),
    extensionMap: new Map([
      ['js', 'javascript'],
      ['ts', 'typescript'],
      ['jsx', 'javascript'],
      ['tsx', 'typescript'],
      ['html', 'html'],
      ['css', 'css'],
      ['scss', 'scss'],
      ['sass', 'scss'],
      ['py', 'python'],
      ['rb', 'ruby'],
      ['java', 'java'],
      ['c', 'c'],
      ['cpp', 'cpp'],
      ['hpp', 'cpp'],
      ['h', 'c'],
      ['cs', 'csharp'],
      ['php', 'php'],
      ['go', 'go'],
      ['rust', 'rust'],
      ['rs', 'rust'],
      ['swift', 'swift'],
      ['md', 'markdown'],
      ['json', 'json'],
      ['xml', 'xml'],
      ['yaml', 'yaml'],
      ['yml', 'yaml'],
      ['sh', 'bash'],
      ['bash', 'bash'],
      ['kt', 'kotlin'],
      ['kts', 'kotlin'],
      ['dart', 'dart'],
      ['pl', 'perl'],
      ['pm', 'perl'],
      ['lua', 'lua'],
      ['groovy', 'groovy'],
      ['r', 'r'],
      ['scala', 'scala'],
      ['sql', 'sql'],
      ['toml', 'toml'],
      ['ini', 'ini'],
      ['hcl', 'hcl'],
      ['tf', 'terraform'],
      ['dockerfile', 'dockerfile'],
      ['vue', 'vue'],
      ['elm', 'elm'],
      ['clj', 'clojure'],
      ['cljs', 'clojure'],
      ['hs', 'haskell'],
      ['lhs', 'haskell'],
      ['ex', 'elixir'],
      ['exs', 'elixir'],
      ['erl', 'erlang'],
      ['fs', 'fsharp'],
      ['fsx', 'fsharp'],
      ['ml', 'ocaml'],
      ['mli', 'ocaml'],
      ['graphql', 'graphql'],
      ['gql', 'graphql'],
      ['proto', 'protobuf'],
      ['sol', 'solidity'],
    ]),
    htmlEscapes: new Map([
      ['&', '&amp;'],
      ['<', '&lt;'],
      ['>', '&gt;'],
      ['"', '&quot;'],
      ["'", '&#39;'],
      ['/', '&#x2F;'],
      ['`', '&#x60;'],
      ['=', '&#x3D;'],
    ]),
    svgIcons: {
      copy: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="highlightit-copy-icon"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`,
      check: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="highlightit-check-icon"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
      share: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="highlightit-share-icon"><circle cx="18" cy="5" r="3"></circle><circle cx="6" cy="12" r="3"></circle><circle cx="18" cy="19" r="3"></circle><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line></svg>`,
      link: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="highlightit-link-icon"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>`,
      download: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="highlightit-download-icon"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`,
    },
  };

  // End bundled module: cache.js

  /**
   * HighlightIt - A lightweight syntax highlighting library with themes, line numbers, and copy functionality.
   * Uses highlight.js for code highlighting
   */

  const BASE62_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

  /**
   * HighlightIt class for syntax highlighting
   */
  class HighlightIt {
    /**
     * Initialize HighlightIt by finding and highlighting all matching elements
     * @param {Object} options - Configuration options
     * @param {string} [options.selector='.highlight-it'] - CSS selector for elements to highlight
     * @param {boolean} [options.autoDetect=true] - Whether to auto-detect language if not specified
     * @param {boolean} [options.addCopyButton=true] - Whether to add a copy button to code blocks
     * @param {boolean} [options.showLanguage=true] - Whether to show the language label
     * @param {boolean} [options.addHeader=true] - Whether to add the header section to code blocks
     * @param {boolean} [options.addLines=false] - Whether to add line numbers to code blocks
     * @param {boolean} [options.addShare=false] - Whether to add share button to code blocks
     * @param {boolean} [options.addDownload=false] - Whether to add download button to code blocks
     * @param {string} [options.theme='auto'] - Theme to use ('light', 'dark', or 'auto')
     * @param {number} [options.debounceTime=50] - Debounce time in ms for live updates (lower values = more responsive)
     */
    static init(options = {}) {
      const {
        selector = '.highlight-it',
        autoDetect = true,
        addCopyButton = true,
        showLanguage = true,
        addHeader = true,
        addLines = false,
        addShare = false,
        addDownload = false,
        theme = 'auto',
        debounceTime = 50,
      } = options;

      polyfills.init();

      this.debounceTime = debounceTime;
      this.applyGlobalTheme(theme);

      this.isTouchDevice = polyfills.supports.touch;

      if (this.isTouchDevice) {
        polyfills.classList.add(document.documentElement, 'highlightit-touch-device');
      }

      const elements = document.querySelectorAll(`${selector}:not(.highlightit-original)`);

      const chunkSize = 50;
      const processChunk = (startIndex) => {
        const endIndex = Math.min(startIndex + chunkSize, elements.length);
        for (let i = startIndex; i < endIndex; i++) {
          this.processElement(
            elements[i],
            autoDetect,
            addCopyButton,
            showLanguage,
            addHeader,
            addLines,
            addShare,
            addDownload
          );
        }
        if (endIndex < elements.length) {
          polyfills.requestAnimationFrame(() => processChunk(endIndex));
        } else {
          if (window.location.hash) {
            this.scrollToAnchor();
          }
        }
      };

      processChunk(0);
      this._initialized = true;

      this.initSharing();
    }

    /**
     * Generate a hash using SHA-256 and convert to a 12-character base62 string
     * @param {string} input - The string to hash
     * @returns {Promise<string>} - A 12-character base62 hash
     */
    static async generateHash(input) {
      try {
        if (!window.crypto || !window.crypto.subtle) {
          return polyfills.simpleHash(input);
        }

        const TextEncoderClass = window.TextEncoder || polyfills.TextEncoder;
        if (!TextEncoderClass) {
          return polyfills.simpleHash(input);
        }

        const encoder = new TextEncoderClass();
        const data = encoder.encode(input);

        const hashBuffer = await crypto.subtle.digest('SHA-256', data);

        const hashArray = Array.from(new Uint8Array(hashBuffer));

        if (typeof BigInt === 'undefined' && polyfills.BigIntPolyfill) {
          return polyfills.simpleHash(input);
        }

        let base62Hash = '';
        let value = 0n;

        for (let i = 0; i < hashArray.length; i++) {
          value = (value << 8n) | BigInt(hashArray[i]);
        }

        while (value > 0 || base62Hash.length < 12) {
          const remainder = Number(value % 62n);
          base62Hash = BASE62_CHARS[remainder] + base62Hash;
          value = value / 62n;

          if (value === 0n && base62Hash.length < 12) {
            base62Hash = '0' + base62Hash;
          }
        }

        return base62Hash.slice(-12).padStart(12, '0');
      } catch (err) {
        console.warn('Error generating hash:', err);
        return polyfills.simpleHash(input);
      }
    }

    /**
     * Create a share button for code blocks
     * @param {string} code - The code to generate hash from if no id exists
     * @param {HTMLElement} container - The container element (to extract id)
     * @returns {HTMLElement} - The share button element
     */
    static async createShareButton(code, container) {
      const shareButton = document.createElement('button');
      shareButton.className = 'highlightit-button highlightit-share';
      shareButton.setAttribute('aria-label', 'Copy link to this code');
      shareButton.innerHTML = cache.svgIcons.share;

      const originalId = container.getAttribute('data-original-id');
      const containerId = container.id;
      let blockId = originalId || containerId;

      if (!blockId) {
        blockId = await this.generateHash(code);
        container.id = blockId;
      }

      const clickListener = async () => {
        const currentId = container.getAttribute('data-original-id') || container.id;
        const url = new URL(window.location.href);
        url.hash = currentId;

        const success = await polyfills.copyToClipboard(url.toString());

        if (success) {
          shareButton.classList.add('copied');
          shareButton.innerHTML = cache.svgIcons.check;

          setTimeout(() => {
            shareButton.classList.remove('copied');
            shareButton.innerHTML = cache.svgIcons.share;
          }, 2000);
        }
      };

      shareButton.addEventListener('click', clickListener);
      shareButton.onclickBackup = clickListener;
      shareButton._currentBlockId = blockId;

      return shareButton;
    }

    /**
     * Update block ID when code changes for blocks with live updates
     * @param {HTMLElement} container - The container element
     * @param {string} newCode - The new code content
     * @returns {Promise<string>} - The updated block ID
     */
    static async updateBlockId(container, newCode) {
      const originalId = container.getAttribute('data-original-id');

      if (originalId) {
        const originalElement = document.querySelector(`.highlightit-original[id="${originalId}"]`);

        if (originalElement) {
          if (originalElement.id !== originalId) {
            originalElement.id = originalId;
          }

          if (container.id === originalId) {
            container.id = '';
          }

          container.setAttribute('data-original-id', originalId);
        } else {
          if (!container.id || container.id !== originalId) {
            container.id = originalId;
          }
        }

        return originalId;
      } else if (container.id) {
        return container.id;
      } else {
        try {
          const newId = await this.generateHash(newCode);
          container.id = newId;
          return newId;
        } catch (err) {
          console.error('Error generating hash:', err);
          const fallbackId = 'highlightit-' + Math.random().toString(36).substring(2, 15);
          container.id = fallbackId;
          return fallbackId;
        }
      }
    }

    /**
     * Scroll to the element specified in the URL hash
     * @param {number} [attempts=0] - Number of attempts made so far
     */
    static scrollToAnchor(attempts = 0) {
      const fullHash = window.location.hash.substring(1);
      if (!fullHash) return;

      const hashParts = fullHash.split('_');
      const hash = hashParts[0];
      const lineNumber = hashParts.length > 1 ? parseInt(hashParts[1], 10) : null;

      const target = document.getElementById(hash);
      if (target) {
        if (target.classList.contains('highlightit-original')) {
          const uniqueId = target.getAttribute('data-highlightit-id');
          let visibleTarget = null;

          if (uniqueId) {
            visibleTarget = document.querySelector(`[data-linked-original="${uniqueId}"]`);
          }

          if (visibleTarget) {
            setTimeout(() => {
              this.scrollToHighlightedElement(visibleTarget, lineNumber);
            }, 100);
            return;
          }
        }

        setTimeout(() => {
          this.scrollToHighlightedElement(target, lineNumber);
        }, 100);
      } else if (attempts < 10) {
        setTimeout(
          () => {
            this.scrollToAnchor(attempts + 1);
          },
          300 * (attempts + 1)
        );
      }
    }

    /**
     * Scroll to a highlighted element and optionally to a specific line
     * @param {HTMLElement} element - The element to scroll to
     * @param {number|null} lineNumber - The line number to highlight, if any
     * @private
     */
    static scrollToHighlightedElement(element, lineNumber) {
      if (lineNumber !== null) {
        const container = element.closest('.highlightit-container');
        if (container) {
          const lineNumbers = container.querySelectorAll('.highlightit-line-number');
          for (let i = 0; i < lineNumbers.length; i++) {
            const ln = lineNumbers[i];
            if (ln.textContent.trim() === String(lineNumber)) {
              const lineContainer = ln.closest('.highlightit-line-number-container') || ln;

              this.createFullWidthHighlight(lineContainer, container);

              lineContainer.scrollIntoView({ behavior: 'smooth', block: 'center' });

              return;
            }
          }
        }
      }

      element.scrollIntoView({ behavior: 'smooth', block: 'start' });
      element.classList.add('highlightit-anchor-highlight');
      setTimeout(() => {
        element.classList.remove('highlightit-anchor-highlight');
      }, 2000);
    }

    /**
     * Create a full-width highlight that spans both line numbers and code
     * @param {HTMLElement} lineContainer - The line container element
     * @param {HTMLElement} codeContainer - The code container element
     * @private
     */
    static createFullWidthHighlight(lineContainer, codeContainer) {
      lineContainer.classList.add('highlightit-line-highlight');

      const rect = polyfills.getBoundingClientRect(lineContainer);
      const containerRect = polyfills.getBoundingClientRect(codeContainer);

      const overlay = document.createElement('div');
      overlay.className = 'highlightit-line-highlight-overlay';

      overlay.style.top = `${rect.top - containerRect.top}px`;
      overlay.style.height = `${rect.height}px`;
      overlay.style.width = '100%';
      overlay.style.left = '0';

      codeContainer.appendChild(overlay);

      setTimeout(() => {
        lineContainer.classList.remove('highlightit-line-highlight');
        if (overlay && overlay.parentNode) {
          overlay.parentNode.removeChild(overlay);
        }
      }, 2500);
    }

    /**
     * Process an element for highlighting, handling both single and nested element structures
     * @param {HTMLElement} element - The element to process
     * @param {boolean} autoDetect - Whether to auto-detect language
     * @param {boolean} addCopyButton - Whether to add a copy button
     * @param {boolean} showLanguage - Whether to show the language label
     * @param {boolean} addHeader - Whether to add header section
     * @param {boolean} addLines - Whether to add line numbers
     * @param {boolean} addShare - Whether to add share button
     * @param {boolean} addDownload - Whether to add download button
     * @private
     */
    static processElement(
      element,
      autoDetect,
      addCopyButton,
      showLanguage,
      addHeader,
      addLines,
      addShare,
      addDownload
    ) {
      let codeElement;
      let preElement;
      let originalElement = null;
      const withLiveUpdates = element.dataset.withReload !== undefined;

      if (element.textContent !== null && element.textContent !== undefined) {
        element.textContent = element.textContent.trim();
      }

      if (element.dataset.lineStart !== undefined) {
        element.dataset.withLines = '';
        addLines = true;
      }

      if (
        element.tagName.toLowerCase() === 'code' &&
        element.parentElement.tagName.toLowerCase() === 'pre'
      ) {
        codeElement = element;
        preElement = element.parentElement;

        if (withLiveUpdates) {
          const uniqueId = 'highlightit-id-' + Math.random().toString(36).substr(2, 9);

          originalElement = document.createElement('pre');
          const originalCodeElement = document.createElement('code');

          originalCodeElement.textContent = element.textContent || '';

          originalElement.classList.add('highlightit-original');

          if (preElement.id) {
            originalElement.id = preElement.id;
            preElement.setAttribute('data-original-id', preElement.id);
            preElement.id = '';
          }

          originalElement.setAttribute('data-highlightit-id', uniqueId);
          originalElement.classList.add('highlightit-visually-hidden');

          if (element.dataset.language) {
            originalCodeElement.dataset.language = element.dataset.language;
          }

          if (element.dataset.lineStart !== undefined) {
            originalCodeElement.dataset.lineStart = element.dataset.lineStart;
          }

          if (element.dataset.withShare !== undefined) {
            originalCodeElement.dataset.withShare = element.dataset.withShare;
          }

          if (element.dataset.withDownload !== undefined) {
            originalCodeElement.dataset.withDownload = element.dataset.withDownload;
          }

          if (element.dataset.filename !== undefined) {
            originalCodeElement.dataset.filename = element.dataset.filename;
          }

          originalElement.appendChild(originalCodeElement);

          preElement.dataset.linkedOriginal = uniqueId;

          preElement.classList.add('highlightit-streaming-target');

          preElement.parentNode.insertBefore(originalElement, preElement);
        }
      } else {
        const content = element.textContent || '';

        if (withLiveUpdates) {
          const uniqueId = 'highlightit-id-' + Math.random().toString(36).substr(2, 9);

          originalElement = document.createElement('pre');
          const originalCodeElement = document.createElement('code');

          originalCodeElement.textContent = content;
          originalElement.appendChild(originalCodeElement);

          originalElement.classList.add('highlightit-original');

          if (element.id) {
            originalElement.id = element.id;
            element.setAttribute('data-original-id', element.id);
            element.id = '';
          }

          originalElement.setAttribute('data-highlightit-id', uniqueId);
          originalElement.classList.add('highlightit-visually-hidden');

          if (element.dataset.language) {
            originalCodeElement.dataset.language = element.dataset.language;
          }

          if (element.dataset.lineStart !== undefined) {
            originalCodeElement.dataset.lineStart = element.dataset.lineStart;
          }

          if (element.dataset.withShare !== undefined) {
            originalCodeElement.dataset.withShare = element.dataset.withShare;
          }

          if (element.dataset.withDownload !== undefined) {
            originalCodeElement.dataset.withDownload = element.dataset.withDownload;
          }

          if (element.dataset.filename !== undefined) {
            originalCodeElement.dataset.filename = element.dataset.filename;
          }

          element.parentNode.insertBefore(originalElement, element);

          element.setAttribute('data-linked-original', uniqueId);
        }

        const container = document.createElement('div');

        if (element.className.includes('highlight-it')) {
          container.className = 'highlight-it highlightit-container';
        } else {
          container.className = element.className;
        }

        if (element.id && !withLiveUpdates) {
          container.id = element.id;
        }

        preElement = document.createElement('pre');
        codeElement = document.createElement('code');

        codeElement.textContent = content.trim();

        for (const key in element.dataset) {
          container.dataset[key] = element.dataset[key];

          if (key === 'language') {
            codeElement.dataset.language = element.dataset[key];
            codeElement.className = `language-${element.dataset[key]}`;
          }

          if (key === 'withLines') {
            container.classList.add('highlightit-with-lines');
          }

          if (key === 'withDownload') {
            container.classList.add('highlightit-with-download');
          }

          if (key === 'noHeader') {
            container.classList.add('highlightit-no-header');
          }

          if (key === 'lineStart') {
            codeElement.dataset.lineStart = element.dataset[key];
          }
        }

        preElement.appendChild(codeElement);
        container.appendChild(preElement);

        element.parentNode.replaceChild(container, element);
        element = codeElement;
      }

      if (addLines || element.dataset.withLines !== undefined) {
        const container = this.createCodeContainer(element);
        container.classList.add('highlightit-with-lines');
      }

      if (addDownload || element.dataset.withDownload !== undefined) {
        const container = this.createCodeContainer(element);
        container.classList.add('highlightit-with-download');
      }

      this.highlightElement(
        element,
        autoDetect,
        addCopyButton,
        showLanguage,
        addHeader,
        addLines,
        addShare,
        addDownload
      );
    }

    /**
     * Apply global theme to the document root
     * @param {string} theme - Theme to apply ('light', 'dark', or 'auto')
     * @private
     */
    static applyGlobalTheme(theme) {
      document.documentElement.classList.remove(
        'highlightit-theme-light',
        'highlightit-theme-dark',
        'highlightit-theme-auto'
      );

      if (['light', 'dark', 'auto'].includes(theme)) {
        document.documentElement.classList.add(`highlightit-theme-${theme}`);
      } else {
        document.documentElement.classList.add('highlightit-theme-auto');
      }
    }

    /**
     * Highlight a single element
     * @param {HTMLElement} element - The code element to highlight
     * @param {boolean} autoDetect - Whether to auto-detect language
     * @param {boolean} addCopyButton - Whether to add a copy button
     * @param {boolean} showLanguage - Whether to show the language label
     * @param {boolean} addHeader - Whether to add header section
     * @param {boolean} addLines - Whether to add line numbers
     * @param {boolean} addShare - Whether to add share button
     * @param {boolean} addDownload - Whether to add download button
     * @private
     *
     * The element can have various data attributes:
     * - data-language: The programming language for syntax highlighting
     * - data-filename: Filename to display (also used to detect language)
     * - data-theme: Override global theme for this element ('light', 'dark', 'auto')
     * - data-with-lines: Add line numbers to the code block
     * - data-line-start: Set the starting line number (default is 1, can be positive or negative)
     * - data-no-header: Hide the header (language label and copy button)
     * - data-no-copy: Hide the copy button
     * - data-with-reload: Enable live updates - code will be rehighlighted automatically when content changes
     * - data-with-share: Add a share button that copies the URL with the element ID as the fragment
     * - data-with-download: Add a download button that downloads the code as a file
     * - data-filename: Used for the download feature to set the filename for downloaded code
     */
    static highlightElement(
      element,
      autoDetect,
      addCopyButton,
      showLanguage,
      addHeader,
      addLines,
      addShare,
      addDownload
    ) {
      const container = this.createCodeContainer(element);

      const code = (element.textContent || '').trim();

      let language = null;
      let displayLabel = null;
      let filename = null;

      const elementDataset = element.dataset;
      const containerDataset = container.dataset;

      const noHeader =
        !addHeader ||
        elementDataset.noHeader !== undefined ||
        containerDataset.noHeader !== undefined;
      const withLines =
        addLines ||
        elementDataset.withLines !== undefined ||
        containerDataset.withLines !== undefined;
      const withLiveUpdates =
        elementDataset.withReload !== undefined || containerDataset.withReload !== undefined;
      const noCopy = elementDataset.noCopy !== undefined || containerDataset.noCopy !== undefined;
      const withShare =
        addShare ||
        elementDataset.withShare !== undefined ||
        containerDataset.withShare !== undefined;
      const withDownload =
        addDownload ||
        elementDataset.withDownload !== undefined ||
        containerDataset.withDownload !== undefined;

      const shouldAddCopyButton = addCopyButton && !noCopy;

      if (elementDataset.language) {
        language = elementDataset.language;
        displayLabel = language;
      } else if (containerDataset.language) {
        language = containerDataset.language;
        displayLabel = language;
      }

      if (elementDataset.filename) {
        filename = elementDataset.filename;
        language = this.getLanguageFromFilename(filename);
        displayLabel = filename;
      } else if (containerDataset.filename) {
        filename = containerDataset.filename;
        language = this.getLanguageFromFilename(filename);
        displayLabel = filename;
      }

      if (elementDataset.theme) {
        const elementTheme = elementDataset.theme.toLowerCase();
        if (['light', 'dark', 'auto'].includes(elementTheme)) {
          container.classList.add(`highlightit-theme-${elementTheme}`);
        }
      } else if (containerDataset.theme) {
        const elementTheme = containerDataset.theme.toLowerCase();
        if (['light', 'dark', 'auto'].includes(elementTheme)) {
          container.classList.add(`highlightit-theme-${elementTheme}`);
        }
      }

      if (withShare && !withLiveUpdates) {
        const originalId = container.getAttribute('data-original-id');
        const hasId = originalId || container.id;

        if (!hasId) {
          this.generateHash(code).then((blockId) => {
            container.id = blockId;
          });
        }
      }

      if (
        (showLanguage || shouldAddCopyButton || withShare || withDownload) &&
        addHeader &&
        !noHeader
      ) {
        const header = this.createCodeHeader(
          displayLabel,
          code,
          shouldAddCopyButton,
          showLanguage,
          withShare,
          withDownload,
          container
        );
        container.prepend(header);
      } else if (noHeader) {
        container.classList.add('highlightit-no-header');
        if (shouldAddCopyButton || withShare || withDownload) {
          const floatingBtns = this.createFloatingButtons(code, withShare, withDownload, container);
          container.appendChild(floatingBtns);
        }
      }

      if (withLines) {
        container.classList.add('highlightit-with-lines');
      }

      if (withLiveUpdates) {
        this.setupLiveUpdates(element, container, autoDetect, showLanguage, withShare);
      }

      if (!language && autoDetect) {
        const result = this.autoDetectLanguage(code);
        language = result.language || 'unknown';

        element.innerHTML = result.value;
        element.classList.add(`language-${language}`);

        if (withLines) {
          this.addLineNumbers(element, code);
        }

        if (showLanguage && !noHeader) {
          const header = container.querySelector('.highlightit-header');
          if (header) {
            const languageLabel = header.querySelector('.highlightit-language');
            if (languageLabel) {
              languageLabel.textContent = language;
            } else if (language) {
              const newLanguageLabel = document.createElement('span');
              newLanguageLabel.className = 'highlightit-language';
              newLanguageLabel.textContent = language;
              header.insertBefore(newLanguageLabel, header.firstChild);
            }
          }
        }

        return;
      }

      if (language) {
        try {
          let result;
          try {
            result = hljs.highlight(code, { language });
          } catch (e) {
            console.error(
              `HighlightIt: Error highlighting with language ${language}`,
              e,
              'This might be because highlight.js is not available. Please ensure its script is included in the page.'
            );
            result = { value: this.escapeHtml(code) };
          }
          element.innerHTML = result.value;
          element.classList.add(`language-${language}`);

          if (withLines) {
            this.addLineNumbers(element, code);
          }
        } catch (error) {
          if (autoDetect) {
            const result = this.autoDetectLanguage(code);
            element.innerHTML = result.value;
            element.classList.add(`language-${result.language || 'unknown'}`);

            if (withLines) {
              this.addLineNumbers(element, code);
            }

            if (showLanguage && !noHeader) {
              const header = container.querySelector('.highlightit-header');
              if (header) {
                const languageLabel = header.querySelector('.highlightit-language');
                if (languageLabel && result.language) {
                  languageLabel.textContent = result.language;
                }
              }
            }
          } else {
            console.error(`HighlightIt: Error highlighting with language ${language}`, error);
            element.innerHTML = this.escapeHtml(code);

            if (withLines) {
              this.addLineNumbers(element, code);
            }
          }
        }
      } else {
        element.innerHTML = `${this.escapeHtml(code)}`;

        if (withLines) {
          this.addLineNumbers(element, code);
        }
      }
    }

    /**
     * Set up live updates to watch for changes to the code element
     * @param {HTMLElement} element - The code element to watch
     * @param {HTMLElement} container - The container element
     * @param {boolean} autoDetect - Whether to auto-detect language
     * @param {boolean} showLanguage - Whether to show the language label
     * @param {boolean} withShare - Whether to update block ID for sharing
     * @private
     */
    static setupLiveUpdates(element, container, autoDetect, showLanguage, withShare) {
      const MutationObserverClass = window.MutationObserver || polyfills.MutationObserver;
      if (!MutationObserverClass) {
        console.warn('HighlightIt: Live updates not supported in this browser');
        return;
      }

      const debounceTime = this.debounceTime || 30;
      let timeout = null;

      const originalElement = this.findOriginalElement(element, container);
      const elementToWatch = originalElement || element;
      const targetElement = element;

      const language =
        polyfills.dataset.get(element, 'language') ||
        (element.className.match(/language-(\w+)/) || [])[1] ||
        null;

      let detectedLanguage = null;
      if (!language && autoDetect) {
        const code = (elementToWatch.querySelector('code') || elementToWatch).textContent.trim();
        if (code) {
          const result = this.autoDetectLanguage(code);
          detectedLanguage = result.language || null;
        }
      }

      let lastProcessedCode = '';

      const rehighlight = () => {
        const originalCode = elementToWatch.querySelector('code') || elementToWatch;
        const code = originalCode.textContent.trim();
        if (!code) return;

        if (code === lastProcessedCode) {
          return;
        }

        lastProcessedCode = code;

        if (withShare) {
          this.updateBlockId(container, code).then(() => {
            this.updateCodeBlock(targetElement, container, language, code, showLanguage);
          });
        } else {
          if (!language && autoDetect) {
            if (
              !detectedLanguage ||
              (showLanguage &&
                !container.querySelector('.highlightit-header .highlightit-language'))
            ) {
              const result = this.autoDetectLanguage(code);
              detectedLanguage = result.language || 'unknown';
              targetElement.innerHTML = result.value;
              polyfills.classList.add(targetElement, `language-${detectedLanguage}`);

              if (showLanguage && detectedLanguage) {
                const header = container.querySelector('.highlightit-header');
                if (header) {
                  const languageLabel = header.querySelector('.highlightit-language');
                  if (languageLabel) {
                    languageLabel.textContent = detectedLanguage;
                  } else {
                    const newLanguageLabel = document.createElement('span');
                    newLanguageLabel.className = 'highlightit-language';
                    newLanguageLabel.textContent = detectedLanguage;
                    header.insertBefore(newLanguageLabel, header.firstChild);
                  }
                }
              }
            } else {
              try {
                const result = hljs.highlight(code, { language: detectedLanguage });
                targetElement.innerHTML = result.value;
              } catch (e) {
                console.error(
                  `HighlightIt: Error highlighting with language ${detectedLanguage}`,
                  e,
                  'This might be because highlight.js is not available. Please ensure its script is included in the page.'
                );
                targetElement.innerHTML = this.escapeHtml(code);
              }
              polyfills.classList.add(targetElement, `language-${detectedLanguage}`);
            }
          } else {
            this.updateCodeBlock(targetElement, container, language, code, showLanguage);
            polyfills.classList.add(targetElement, `language-${language || 'unknown'}`);
          }
        }

        if (container.classList.contains('highlightit-with-lines')) {
          const preElement = targetElement.parentElement;
          const oldLineNumbers = preElement.querySelector('.highlightit-line-numbers');
          const lineCount = code.split('\n').length;

          const oldLineCount = oldLineNumbers
            ? oldLineNumbers.querySelectorAll('.highlightit-line-number-container').length ||
              oldLineNumbers.querySelectorAll('.highlightit-line-number').length
            : 0;

          let lineStart = parseInt(
            targetElement.dataset.lineStart || preElement.dataset.lineStart || 1,
            10
          );

          const currentBlockId = container.getAttribute('data-original-id') || container.id;
          const withShare =
            container.dataset.withShare !== undefined || element.dataset.withShare !== undefined;

          this.updateLineNumbersForLiveUpdates(
            oldLineNumbers,
            lineCount,
            oldLineCount,
            lineStart,
            withShare,
            currentBlockId,
            container
          );
        }
      };

      const observer = new MutationObserver(() => {
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
          rehighlight();
          timeout = null;
        }, debounceTime);
      });

      observer.observe(elementToWatch, {
        characterData: true,
        childList: true,
        subtree: true,
      });

      elementToWatch._highlightObserver = observer;
    }

    /**
     * Intelligently update line numbers for live updates, preserving existing DOM elements
     * @param {HTMLElement} lineNumbersWrapper - The line numbers wrapper
     * @param {number} newLineCount - The new line count
     * @param {number} oldLineCount - The old line count
     * @param {number} startLine - The starting line number
     * @param {boolean} withShare - Whether share buttons should be included
     * @param {string} blockId - The block ID for share links
     * @param {HTMLElement} container - The container element
     */
    static updateLineNumbersForLiveUpdates(
      lineNumbersWrapper,
      newLineCount,
      oldLineCount,
      startLine,
      withShare,
      blockId,
      container
    ) {
      if (newLineCount === oldLineCount) {
        const lineNumbers = lineNumbersWrapper.querySelectorAll('.highlightit-line-number');
        const lineShareButtons = lineNumbersWrapper.querySelectorAll('.highlightit-line-share');

        for (let i = 0; i < newLineCount; i++) {
          const lineNumber = startLine + i;

          if (lineNumbers[i]) {
            lineNumbers[i].textContent = lineNumber;
          }

          if (withShare && blockId && lineShareButtons[i]) {
            lineShareButtons[i].dataset.lineNumber = lineNumber;

            if (lineShareButtons[i].dataset.blockId !== blockId) {
              lineShareButtons[i].dataset.blockId = blockId;

              const oldClickListener = lineShareButtons[i]._clickListener;
              if (oldClickListener) {
                lineShareButtons[i].removeEventListener('click', oldClickListener);
              }

              this.setupLineShareButtonHandler(lineShareButtons[i], container);
            }
          }
        }
        return;
      }

      if (newLineCount > oldLineCount) {
        const fragment = document.createDocumentFragment();

        for (let i = oldLineCount; i < newLineCount; i++) {
          const lineNumber = startLine + i;
          const lineNumberContainer = document.createElement('div');
          lineNumberContainer.className = 'highlightit-line-number-container';

          const span = document.createElement('span');
          span.className = 'highlightit-line-number';
          span.textContent = lineNumber;

          if (withShare && blockId) {
            span.className += ' highlightit-line-number-shareable';

            const lineShareButton = document.createElement('button');
            lineShareButton.className = 'highlightit-line-share';
            lineShareButton.setAttribute('aria-label', `Copy link to line ${lineNumber}`);
            lineShareButton.innerHTML = cache.svgIcons.link;
            lineShareButton.dataset.lineNumber = lineNumber;
            lineShareButton.dataset.blockId = blockId;

            this.setupLineShareButtonHandler(lineShareButton, container);

            lineNumberContainer.appendChild(span);
            lineNumberContainer.appendChild(lineShareButton);
          } else {
            lineNumberContainer.appendChild(span);
          }

          fragment.appendChild(lineNumberContainer);
        }

        lineNumbersWrapper.appendChild(fragment);
      } else if (newLineCount < oldLineCount) {
        const allLineContainers = lineNumbersWrapper.querySelectorAll(
          '.highlightit-line-number-container'
        );
        const lineNumbers = lineNumbersWrapper.querySelectorAll('.highlightit-line-number');

        for (let i = newLineCount; i < oldLineCount; i++) {
          if (allLineContainers[i]) {
            lineNumbersWrapper.removeChild(allLineContainers[i]);
          } else if (lineNumbers[i]) {
            lineNumbersWrapper.removeChild(lineNumbers[i]);
          }
        }

        for (let i = 0; i < newLineCount; i++) {
          const lineNumber = startLine + i;

          if (allLineContainers[i]) {
            const span = allLineContainers[i].querySelector('.highlightit-line-number');
            if (span) {
              span.textContent = lineNumber;
            }

            if (withShare && blockId) {
              const button = allLineContainers[i].querySelector('.highlightit-line-share');
              if (button) {
                button.dataset.lineNumber = lineNumber;

                if (button.dataset.blockId !== blockId) {
                  button.dataset.blockId = blockId;

                  const oldClickListener = button._clickListener;
                  if (oldClickListener) {
                    button.removeEventListener('click', oldClickListener);
                  }

                  this.setupLineShareButtonHandler(button, container);
                }
              }
            }
          } else if (lineNumbers[i]) {
            lineNumbers[i].textContent = lineNumber;
          }
        }
      }
    }

    /**
     * Create a styled container for code block
     * @param {HTMLElement} element - The code element to wrap
     * @returns {HTMLElement} - The container element
     * @private
     */
    static createCodeContainer(element) {
      const preElement = element.parentElement;

      if (
        preElement.parentElement &&
        preElement.parentElement.classList.contains('highlightit-container')
      ) {
        return preElement.parentElement;
      }

      const container = document.createElement('div');
      container.className = 'highlightit-container';

      if (preElement.dataset && preElement.dataset.linkedOriginal) {
        container.dataset.linkedOriginal = preElement.dataset.linkedOriginal;
      } else if (preElement.hasAttribute('data-linked-original')) {
        container.setAttribute(
          'data-linked-original',
          preElement.getAttribute('data-linked-original')
        );
        preElement.removeAttribute('data-linked-original');
      }

      if (preElement.hasAttribute('data-original-id')) {
        container.setAttribute('data-original-id', preElement.getAttribute('data-original-id'));
      }

      if (!container.id) {
        if (preElement.id) {
          container.id = preElement.id;
          preElement.removeAttribute('id');
        } else if (element.id) {
          container.id = element.id;
          element.removeAttribute('id');
        }
      }

      preElement.parentNode.insertBefore(container, preElement);
      container.appendChild(preElement);

      return container;
    }

    /**
     * Create code header with language/filename label and copy button
     * @param {string} displayLabel - The text to display (language or filename)
     * @param {string} code - The code to copy
     * @param {boolean} addCopyButton - Whether to add a copy button
     * @param {boolean} showLanguage - Whether to show the language label
     * @param {boolean} addShareButton - Whether to add a share button
     * @param {boolean} addDownloadButton - Whether to add a download button
     * @param {HTMLElement} container - The container element (for share button)
     * @returns {HTMLElement} - The header element
     */
    static createCodeHeader(
      displayLabel,
      code,
      addCopyButton,
      showLanguage,
      addShareButton,
      addDownloadButton,
      container
    ) {
      const header = document.createElement('div');
      header.className = 'highlightit-header';

      if (showLanguage) {
        const languageLabel = document.createElement('span');
        languageLabel.className = 'highlightit-language';
        languageLabel.textContent = displayLabel || 'unknown';
        header.appendChild(languageLabel);
      } else {
        header.style.justifyContent = 'flex-end';
      }

      const buttonContainer = document.createElement('div');
      buttonContainer.className = 'highlightit-buttons-container';
      buttonContainer.style.display = 'flex';
      buttonContainer.style.alignItems = 'center';

      if (addCopyButton) {
        const copyButton = this.createCopyButton(code);
        buttonContainer.appendChild(copyButton);
      }

      if (addDownloadButton) {
        const downloadButton = this.createDownloadButton(code, displayLabel, container);
        buttonContainer.appendChild(downloadButton);
      }

      if (addShareButton) {
        this.createShareButton(code, container).then((shareButton) => {
          buttonContainer.appendChild(shareButton);
        });
      }

      header.appendChild(buttonContainer);

      return header;
    }

    /**
     * Create copy button element
     * @param {string} code - The code to copy
     * @returns {HTMLElement} - The copy button element
     * @private
     */
    static createCopyButton(code) {
      const copyButton = document.createElement('button');
      copyButton.className = 'highlightit-button highlightit-copy';
      copyButton.setAttribute('aria-label', 'Copy code');
      copyButton.innerHTML = `${cache.svgIcons.copy}${cache.svgIcons.check.replace('highlightit-check-icon', 'highlightit-check-icon" style="display: none;')}`;

      const clickListener = async () => {
        const codeToCopy = code.trim();
        const success = await polyfills.copyToClipboard(codeToCopy);

        if (success) {
          polyfills.classList.add(copyButton, 'copied');

          const copyIcon = copyButton.querySelector('.highlightit-copy-icon');
          const checkIcon = copyButton.querySelector('.highlightit-check-icon');

          if (copyIcon) copyIcon.style.display = 'none';
          if (checkIcon) checkIcon.style.display = 'block';

          setTimeout(() => {
            polyfills.classList.remove(copyButton, 'copied');

            if (copyIcon) copyIcon.style.display = 'block';
            if (checkIcon) checkIcon.style.display = 'none';
          }, 2000);
        } else {
          console.warn('Failed to copy code');
        }
      };

      copyButton.onclickBackup = clickListener;
      copyButton._currentCode = code.trim();
      copyButton.addEventListener('click', clickListener);

      return copyButton;
    }

    /**
     * Create download button element
     * @param {string} code - The code to download
     * @param {string} language - The language of the code (for filename extension)
     * @param {HTMLElement} container - The container element (for filename attribute)
     * @returns {HTMLElement} - The download button element
     * @private
     */
    static createDownloadButton(code, language, container) {
      const downloadButton = document.createElement('button');
      downloadButton.className = 'highlightit-button highlightit-download';
      downloadButton.setAttribute('aria-label', 'Download code');
      downloadButton.innerHTML = `${cache.svgIcons.download}${cache.svgIcons.check.replace('highlightit-check-icon', 'highlightit-check-icon" style="display: none;')}`;

      let filename = container && container.dataset && container.dataset.filename;

      if (!filename) {
        const extension = language ? this.getLanguageFileExtension(language) : 'txt';
        filename = `code.${extension}`;
      }

      const clickListener = async () => {
        const codeToDownload = code.trim();
        const success = polyfills.downloadFile(filename, codeToDownload);

        if (success) {
          polyfills.classList.add(downloadButton, 'copied');
          const downloadIcon = downloadButton.querySelector('.highlightit-download-icon');
          const checkIcon = downloadButton.querySelector('.highlightit-check-icon');

          if (downloadIcon) downloadIcon.style.display = 'none';
          if (checkIcon) checkIcon.style.display = 'block';

          setTimeout(() => {
            polyfills.classList.remove(downloadButton, 'copied');
            if (downloadIcon) downloadIcon.style.display = 'block';
            if (checkIcon) checkIcon.style.display = 'none';
          }, 2000);
        } else {
          console.warn('Failed to download code');
        }
      };

      downloadButton.addEventListener('click', clickListener);
      downloadButton.onclickBackup = clickListener;
      downloadButton._code = code;

      return downloadButton;
    }

    /**
     * Create floating buttons for no-header mode
     * @param {string} code - The code to copy
     * @param {boolean} withShare - Whether to add a share button
     * @param {boolean} withDownload - Whether to add a download button
     * @param {HTMLElement} container - The container element for share functionality
     * @returns {HTMLElement} - The floating buttons container
     * @private
     */
    static createFloatingButtons(code, withShare = false, withDownload = false, container = null) {
      const buttonsContainer = document.createElement('div');
      buttonsContainer.className = 'highlightit-floating-buttons';

      const copyButton = document.createElement('button');
      copyButton.className = 'highlightit-button highlightit-floating highlightit-copy';
      copyButton.setAttribute('aria-label', 'Copy code');
      copyButton.innerHTML = cache.svgIcons.copy;

      copyButton.addEventListener('click', async () => {
        const success = await polyfills.copyToClipboard(code.trim());

        if (success) {
          polyfills.classList.add(copyButton, 'copied');
          copyButton.innerHTML = cache.svgIcons.check;

          setTimeout(() => {
            polyfills.classList.remove(copyButton, 'copied');
            copyButton.innerHTML = cache.svgIcons.copy;
          }, 2000);
        }
      });

      buttonsContainer.appendChild(copyButton);

      if (withDownload && container) {
        const downloadButton = document.createElement('button');
        downloadButton.className = 'highlightit-button highlightit-floating highlightit-download';
        downloadButton.setAttribute('aria-label', 'Download code');
        downloadButton.innerHTML = `${cache.svgIcons.download}${cache.svgIcons.check.replace('highlightit-check-icon', 'highlightit-check-icon" style="display: none;')}`;

        let filename = container && container.dataset && container.dataset.filename;
        let codeLanguage =
          container.querySelector('code') &&
          (container.querySelector('code').dataset.language ||
            (container.querySelector('code').className.match(/language-(\w+)/) || [])[1]);

        if (!filename) {
          const extension = codeLanguage ? this.getLanguageFileExtension(codeLanguage) : 'txt';
          filename = `code.${extension}`;
        }

        const clickListener = () => {
          const success = polyfills.downloadFile(filename, code.trim());

          if (success) {
            polyfills.classList.add(downloadButton, 'copied');

            const downloadIcon = downloadButton.querySelector('.highlightit-download-icon');
            const checkIcon = downloadButton.querySelector('.highlightit-check-icon');

            if (downloadIcon) downloadIcon.style.display = 'none';
            if (checkIcon) checkIcon.style.display = 'block';

            setTimeout(() => {
              polyfills.classList.remove(downloadButton, 'copied');

              if (downloadIcon) downloadIcon.style.display = 'block';
              if (checkIcon) checkIcon.style.display = 'none';
            }, 2000);
          }
        };

        downloadButton.addEventListener('click', clickListener);
        downloadButton.onclickBackup = clickListener;
        downloadButton._code = code.trim();

        buttonsContainer.appendChild(downloadButton);
      }

      if (withShare && container) {
        (async () => {
          const shareButton = await this.createShareButton(code, container);
          shareButton.className = 'highlightit-button highlightit-floating highlightit-share';

          if (this.isTouchDevice) {
            shareButton.style.opacity = '1';
          }

          buttonsContainer.appendChild(shareButton);
        })();
      }

      return buttonsContainer;
    }

    /**
     * Get language from filename extension
     * @param {string} filename - The filename to extract extension from
     * @returns {string|null} - The language name or null if not determined
     * @private
     */
    static getLanguageFromFilename(filename) {
      const extension = filename.split('.').pop().toLowerCase();
      return cache.extensionMap.get(extension) || null;
    }

    /**
     * Auto-detect language with priority given to popular languages
     * @param {string} code - The code to detect the language of
     * @returns {Object} - The highlight.js result object with language and value properties
     * @private
     */
    static autoDetectLanguage(code) {
      try {
        if (!code || code.trim().length < 3) {
          return { value: this.escapeHtml(code), language: 'plaintext' };
        }

        const result = hljs.highlightAuto(code, Array.from(cache.popularLanguages));
        return result.language ? result : hljs.highlightAuto(code);
      } catch (e) {
        console.error(
          'HighlightIt: Error auto-detecting language',
          e,
          'This might be because highlight.js is not available. Please ensure its script is included in the page.'
        );
        return { value: this.escapeHtml(code), language: 'unknown' };
      }
    }

    /**
     * Escape HTML special characters
     * @param {string} html - The HTML string to escape
     * @returns {string} - The escaped HTML string
     * @private
     */
    static escapeHtml(html) {
      return html.replace(/[&<>"'`=/]/g, (char) => cache.htmlEscapes.get(char));
    }

    /**
     * Add line numbers to a code element
     * @param {HTMLElement} element - The code element to add line numbers to
     * @param {string} code - The original code content
     * @private
     */
    static addLineNumbers(element, code) {
      const preElement = element.parentElement;
      if (preElement.querySelector('.highlightit-line-numbers')) return;

      const container = preElement.closest('.highlightit-container');
      const withShare =
        container &&
        (container.dataset.withShare !== undefined || element.dataset.withShare !== undefined);

      const lines = code.trim().split('\n');
      const lineCount = lines.length;

      const lineNumbersWrapper = document.createElement('div');
      lineNumbersWrapper.className = 'highlightit-line-numbers';

      const startLine = parseInt(
        element.dataset.lineStart || preElement.dataset.lineStart || 1,
        10
      );

      const fragment = document.createDocumentFragment();

      let blockId = '';
      if (withShare) {
        blockId = container.getAttribute('data-original-id') || container.id;

        if (!blockId) {
          blockId = 'temp-' + Math.random().toString(36).substr(2, 9);
          container.id = blockId;

          this.generateHash(code).then((hash) => {
            if (container.id === blockId) {
              container.id = hash;
            }

            const lineNumbers = lineNumbersWrapper.querySelectorAll('.highlightit-line-number');
            lineNumbers.forEach((lineNumber) => {
              const lineShareBtn = lineNumber.querySelector('.highlightit-line-share');
              if (lineShareBtn && lineShareBtn.dataset.blockId === blockId) {
                lineShareBtn.dataset.blockId = hash;
              }
            });
          });
        }
      }

      for (let i = 0; i < lineCount; i++) {
        const lineNumberContainer = document.createElement('div');
        lineNumberContainer.className = 'highlightit-line-number-container';

        const span = document.createElement('span');
        span.className = 'highlightit-line-number';
        span.textContent = startLine + i;

        if (withShare && blockId) {
          const lineNumber = startLine + i;
          span.className += ' highlightit-line-number-shareable';

          const lineShareButton = document.createElement('button');
          lineShareButton.className = 'highlightit-line-share';
          lineShareButton.setAttribute('aria-label', `Copy link to line ${lineNumber}`);
          lineShareButton.innerHTML = cache.svgIcons.link;
          lineShareButton.dataset.lineNumber = lineNumber;
          lineShareButton.dataset.blockId = blockId;

          this.setupLineShareButtonHandler(lineShareButton, container);

          lineNumberContainer.appendChild(span);
          lineNumberContainer.appendChild(lineShareButton);
        } else {
          lineNumberContainer.appendChild(span);
        }

        fragment.appendChild(lineNumberContainer);
      }

      lineNumbersWrapper.appendChild(fragment);

      polyfills.classList.add(preElement, 'highlightit-has-line-numbers');
      preElement.insertBefore(lineNumbersWrapper, preElement.firstChild);
    }

    /**
     * Update code block with new content
     * @param {HTMLElement} element - The code element to rehighlight
     * @param {HTMLElement} container - The container element
     * @param {string} languageOrFilename - The language or filename to use
     * @param {string} code - The code content
     * @param {boolean} showLanguage - Whether to show the language label
     * @private
     */
    static updateCodeBlock(element, container, languageOrFilename, code, showLanguage) {
      const cleanedCode = code.trim();
      const withLines =
        container.classList.contains('highlightit-with-lines') ||
        element.dataset.lineStart !== undefined;

      let language = null;
      let displayLabel = languageOrFilename;

      if (languageOrFilename) {
        language = this.getLanguageFromFilename(languageOrFilename) || languageOrFilename;
      }

      try {
        let result;
        try {
          result = language
            ? hljs.highlight(cleanedCode, { language })
            : { value: this.escapeHtml(cleanedCode) };
        } catch (e) {
          console.error(
            `HighlightIt: Error highlighting with language ${language}`,
            e,
            'This might be because highlight.js is not available. Please ensure its script is included in the page.'
          );
          result = { value: this.escapeHtml(cleanedCode) };
        }

        element.innerHTML = result.value;

        if (withLines) {
          const oldLineNumbers = container.querySelector('.highlightit-line-numbers');
          const oldLines = oldLineNumbers
            ? oldLineNumbers.querySelectorAll(
                '.highlightit-line-number-container, .highlightit-line-number'
              )
            : null;

          const lineCount = cleanedCode.split('\n').length;
          const oldLineCount = oldLines ? oldLines.length : 0;

          let lineStart = parseInt(
            element.dataset.lineStart || container.dataset.lineStart || 1,
            10
          );

          const currentBlockId = container.getAttribute('data-original-id') || container.id;
          const withShare =
            container.dataset.withShare !== undefined || element.dataset.withShare !== undefined;

          if (oldLineNumbers) {
            if (lineCount !== oldLineCount) {
              if (lineCount > oldLineCount) {
                const fragment = document.createDocumentFragment();

                for (let i = oldLineCount; i < lineCount; i++) {
                  const lineNumber = lineStart + i;
                  const lineNumberContainer = document.createElement('div');
                  lineNumberContainer.className = 'highlightit-line-number-container';

                  const span = document.createElement('span');
                  span.className = 'highlightit-line-number';
                  span.textContent = lineNumber;

                  if (withShare && currentBlockId) {
                    span.className += ' highlightit-line-number-shareable';

                    const lineShareButton = document.createElement('button');
                    lineShareButton.className = 'highlightit-line-share';
                    lineShareButton.setAttribute('aria-label', `Copy link to line ${lineNumber}`);
                    lineShareButton.innerHTML = cache.svgIcons.link;
                    lineShareButton.dataset.lineNumber = lineNumber;
                    lineShareButton.dataset.blockId = currentBlockId;

                    this.setupLineShareButtonHandler(lineShareButton, container);

                    lineNumberContainer.appendChild(span);
                    lineNumberContainer.appendChild(lineShareButton);
                  } else {
                    lineNumberContainer.appendChild(span);
                  }

                  fragment.appendChild(lineNumberContainer);
                }

                oldLineNumbers.appendChild(fragment);
              } else if (lineCount < oldLineCount) {
                const allLineContainers = oldLineNumbers.querySelectorAll(
                  '.highlightit-line-number-container'
                );
                const lineNumbers = oldLineNumbers.querySelectorAll('.highlightit-line-number');

                for (let i = lineCount; i < oldLineCount; i++) {
                  if (allLineContainers[i]) {
                    oldLineNumbers.removeChild(allLineContainers[i]);
                  } else if (lineNumbers[i]) {
                    oldLineNumbers.removeChild(lineNumbers[i]);
                  }
                }
              }
            }

            const allLineContainers = oldLineNumbers.querySelectorAll(
              '.highlightit-line-number-container'
            );
            const lineNumbers = oldLineNumbers.querySelectorAll('.highlightit-line-number');
            const lineShareButtons = oldLineNumbers.querySelectorAll('.highlightit-line-share');

            for (let i = 0; i < lineCount; i++) {
              const lineNumber = lineStart + i;

              if (allLineContainers[i]) {
                const span = allLineContainers[i].querySelector('.highlightit-line-number');
                if (span) {
                  span.textContent = lineNumber;
                }

                if (withShare && currentBlockId) {
                  const button = allLineContainers[i].querySelector('.highlightit-line-share');
                  if (button) {
                    button.dataset.lineNumber = lineNumber;
                    button.setAttribute('aria-label', `Copy link to line ${lineNumber}`);

                    if (button.dataset.blockId !== currentBlockId) {
                      button.dataset.blockId = currentBlockId;

                      const oldClickListener = button._clickListener;
                      if (oldClickListener) {
                        button.removeEventListener('click', oldClickListener);
                      }

                      this.setupLineShareButtonHandler(button, container);
                    }
                  }
                }
              } else if (lineNumbers[i]) {
                lineNumbers[i].textContent = lineNumber;

                if (withShare && currentBlockId && lineShareButtons[i]) {
                  lineShareButtons[i].dataset.lineNumber = lineNumber;
                  lineShareButtons[i].setAttribute('aria-label', `Copy link to line ${lineNumber}`);

                  if (lineShareButtons[i].dataset.blockId !== currentBlockId) {
                    lineShareButtons[i].dataset.blockId = currentBlockId;

                    const oldClickListener = lineShareButtons[i]._clickListener;
                    if (oldClickListener) {
                      lineShareButtons[i].removeEventListener('click', oldClickListener);
                    }

                    this.setupLineShareButtonHandler(lineShareButtons[i], container);
                  }
                }
              }
            }
          } else {
            this.addLineNumbers(element, cleanedCode);
          }
        }

        const copyButtons = container.querySelectorAll('.highlightit-copy');
        copyButtons.forEach((copyButton) => {
          const currentCode = copyButton._currentCode;

          if (currentCode !== cleanedCode) {
            const clickListener = copyButton.onclickBackup || copyButton.onclick;

            if (clickListener) {
              copyButton.removeEventListener('click', clickListener);
            }

            const newClickListener = async () => {
              const codeToCopy = cleanedCode;
              const success = await polyfills.copyToClipboard(codeToCopy);

              if (success) {
                polyfills.classList.add(copyButton, 'copied');

                const copyIcon = copyButton.querySelector('.highlightit-copy-icon');
                const checkIcon = copyButton.querySelector('.highlightit-check-icon');

                if (copyIcon) copyIcon.style.display = 'none';
                if (checkIcon) checkIcon.style.display = 'block';

                setTimeout(() => {
                  polyfills.classList.remove(copyButton, 'copied');

                  if (copyIcon) copyIcon.style.display = 'block';
                  if (checkIcon) checkIcon.style.display = 'none';
                }, 2000);
              } else {
                console.warn('Failed to copy code');
              }
            };

            copyButton.onclickBackup = newClickListener;
            copyButton._currentCode = cleanedCode;
            copyButton.addEventListener('click', newClickListener);
          }
        });

        const downloadButtons = container.querySelectorAll('.highlightit-download');
        downloadButtons.forEach((downloadButton) => {
          const currentCode = downloadButton._code;

          if (currentCode !== cleanedCode) {
            const clickListener = downloadButton.onclickBackup || downloadButton.onclick;

            if (clickListener) {
              downloadButton.removeEventListener('click', clickListener);
            }

            let filename = container && container.dataset && container.dataset.filename;
            let codeLanguage =
              container.querySelector('code') &&
              (container.querySelector('code').dataset.language ||
                (container.querySelector('code').className.match(/language-(\w+)/) || [])[1]);
            if (!filename) {
              const extension = codeLanguage ? this.getLanguageFileExtension(codeLanguage) : 'txt';
              filename = `code.${extension}`;
            }

            const newClickListener = () => {
              const success = polyfills.downloadFile(filename, cleanedCode.trim());

              if (success) {
                polyfills.classList.add(downloadButton, 'copied');

                const downloadIcon = downloadButton.querySelector('.highlightit-download-icon');
                const checkIcon = downloadButton.querySelector('.highlightit-check-icon');

                if (downloadIcon) downloadIcon.style.display = 'none';
                if (checkIcon) checkIcon.style.display = 'block';

                setTimeout(() => {
                  polyfills.classList.remove(downloadButton, 'copied');

                  if (downloadIcon) downloadIcon.style.display = 'block';
                  if (checkIcon) checkIcon.style.display = 'none';
                }, 2000);
              }
            };

            downloadButton.onclickBackup = newClickListener;
            downloadButton._code = cleanedCode;
            downloadButton.addEventListener('click', newClickListener);
          }
        });

        const shareButtons = container.querySelectorAll('.highlightit-share');
        shareButtons.forEach(async (shareButton) => {
          const originalId = container.getAttribute('data-original-id');

          if (originalId) {
            if (shareButton._currentBlockId !== originalId) {
              shareButton._currentBlockId = originalId;
            }
            return;
          }

          if (container.id) {
            if (shareButton._currentBlockId !== container.id) {
              const clickListener = shareButton.onclickBackup || shareButton.onclick;

              if (clickListener) {
                shareButton.removeEventListener('click', clickListener);
              }

              const newClickListener = async () => {
                const url = new URL(window.location.href);
                url.hash = container.id;

                const success = await polyfills.copyToClipboard(url.toString());

                if (success) {
                  shareButton.classList.add('copied');
                  shareButton.innerHTML = cache.svgIcons.check;

                  setTimeout(() => {
                    shareButton.classList.remove('copied');
                    shareButton.innerHTML = cache.svgIcons.share;
                  }, 2000);
                }
              };

              shareButton.onclickBackup = newClickListener;
              shareButton._currentBlockId = container.id;
              shareButton.addEventListener('click', newClickListener);
            }
            return;
          }

          const blockId = await this.generateHash(cleanedCode);
          container.id = blockId;

          if (shareButton._currentBlockId !== blockId) {
            const clickListener = shareButton.onclickBackup || shareButton.onclick;

            if (clickListener) {
              shareButton.removeEventListener('click', clickListener);
            }

            const newClickListener = async () => {
              const url = new URL(window.location.href);
              url.hash = blockId;

              const success = await polyfills.copyToClipboard(url.toString());

              if (success) {
                shareButton.classList.add('copied');
                shareButton.innerHTML = cache.svgIcons.check;

                setTimeout(() => {
                  shareButton.classList.remove('copied');
                  shareButton.innerHTML = cache.svgIcons.share;
                }, 2000);
              }
            };

            shareButton.onclickBackup = newClickListener;
            shareButton._currentBlockId = blockId;
            shareButton.addEventListener('click', newClickListener);
          }
        });

        const floatingBtnsContainer = container.querySelector('.highlightit-floating-buttons');
        if (floatingBtnsContainer && container.classList.contains('highlightit-no-header')) {
          const floatingCopyBtn = floatingBtnsContainer.querySelector('.highlightit-copy');
          if (floatingCopyBtn) {
            const currentCode = floatingCopyBtn._currentCode;

            if (currentCode !== cleanedCode) {
              const clickListener = floatingCopyBtn.onclick;

              if (clickListener) {
                floatingCopyBtn.removeEventListener('click', clickListener);
              }

              const newClickListener = async () => {
                const success = await polyfills.copyToClipboard(cleanedCode.trim());

                if (success) {
                  polyfills.classList.add(floatingCopyBtn, 'copied');
                  floatingCopyBtn.innerHTML = cache.svgIcons.check;

                  setTimeout(() => {
                    polyfills.classList.remove(floatingCopyBtn, 'copied');
                    floatingCopyBtn.innerHTML = cache.svgIcons.copy;
                  }, 2000);
                }
              };

              floatingCopyBtn._currentCode = cleanedCode;
              floatingCopyBtn.addEventListener('click', newClickListener);
            }
          }

          const floatingDownloadBtn = floatingBtnsContainer.querySelector('.highlightit-download');
          if (floatingDownloadBtn) {
            const currentCode = floatingDownloadBtn._code;

            if (currentCode !== cleanedCode) {
              const clickListener =
                floatingDownloadBtn.onclickBackup || floatingDownloadBtn.onclick;

              if (clickListener) {
                floatingDownloadBtn.removeEventListener('click', clickListener);
              }

              let filename = container && container.dataset && container.dataset.filename;
              let codeLanguage =
                container.querySelector('code') &&
                (container.querySelector('code').dataset.language ||
                  (container.querySelector('code').className.match(/language-(\w+)/) || [])[1]);

              if (!filename) {
                const extension = codeLanguage
                  ? this.getLanguageFileExtension(codeLanguage)
                  : 'txt';
                filename = `code.${extension}`;
              }

              const newClickListener = () => {
                const success = polyfills.downloadFile(filename, cleanedCode.trim());

                if (success) {
                  polyfills.classList.add(floatingDownloadBtn, 'copied');

                  const downloadIcon = floatingDownloadBtn.querySelector(
                    '.highlightit-download-icon'
                  );
                  const checkIcon = floatingDownloadBtn.querySelector('.highlightit-check-icon');

                  if (downloadIcon) downloadIcon.style.display = 'none';
                  if (checkIcon) checkIcon.style.display = 'block';

                  setTimeout(() => {
                    polyfills.classList.remove(floatingDownloadBtn, 'copied');

                    if (downloadIcon) downloadIcon.style.display = 'block';
                    if (checkIcon) checkIcon.style.display = 'none';
                  }, 2000);
                }
              };

              floatingDownloadBtn.onclickBackup = newClickListener;
              floatingDownloadBtn._code = cleanedCode;
              floatingDownloadBtn.addEventListener('click', newClickListener);
            }
          }

          const floatingShareBtn = floatingBtnsContainer.querySelector('.highlightit-share');
          if (floatingShareBtn) {
            const originalId = container.getAttribute('data-original-id');

            if (originalId) {
              if (floatingShareBtn._currentBlockId !== originalId) {
                floatingShareBtn._currentBlockId = originalId;
              }
            } else if (container.id) {
              if (floatingShareBtn._currentBlockId !== container.id) {
                const clickListener = floatingShareBtn.onclick;

                if (clickListener) {
                  floatingShareBtn.removeEventListener('click', clickListener);
                }

                const newClickListener = async () => {
                  const url = new URL(window.location.href);
                  url.hash = container.id;

                  const success = await polyfills.copyToClipboard(url.toString());

                  if (success) {
                    floatingShareBtn.classList.add('copied');
                    floatingShareBtn.innerHTML = cache.svgIcons.check;

                    setTimeout(() => {
                      floatingShareBtn.classList.remove('copied');
                      floatingShareBtn.innerHTML = cache.svgIcons.share;
                    }, 2000);
                  }
                };

                floatingShareBtn._currentBlockId = container.id;
                floatingShareBtn.addEventListener('click', newClickListener);
              }
            } else {
              this.generateHash(cleanedCode).then((blockId) => {
                container.id = blockId;

                if (floatingShareBtn._currentBlockId !== blockId) {
                  const clickListener = floatingShareBtn.onclick;

                  if (clickListener) {
                    floatingShareBtn.removeEventListener('click', clickListener);
                  }

                  const newClickListener = async () => {
                    const url = new URL(window.location.href);
                    url.hash = blockId;

                    const success = await polyfills.copyToClipboard(url.toString());

                    if (success) {
                      floatingShareBtn.classList.add('copied');
                      floatingShareBtn.innerHTML = cache.svgIcons.check;

                      setTimeout(() => {
                        floatingShareBtn.classList.remove('copied');
                        floatingShareBtn.innerHTML = cache.svgIcons.share;
                      }, 2000);
                    }
                  };

                  floatingShareBtn._currentBlockId = blockId;
                  floatingShareBtn.addEventListener('click', newClickListener);
                }
              });
            }
          }
        } else if (
          !floatingBtnsContainer &&
          container.classList.contains('highlightit-no-header')
        ) {
          const withShare = container.dataset.withShare !== undefined;
          const withDownload = container.dataset.withDownload !== undefined;
          const newFloatingBtns = this.createFloatingButtons(
            cleanedCode,
            withShare,
            withDownload,
            container
          );
          container.appendChild(newFloatingBtns);
        }

        if (showLanguage && language) {
          const header = container.querySelector('.highlightit-header');
          if (header) {
            const languageLabel = header.querySelector('.highlightit-language');
            if (languageLabel) {
              languageLabel.textContent = displayLabel || language;
            } else if (language) {
              const newLanguageLabel = document.createElement('span');
              newLanguageLabel.className = 'highlightit-language';
              newLanguageLabel.textContent = displayLabel || language;
              header.insertBefore(newLanguageLabel, header.firstChild);
            }
          }
        }
      } catch (error) {
        console.warn(`HighlightIt: Error highlighting with language ${language}`, error);
        element.innerHTML = this.escapeHtml(cleanedCode);
      }
    }

    /**
     * Setup a click handler for line share buttons
     * @param {HTMLElement} button - The line share button
     * @param {HTMLElement} container - The container element
     */
    static setupLineShareButtonHandler(button, container) {
      const clickListener = async (e) => {
        e.stopPropagation();

        const currentBlockId = container.getAttribute('data-original-id') || container.id;
        const lineNumber = button.dataset.lineNumber;
        const url = new URL(window.location.href);
        url.hash = `${currentBlockId}_${lineNumber}`;

        const success = await polyfills.copyToClipboard(url.toString());

        if (success) {
          button.classList.add('copied');
          button.innerHTML = cache.svgIcons.check;

          const containerElement = button.closest('.highlightit-line-number-container');
          if (containerElement) {
            containerElement.classList.add('has-copied-button');
            polyfills.updateHasClass(
              containerElement,
              '.highlightit-line-share.copied',
              'has-copied-button',
              true
            );
          }

          setTimeout(() => {
            button.classList.remove('copied');
            button.innerHTML = cache.svgIcons.link;

            if (containerElement) {
              containerElement.classList.remove('has-copied-button');
              polyfills.updateHasClass(
                containerElement,
                '.highlightit-line-share.copied',
                'has-copied-button',
                false
              );
            }
          }, 2000);
        }
      };

      button._clickListener = clickListener;
      button.addEventListener('click', clickListener);
    }

    /**
     * Find the original element for a live-updated element
     * @param {HTMLElement} element - The element to find the original for
     * @param {HTMLElement} container - The container element
     * @returns {HTMLElement|null} - The original element or null if not found
     * @private
     */
    static findOriginalElement(element, container) {
      const linkedId =
        (element.parentElement &&
          element.parentElement.dataset &&
          element.parentElement.dataset.linkedOriginal) ||
        (container && container.dataset && container.dataset.linkedOriginal) ||
        (element.parentElement && element.parentElement.getAttribute('data-linked-original')) ||
        (container && container.getAttribute('data-linked-original'));

      if (linkedId) {
        const originalElement = document.querySelector(
          `.highlightit-original[data-highlightit-id="${linkedId}"]`
        );
        if (originalElement) {
          return originalElement;
        }
      }

      const originalId =
        (element.parentElement && element.parentElement.getAttribute('data-original-id')) ||
        (container && container.getAttribute('data-original-id'));

      if (originalId) {
        const idElement = document.getElementById(originalId);
        if (idElement) {
          return idElement;
        }
      }

      if (
        container &&
        container.previousSibling &&
        container.previousSibling.classList &&
        container.previousSibling.classList.contains('highlightit-original')
      ) {
        return container.previousSibling;
      }

      return null;
    }

    /**
     * Initialize the share functionality
     */
    static initSharing() {
      setTimeout(() => {
        this.scrollToAnchor();
      }, 100);

      window.addEventListener('hashchange', () => {
        this.scrollToAnchor();
      });
    }

    /**
     * Get file extension from language name
     * @param {string} language - The language to convert to file extension
     * @returns {string} - The file extension for the language
     * @private
     */
    static getLanguageFileExtension(language) {
      if (!language) return 'txt';

      for (const [ext, lang] of cache.extensionMap.entries()) {
        if (lang === language.toLowerCase()) {
          return ext;
        }
      }

      return language.toLowerCase();
    }
  }

  if (typeof window !== 'undefined') {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => HighlightIt.initSharing());
    } else {
      HighlightIt.initSharing();
    }
  }

  /**
   * Highlight a new element that wasn't present when the library was initialized
   * @param {HTMLElement} element - The element to highlight
   * @param {Object} options - Configuration options
   * @param {boolean} [options.autoDetect=true] - Whether to auto-detect language if not specified
   * @param {boolean} [options.addCopyButton=true] - Whether to add a copy button
   * @param {boolean} [options.showLanguage=true] - Whether to show the language label
   * @param {boolean} [options.addHeader=true] - Whether to add a header section
   * @param {boolean} [options.addLines=false] - Whether to add line numbers
   * @param {boolean} [options.withReload=false] - Whether to enable live updates
   * @param {boolean} [options.addShare=false] - Whether to add a share button
   * @param {boolean} [options.addDownload=false] - Whether to add a download button
   * @param {string} [options.filename] - The filename to use for the download button
   * @param {string} [options.language] - The language to use for syntax highlighting
   * @param {string} [options.theme] - Theme override for this element ('light', 'dark', or 'auto')
   * @param {number} [options.lineStart] - Starting line number (default is 1, can be positive or negative)
   * @returns {HTMLElement} - The highlighted element container
   */
  HighlightIt.highlight = function (element, options = {}) {
    if (
      !element ||
      element.classList.contains('highlightit-original') ||
      element.closest('.highlightit-container') ||
      (element.parentElement && element.parentElement.classList.contains('highlightit-container'))
    ) {
      console.warn('HighlightIt: Element is already highlighted or is a hidden original element');
      return element;
    }

    const {
      autoDetect = true,
      addCopyButton = true,
      showLanguage = true,
      addHeader = true,
      addLines = false,
      withReload = false,
      addShare = false,
      addDownload = false,
      filename,
      language,
      theme,
      lineStart,
    } = options;

    if (addLines) {
      element.dataset.withLines = '';
    }

    if (lineStart !== undefined) {
      element.dataset.lineStart = lineStart;
    }

    if (withReload) {
      element.dataset.withReload = '';
    }

    if (!addHeader) {
      element.dataset.noHeader = '';
    }

    if (!addCopyButton) {
      element.dataset.noCopy = '';
    }

    if (addShare) {
      element.dataset.withShare = '';
    }

    if (addDownload) {
      element.dataset.withDownload = '';
    }

    if (filename) {
      element.dataset.filename = filename;
    }

    if (language) {
      element.dataset.language = language;
    }

    if (theme) {
      element.dataset.theme = theme;
    }

    this.processElement(
      element,
      autoDetect,
      addCopyButton,
      showLanguage,
      addHeader,
      addLines,
      addShare,
      addDownload
    );

    const container =
      element.closest('.highlightit-container') ||
      (element.parentElement && element.parentElement.closest('.highlightit-container'));

    return container || element;
  };

  global.HighlightIt = HighlightIt;

  if (typeof window !== 'undefined') {
    window.HighlightIt = HighlightIt;

    injectCSS(STYLES_CSS);
  }
})(typeof window !== 'undefined' ? window : this);