{"version":3,"sources":["jsdelivr-header.js","/npm/pangu@7.2.0/src/shared/index.ts","/npm/pangu@7.2.0/src/browser/dom-walker.ts","/npm/pangu@7.2.0/src/browser/task-scheduler.ts","/npm/pangu@7.2.0/src/browser/visibility-detector.ts","/npm/pangu@7.2.0/src/browser/pangu.ts","/npm/pangu@7.2.0/src/browser/pangu.umd.ts"],"names":[],"mappings":"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","file":"/npm/pangu@7.2.0/dist/browser/pangu.umd.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/pangu@7.2.0/dist/browser/pangu.umd.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","// CJK is short for Chinese, Japanese, and Korean:\n// \\u2e80-\\u2eff CJK Radicals Supplement\n// \\u2f00-\\u2fdf Kangxi Radicals\n// \\u3040-\\u309f Hiragana\n// \\u30a0-\\u30ff Katakana\n// \\u3100-\\u312f Bopomofo\n// \\u3200-\\u32ff Enclosed CJK Letters and Months\n// \\u3400-\\u4dbf CJK Unified Ideographs Extension A\n// \\u4e00-\\u9fff CJK Unified Ideographs\n// \\uf900-\\ufaff CJK Compatibility Ideographs\n//\n// ANS is short for Alphabets, Numbers, and Symbols:\n// A includes A-Za-z\\u0370-\\u03ff\n// N includes 0-9\n// S includes `~!@#$%^&*()-_=+[]{}\\|;:'\",<.>/?\n//\n// All J below does not include \\u30fb\n// Some S below does not include all symbols\n//\n// For more information about Unicode blocks, see\n// https://symbl.cc/en/unicode-table/\n\nconst CJK = '\\u2e80-\\u2eff\\u2f00-\\u2fdf\\u3040-\\u309f\\u30a0-\\u30fa\\u30fc-\\u30ff\\u3100-\\u312f\\u3200-\\u32ff\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff';\n\n// Basic character classes\nconst AN = 'A-Za-z0-9';\nconst A = 'A-Za-z';\nconst UPPER_AN = 'A-Z0-9'; // For FIX_CJK_COLON_ANS\n\n// Operators - note the different sets!\nconst OPERATORS_BASE = '\\\\+\\\\*=&';\nconst OPERATORS_WITH_HYPHEN = `${OPERATORS_BASE}\\\\-`; // For CJK patterns\nconst OPERATORS_NO_HYPHEN = OPERATORS_BASE; // For ANS_OPERATOR_ANS only\nconst GRADE_OPERATORS = '\\\\+\\\\-\\\\*'; // For single letter grades\n\n// Quotes\nconst QUOTES = '\\`\"\\u05f4'; // Backtick, straight quote, Hebrew punctuation\n\n// Brackets - different sets!\nconst LEFT_BRACKETS_BASIC = '\\\\(\\\\[\\\\{'; // For AN_LEFT_BRACKET\nconst RIGHT_BRACKETS_BASIC = '\\\\)\\\\]\\\\}'; // For RIGHT_BRACKET_AN\nconst LEFT_BRACKETS_EXTENDED = '\\\\(\\\\[\\\\{<>\\u201c'; // For CJK_LEFT_BRACKET (includes angle brackets + curly quote)\nconst RIGHT_BRACKETS_EXTENDED = '\\\\)\\\\]\\\\}<>\\u201d'; // For RIGHT_BRACKET_CJK\n\n// ANS extended sets - CAREFUL: different symbols!\nconst ANS_CJK_AFTER = `${A}\\u0370-\\u03ff0-9@\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=\\u00a1-\\u00ff\\u2150-\\u218f\\u2700—\\u27bf`; // Has @, no punctuation\nconst ANS_BEFORE_CJK = `${A}\\u0370-\\u03ff0-9\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=\\u00a1-\\u00ff\\u2150-\\u218f\\u2700—\\u27bf`; // No @ symbol\n\n// File path components - common directories in Unix/project paths\n// prettier-ignore\nconst FILE_PATH_DIRS = 'home|root|usr|etc|var|opt|tmp|dev|mnt|proc|sys|bin|boot|lib|media|run|sbin|srv|node_modules|path|project|src|dist|test|tests|docs|templates|assets|public|static|config|scripts|tools|build|out|target|your|\\\\.claude|\\\\.git|\\\\.vscode';\nconst FILE_PATH_CHARS = '[A-Za-z0-9_\\\\-\\\\.@\\\\+\\\\*]+';\n\n// Unix absolute paths: system dirs + common project paths\n// Examples: /home, /usr/bin, /etc/nginx.conf, /.bashrc, /node_modules/@babel/core, /path/to/your/project\nconst UNIX_ABSOLUTE_FILE_PATH = new RegExp(`/(?:\\\\.?(?:${FILE_PATH_DIRS})|\\\\.(?:[A-Za-z0-9_\\\\-]+))(?:/${FILE_PATH_CHARS})*`);\n\n// Unix relative paths common in documentation and blog posts\n// Examples: src/main.py, dist/index.js, test/spec.js, ./.claude/CLAUDE.md, templates/*.html\nconst UNIX_RELATIVE_FILE_PATH = new RegExp(`(?:\\\\./)?(?:${FILE_PATH_DIRS})(?:/${FILE_PATH_CHARS})+`);\n\n// Windows paths: C:\\Users\\name\\, D:\\Program Files\\, C:\\Windows\\System32\nconst WINDOWS_FILE_PATH = /[A-Z]:\\\\(?:[A-Za-z0-9_\\-\\. ]+\\\\?)+/;\n\nconst ANY_CJK = new RegExp(`[${CJK}]`);\n\n// Handle punctuation after CJK - add space but don't convert to full-width\n// Support multiple consecutive punctuation marks\n// Only add space if followed by CJK, letters, or numbers (not at end of text or before same punctuation)\nconst CJK_PUNCTUATION = new RegExp(`([${CJK}])([!;,\\\\?:]+)(?=[${CJK}${AN}])`, 'g');\n// Handle punctuation between AN and CJK - add space after punctuation\nconst AN_PUNCTUATION_CJK = new RegExp(`([${AN}])([!;,\\\\?]+)([${CJK}])`, 'g');\n// Handle tilde separately for special cases like ~=\n// Only add space if followed by CJK, letters, or numbers (not at end of text)\nconst CJK_TILDE = new RegExp(`([${CJK}])(~+)(?!=)(?=[${CJK}${AN}])`, 'g');\nconst CJK_TILDE_EQUALS = new RegExp(`([${CJK}])(~=)`, 'g');\n// Handle period separately to avoid matching file extensions, multiple dots, and file paths\n// Note: Multiple dots are handled by DOTS_CJK pattern first\n// Only add space if followed by CJK, letters, or numbers (not at end of text)\nconst CJK_PERIOD = new RegExp(`([${CJK}])(\\\\.)(?![${AN}\\\\./])(?=[${CJK}${AN}])`, 'g');\n// Handle period between AN and CJK - avoid file extensions\nconst AN_PERIOD_CJK = new RegExp(`([${AN}])(\\\\.)([${CJK}])`, 'g');\n// Handle colon between AN and CJK\nconst AN_COLON_CJK = new RegExp(`([${AN}])(:)([${CJK}])`, 'g');\nconst DOTS_CJK = new RegExp(`([\\\\.]{2,}|\\u2026)([${CJK}])`, 'g');\n// Special case for colon before uppercase letters/parentheses (convert to full-width)\nconst FIX_CJK_COLON_ANS = new RegExp(`([${CJK}])\\\\:([${UPPER_AN}\\\\(\\\\)])`, 'g');\n\n// The symbol part does not include '\nconst CJK_QUOTE = new RegExp(`([${CJK}])([${QUOTES}])`, 'g');\nconst QUOTE_CJK = new RegExp(`([${QUOTES}])([${CJK}])`, 'g');\nconst FIX_QUOTE_ANY_QUOTE = new RegExp(`([${QUOTES}]+)[ ]*(.+?)[ ]*([${QUOTES}]+)`, 'g');\n\n// Handle curly quotes with alphanumeric characters\n// These patterns should only apply to curly quotes, not straight quotes\n// Straight quotes are already handled by CJK_QUOTE, QUOTE_CJK and FIX_QUOTE_ANY_QUOTE\nconst QUOTE_AN = new RegExp(`([\\u201d])([${AN}])`, 'g'); // Only closing curly quotes + AN\n\n// Special handling for straight quotes followed by alphanumeric after CJK\n// This catches patterns like: 中文\"ABC where the quote appears to be closing a quoted CJK phrase\nconst CJK_QUOTE_AN = new RegExp(`([${CJK}])(\")([${AN}])`, 'g');\n\nconst CJK_SINGLE_QUOTE_BUT_POSSESSIVE = new RegExp(`([${CJK}])('[^s])`, 'g');\nconst SINGLE_QUOTE_CJK = new RegExp(`(')([${CJK}])`, 'g');\nconst FIX_POSSESSIVE_SINGLE_QUOTE = new RegExp(`([${AN}${CJK}])( )('s)`, 'g');\n\nconst HASH_ANS_CJK_HASH = new RegExp(`([${CJK}])(#)([${CJK}]+)(#)([${CJK}])`, 'g');\nconst CJK_HASH = new RegExp(`([${CJK}])(#([^ ]))`, 'g');\nconst HASH_CJK = new RegExp(`(([^ ])#)([${CJK}])`, 'g');\n\n// The symbol part only includes + - * = & (excluding | / < >)\nconst CJK_OPERATOR_ANS = new RegExp(`([${CJK}])([${OPERATORS_WITH_HYPHEN}])([${AN}])`, 'g');\nconst ANS_OPERATOR_CJK = new RegExp(`([${AN}])([${OPERATORS_WITH_HYPHEN}])([${CJK}])`, 'g');\n// Handle operators between alphanumeric characters when CJK is present in text\n// Note: This pattern excludes hyphens entirely (only + * = &) to avoid conflicts with compound words\nconst ANS_OPERATOR_ANS = new RegExp(`([${AN}])([${OPERATORS_NO_HYPHEN}])([${AN}])`, 'g');\n\n// Hyphens that should be treated as operators (with spaces) rather than word connectors\n// This regex has 3 patterns to catch different cases while preserving compound words:\n// 1. Letter-Letter/Number: A-B, X-5 (spaces added) BUT NOT co-author, X-ray, GPT-5 (preserved)\n// 2. Mixed alphanumeric-number patterns that aren't already protected as compound words\n// 3. Number-Letter: 5-A, 3-B (spaces added) BUT NOT 5-year, 2016-12-26 (preserved)\n// Note: Patterns like GPT4-5, v1-2 are protected by COMPOUND_WORD_PATTERN and won't get spaces\n// The negative lookahead (?![a-z]) prevents matching hyphens followed by lowercase letters\nconst ANS_HYPHEN_ANS_NOT_COMPOUND = new RegExp(`([A-Za-z])(-(?![a-z]))([A-Za-z0-9])|([A-Za-z]+[0-9]+)(-(?![a-z]))([0-9])|([0-9])(-(?![a-z0-9]))([A-Za-z])`, 'g');\n\n// Slash patterns for operator vs separator behavior\nconst CJK_SLASH_CJK = new RegExp(`([${CJK}])([/])([${CJK}])`, 'g');\nconst CJK_SLASH_ANS = new RegExp(`([${CJK}])([/])([${AN}])`, 'g');\nconst ANS_SLASH_CJK = new RegExp(`([${AN}])([/])([${CJK}])`, 'g');\nconst ANS_SLASH_ANS = new RegExp(`([${AN}])([/])([${AN}])`, 'g');\n\n// Special handling for single letter grades/ratings (A+, B-, C*) before CJK\n// These should have space after the operator, not before\n// Use word boundary to ensure it's a single letter, not part of a longer word\nconst SINGLE_LETTER_GRADE_CJK = new RegExp(`\\\\b([${A}])([${GRADE_OPERATORS}])([${CJK}])`, 'g');\n\n// Special handling for < and > as comparison operators (not brackets)\nconst CJK_LESS_THAN = new RegExp(`([${CJK}])(<)([${AN}])`, 'g');\nconst LESS_THAN_CJK = new RegExp(`([${AN}])(<)([${CJK}])`, 'g');\nconst CJK_GREATER_THAN = new RegExp(`([${CJK}])(>)([${AN}])`, 'g');\nconst GREATER_THAN_CJK = new RegExp(`([${AN}])(>)([${CJK}])`, 'g');\n// Handle < and > between alphanumeric characters when CJK is present in text\nconst ANS_LESS_THAN_ANS = new RegExp(`([${AN}])(<)([${AN}])`, 'g');\nconst ANS_GREATER_THAN_ANS = new RegExp(`([${AN}])(>)([${AN}])`, 'g');\n\n// Bracket patterns: ( ) [ ] { } and also < > (though < > are also handled as operators separately)\n// Note: The curly quotes “ ” (\\u201c \\u201d) appear in CJK_LEFT_BRACKET/RIGHT_BRACKET_CJK but are primarily handled in the patterns below\nconst CJK_LEFT_BRACKET = new RegExp(`([${CJK}])([${LEFT_BRACKETS_EXTENDED}])`, 'g');\nconst RIGHT_BRACKET_CJK = new RegExp(`([${RIGHT_BRACKETS_EXTENDED}])([${CJK}])`, 'g');\nconst ANS_CJK_LEFT_BRACKET_ANY_RIGHT_BRACKET = new RegExp(`([${AN}${CJK}])[ ]*([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])`, 'g');\nconst LEFT_BRACKET_ANY_RIGHT_BRACKET_ANS_CJK = new RegExp(`([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])[ ]*([${AN}${CJK}])`, 'g');\n\nconst AN_LEFT_BRACKET = new RegExp(`([${AN}])(?<!\\\\.[${AN}]*)([${LEFT_BRACKETS_BASIC}])`, 'g');\nconst RIGHT_BRACKET_AN = new RegExp(`([${RIGHT_BRACKETS_BASIC}])([${AN}])`, 'g');\n\n// Special patterns for filesystem paths after CJK\nconst CJK_UNIX_ABSOLUTE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_ABSOLUTE_FILE_PATH.source})`, 'g');\nconst CJK_UNIX_RELATIVE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_RELATIVE_FILE_PATH.source})`, 'g');\nconst CJK_WINDOWS_PATH = new RegExp(`([${CJK}])(${WINDOWS_FILE_PATH.source})`, 'g');\n\n// Pattern for Unix paths ending with / followed by CJK\nconst UNIX_ABSOLUTE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_ABSOLUTE_FILE_PATH.source}/)([${CJK}])`, 'g');\nconst UNIX_RELATIVE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_RELATIVE_FILE_PATH.source}/)([${CJK}])`, 'g');\n\nconst CJK_ANS = new RegExp(`([${CJK}])([${ANS_CJK_AFTER}])`, 'g');\nconst ANS_CJK = new RegExp(`([${ANS_BEFORE_CJK}])([${CJK}])`, 'g');\n\nconst S_A = new RegExp(`(%)([${A}])`, 'g');\n\nconst MIDDLE_DOT = /([ ]*)([\\u00b7\\u2022\\u2027])([ ]*)/g;\n\nclass PlaceholderReplacer {\n  private items: string[] = [];\n  private index = 0;\n  private pattern: RegExp;\n\n  constructor(\n    private placeholder: string,\n    private startDelimiter: string,\n    private endDelimiter: string,\n  ) {\n    const escapedStart = this.startDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n    const escapedEnd = this.endDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n    this.pattern = new RegExp(`${escapedStart}${this.placeholder}(\\\\d+)${escapedEnd}`, 'g');\n  }\n\n  store(item: string) {\n    this.items[this.index] = item;\n    return `${this.startDelimiter}${this.placeholder}${this.index++}${this.endDelimiter}`;\n  }\n\n  restore(text: string) {\n    return text.replace(this.pattern, (_match, index) => {\n      return this.items[parseInt(index, 10)] || '';\n    });\n  }\n\n  reset() {\n    this.items = [];\n    this.index = 0;\n  }\n}\n\nexport class Pangu {\n  version: string;\n\n  constructor() {\n    this.version = '7.2.0';\n  }\n\n  public spacingText(text: string) {\n    if (typeof text !== 'string') {\n      console.warn(`spacingText(text) only accepts string but got ${typeof text}`);\n      return text;\n    }\n\n    if (text.length <= 1 || !ANY_CJK.test(text)) {\n      return text;\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    const self = this;\n\n    let newText = text;\n\n    // Protect backtick content from quote processing but allow spacing around backticks\n    const backtickManager = new PlaceholderReplacer('BACKTICK_CONTENT_', '\\uE004', '\\uE005');\n    newText = newText.replace(/`([^`]+)`/g, (_match, content) => {\n      return `\\`${backtickManager.store(content)}\\``;\n    });\n\n    // Initialize placeholder managers\n    const htmlTagManager = new PlaceholderReplacer('HTML_TAG_PLACEHOLDER_', '\\uE000', '\\uE001');\n    let hasHtmlTags = false;\n\n    // Early return for HTML processing if no HTML tags present\n    if (newText.includes('<')) {\n      hasHtmlTags = true;\n      // More specific HTML tag pattern:\n      // - Opening tags: <tagname ...> or <tagname>\n      // - Closing tags: </tagname>\n      // - Self-closing tags: <tagname ... />\n      // This pattern ensures we only match actual HTML tags, not just any < > content\n      const HTML_TAG_PATTERN = /<\\/?[a-zA-Z][a-zA-Z0-9]*(?:\\s+[^>]*)?>/g;\n\n      // Replace all HTML tags with placeholders, but process attribute values\n      newText = newText.replace(HTML_TAG_PATTERN, (match) => {\n        // Process attribute values inside the tag\n        const processedTag = match.replace(/(\\w+)=\"([^\"]*)\"/g, (_attrMatch, attrName, attrValue) => {\n          // Process the attribute value with spacing\n          const processedValue = self.spacingText(attrValue);\n          return `${attrName}=\"${processedValue}\"`;\n        });\n\n        return htmlTagManager.store(processedTag);\n      });\n    }\n\n    // Handle multiple dots first (before single period)\n    newText = newText.replace(DOTS_CJK, '$1 $2');\n\n    // Handle punctuation after CJK - add space but don't convert to full-width\n    newText = newText.replace(CJK_PUNCTUATION, '$1$2 ');\n    // Handle punctuation between AN and CJK\n    newText = newText.replace(AN_PUNCTUATION_CJK, '$1$2 $3');\n    // Handle tilde separately for special cases\n    newText = newText.replace(CJK_TILDE, '$1$2 ');\n    newText = newText.replace(CJK_TILDE_EQUALS, '$1 $2 ');\n    // Handle period separately to avoid file extensions\n    newText = newText.replace(CJK_PERIOD, '$1$2 ');\n    newText = newText.replace(AN_PERIOD_CJK, '$1$2 $3');\n    // Handle colon between AN and CJK\n    newText = newText.replace(AN_COLON_CJK, '$1$2 $3');\n    // Only convert colon to full-width in specific cases (before uppercase/parentheses)\n    newText = newText.replace(FIX_CJK_COLON_ANS, '$1：$2');\n\n    newText = newText.replace(CJK_QUOTE, '$1 $2');\n    newText = newText.replace(QUOTE_CJK, '$1 $2');\n    newText = newText.replace(FIX_QUOTE_ANY_QUOTE, '$1$2$3');\n\n    // Handle quotes with alphanumeric - closing quotes followed by AN need space\n    newText = newText.replace(QUOTE_AN, '$1 $2');\n    // Opening quotes preceded by AN don't need space (they're handled by other patterns)\n\n    // Handle CJK followed by closing quote followed by alphanumeric\n    newText = newText.replace(CJK_QUOTE_AN, '$1$2 $3');\n\n    // Handle single quotes more intelligently\n    // First, handle possessive case\n    newText = newText.replace(FIX_POSSESSIVE_SINGLE_QUOTE, \"$1's\");\n\n    // Process single quotes around pure CJK text differently from mixed content\n    const singleQuoteCJKManager = new PlaceholderReplacer('SINGLE_QUOTE_CJK_PLACEHOLDER_', '\\uE030', '\\uE031');\n\n    // Pattern to match single quotes around pure CJK text (no spaces, no other characters)\n    const SINGLE_QUOTE_PURE_CJK = new RegExp(`(')([${CJK}]+)(')`, 'g');\n\n    // Protect pure CJK content in single quotes\n    newText = newText.replace(SINGLE_QUOTE_PURE_CJK, (match) => {\n      return singleQuoteCJKManager.store(match);\n    });\n\n    // Now process other single quote patterns\n    newText = newText.replace(CJK_SINGLE_QUOTE_BUT_POSSESSIVE, '$1 $2');\n    newText = newText.replace(SINGLE_QUOTE_CJK, '$1 $2');\n\n    // Restore protected pure CJK content\n    newText = singleQuoteCJKManager.restore(newText);\n\n    // Early return for complex patterns that need longer text\n    const textLength = newText.length;\n\n    // Check slash count early to determine hashtag behavior\n    const slashCount = (newText.match(/\\//g) || []).length;\n\n    // Early return for slash processing if no slashes present\n    if (slashCount === 0) {\n      // Apply normal hashtag spacing without slash considerations\n      // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n      if (textLength >= 5) {\n        newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n      }\n      newText = newText.replace(CJK_HASH, '$1 $2');\n      newText = newText.replace(HASH_CJK, '$1 $3');\n    } else if (slashCount <= 1) {\n      // Single or no slash - apply normal hashtag spacing\n      // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n      if (textLength >= 5) {\n        newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n      }\n      newText = newText.replace(CJK_HASH, '$1 $2');\n      newText = newText.replace(HASH_CJK, '$1 $3');\n    } else {\n      // Multiple slashes - skip hashtag processing to preserve path structure\n      // But add space before final hashtag if it's not preceded by a slash\n      // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n      if (textLength >= 5) {\n        newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n      }\n      newText = newText.replace(new RegExp(`([^/])([${CJK}])(#[A-Za-z0-9]+)$`), '$1$2 $3');\n    }\n\n    // Protect compound words from operator spacing\n    const compoundWordManager = new PlaceholderReplacer('COMPOUND_WORD_PLACEHOLDER_', '\\uE010', '\\uE011');\n\n    // Pattern to detect compound words: alphanumeric-alphanumeric combinations that look like compound words/product names\n    // Examples: state-of-the-art, machine-learning, GPT-4o, real-time, end-to-end, gpt-4o, GPT-5, claude-4-opus\n    // Match: word-word(s) where at least one part contains lowercase letters OR contains mix of letters and numbers (like GPT-5)\n    const COMPOUND_WORD_PATTERN = /\\b(?:[A-Za-z0-9]*[a-z][A-Za-z0-9]*-[A-Za-z0-9]+|[A-Za-z0-9]+-[A-Za-z0-9]*[a-z][A-Za-z0-9]*|[A-Za-z]+-[0-9]+|[A-Za-z]+[0-9]+-[A-Za-z0-9]+)(?:-[A-Za-z0-9]+)*\\b/g;\n\n    // Store compound words and replace with placeholders\n    newText = newText.replace(COMPOUND_WORD_PATTERN, (match) => {\n      return compoundWordManager.store(match);\n    });\n\n    // Handle single letter grades (A+, B-, etc.) before general operator rules\n    // This ensures \"A+的\" becomes \"A+ 的\" not \"A + 的\"\n    newText = newText.replace(SINGLE_LETTER_GRADE_CJK, '$1$2 $3');\n\n    newText = newText.replace(CJK_OPERATOR_ANS, '$1 $2 $3');\n    newText = newText.replace(ANS_OPERATOR_CJK, '$1 $2 $3');\n    newText = newText.replace(ANS_OPERATOR_ANS, '$1 $2 $3');\n    newText = newText.replace(ANS_HYPHEN_ANS_NOT_COMPOUND, (match, ...groups) => {\n      // Handle all patterns in the alternation\n      if (groups[0] && groups[1] && groups[2]) {\n        // First pattern: letter-alphanumeric\n        return `${groups[0]} ${groups[1]} ${groups[2]}`;\n      } else if (groups[3] && groups[4] && groups[5]) {\n        // Second pattern: version range (letter+number-number)\n        return `${groups[3]} ${groups[4]} ${groups[5]}`;\n      } else if (groups[6] && groups[7] && groups[8]) {\n        // Third pattern: number-letter\n        return `${groups[6]} ${groups[7]} ${groups[8]}`;\n      }\n      return match;\n    });\n\n    // Handle < and > as comparison operators\n    newText = newText.replace(CJK_LESS_THAN, '$1 $2 $3');\n    newText = newText.replace(LESS_THAN_CJK, '$1 $2 $3');\n    newText = newText.replace(ANS_LESS_THAN_ANS, '$1 $2 $3');\n    newText = newText.replace(CJK_GREATER_THAN, '$1 $2 $3');\n    newText = newText.replace(GREATER_THAN_CJK, '$1 $2 $3');\n    newText = newText.replace(ANS_GREATER_THAN_ANS, '$1 $2 $3');\n\n    // Add space before filesystem paths after CJK\n    newText = newText.replace(CJK_UNIX_ABSOLUTE_FILE_PATH, '$1 $2');\n    newText = newText.replace(CJK_UNIX_RELATIVE_FILE_PATH, '$1 $2');\n    newText = newText.replace(CJK_WINDOWS_PATH, '$1 $2');\n\n    // Add space after Unix paths ending with / before CJK\n    newText = newText.replace(UNIX_ABSOLUTE_FILE_PATH_SLASH_CJK, '$1 $2');\n    newText = newText.replace(UNIX_RELATIVE_FILE_PATH_SLASH_CJK, '$1 $2');\n\n    // Context-aware slash handling: single slash = operator, multiple slashes = separator\n    // But exclude slashes that are part of file paths by protecting them first\n    if (slashCount === 1) {\n      // Temporarily protect file paths from slash operator processing\n      const filePathManager = new PlaceholderReplacer('FILE_PATH_PLACEHOLDER_', '\\uE020', '\\uE021');\n\n      // Store all file paths and replace with placeholders\n      const allFilePathPattern = new RegExp(`(${UNIX_ABSOLUTE_FILE_PATH.source}|${UNIX_RELATIVE_FILE_PATH.source})`, 'g');\n      newText = newText.replace(allFilePathPattern, (match) => {\n        return filePathManager.store(match);\n      });\n\n      // Now apply slash operator spacing\n      newText = newText.replace(CJK_SLASH_CJK, '$1 $2 $3');\n      newText = newText.replace(CJK_SLASH_ANS, '$1 $2 $3');\n      newText = newText.replace(ANS_SLASH_CJK, '$1 $2 $3');\n      newText = newText.replace(ANS_SLASH_ANS, '$1 $2 $3');\n\n      // Restore file paths\n      newText = filePathManager.restore(newText);\n    }\n    // If multiple slashes, treat as separator - do nothing (no spaces)\n\n    // Restore compound words from placeholders\n    newText = compoundWordManager.restore(newText);\n\n    newText = newText.replace(CJK_LEFT_BRACKET, '$1 $2');\n    newText = newText.replace(RIGHT_BRACKET_CJK, '$1 $2');\n    newText = newText.replace(ANS_CJK_LEFT_BRACKET_ANY_RIGHT_BRACKET, '$1 $2$3$4');\n    newText = newText.replace(LEFT_BRACKET_ANY_RIGHT_BRACKET_ANS_CJK, '$1$2$3 $4');\n\n    newText = newText.replace(AN_LEFT_BRACKET, '$1 $2');\n    newText = newText.replace(RIGHT_BRACKET_AN, '$1 $2');\n\n    newText = newText.replace(CJK_ANS, '$1 $2');\n    newText = newText.replace(ANS_CJK, '$1 $2');\n\n    newText = newText.replace(S_A, '$1 $2');\n\n    newText = newText.replace(MIDDLE_DOT, '・');\n\n    // Brackets: <fcontentl> (fcontentl) [fcontentl] {fcontentl}\n    // f: the first character inside the brackets\n    // l: the last character inside the brackets\n    // content: the content inside the brackets but exclude the first and last characters\n    // DO NOT change the first and last characters inside brackets AT ALL\n    // ONLY spacing the content between them\n\n    // Fix spacing inside brackets according to the above rules:\n    // Ensure no unwanted spaces immediately after opening or before closing brackets\n    const fixBracketSpacing = (text: string) => {\n      // Process all bracket types at once\n      const bracketPatterns = [\n        { pattern: /<([^<>]*)>/g, open: '<', close: '>' },\n        { pattern: /\\(([^()]*)\\)/g, open: '(', close: ')' },\n        { pattern: /\\[([^\\[\\]]*)\\]/g, open: '[', close: ']' },\n        { pattern: /\\{([^{}]*)\\}/g, open: '{', close: '}' },\n      ];\n\n      for (const { pattern, open, close } of bracketPatterns) {\n        text = text.replace(pattern, (_match, innerContent) => {\n          if (!innerContent) {\n            return `${open}${close}`;\n          }\n          // Remove spaces at the very beginning and end of content\n          const trimmedContent = innerContent.replace(/^ +| +$/g, '');\n          return `${open}${trimmedContent}${close}`;\n        });\n      }\n\n      return text;\n    };\n\n    newText = fixBracketSpacing(newText);\n\n    // Restore HTML tags from placeholders (only if HTML processing occurred)\n    if (hasHtmlTags) {\n      newText = htmlTagManager.restore(newText);\n    }\n\n    // Restore backtick content\n    newText = backtickManager.restore(newText);\n\n    // TODO:\n    // Final fix for HTML comments: ensure no space after <!--\n    // This is needed because <!-- is not protected as an HTML tag\n    // and the ! character gets spaced by ANS_CJK pattern\n    // newText = newText.replace(/<!--\\s+/g, '<!--');\n\n    return newText;\n  }\n\n  public hasProperSpacing(text: string) {\n    return this.spacingText(text) === text;\n  }\n}\n\nexport const pangu = new Pangu();\n\nexport { ANY_CJK };\n\nexport default pangu;\n","export class DomWalker {\n  public static readonly blockTags = /^(div|p|h1|h2|h3|h4|h5|h6)$/i;\n  public static readonly ignoredTags = /^(code|pre|script|style|textarea|iframe|input)$/i;\n  public static readonly presentationalTags = /^(b|code|del|em|i|s|strong|kbd)$/i;\n  public static readonly spaceLikeTags = /^(br|hr|i|img|pangu)$/i;\n  public static readonly spaceSensitiveTags = /^(a|del|pre|s|strike|u)$/i;\n  public static readonly ignoredClass = 'no-pangu-spacing';\n\n  public static collectTextNodes(contextNode: Node, reverse = false) {\n    const nodes: Text[] = [];\n\n    // Handle edge cases\n    if (!contextNode || contextNode instanceof DocumentFragment) {\n      return nodes;\n    }\n\n    const walker = document.createTreeWalker(contextNode, NodeFilter.SHOW_TEXT, {\n      acceptNode: (node) => {\n        // Skip whitespace-only nodes\n        if (!node.nodeValue || !/\\S/.test(node.nodeValue)) {\n          return NodeFilter.FILTER_REJECT;\n        }\n\n        // Skip nodes that should be ignored (same as canIgnoreNode check)\n        // We need to check the node itself and its ancestors\n        let currentNode = node;\n        while (currentNode) {\n          if (currentNode instanceof Element) {\n            // Check for ignored tags\n            if (this.ignoredTags.test(currentNode.nodeName)) {\n              return NodeFilter.FILTER_REJECT;\n            }\n            // Check for contentEditable\n            if (this.isContentEditable(currentNode)) {\n              return NodeFilter.FILTER_REJECT;\n            }\n            // Check for ignored class\n            if (currentNode.classList.contains(this.ignoredClass)) {\n              return NodeFilter.FILTER_REJECT;\n            }\n          }\n          currentNode = currentNode.parentNode as Node;\n        }\n\n        return NodeFilter.FILTER_ACCEPT;\n      },\n    });\n\n    // Collect all text nodes\n    while (walker.nextNode()) {\n      nodes.push(walker.currentNode as Text);\n    }\n\n    // Return in reverse order if requested\n    return reverse ? nodes.reverse() : nodes;\n  }\n\n  public static canIgnoreNode(node: Node) {\n    let currentNode = node;\n    if (currentNode && (this.isSpecificTag(currentNode, this.ignoredTags) || this.isContentEditable(currentNode) || this.hasIgnoredClass(currentNode))) {\n      // We will skip processing any children of ignored elements, so don't need to check all ancestors\n      return true;\n    }\n    while (currentNode.parentNode) {\n      currentNode = currentNode.parentNode;\n      if (currentNode && (this.isSpecificTag(currentNode, this.ignoredTags) || this.isContentEditable(currentNode))) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  public static isFirstTextChild(parentNode: Node, targetNode: Node) {\n    const { childNodes } = parentNode;\n\n    // Check if targetNode is the first child node (excluding comments) that has textContent\n    // Note: textContent includes text from all descendants, so element nodes can match too\n    for (let i = 0; i < childNodes.length; i++) {\n      const childNode = childNodes[i];\n      if (childNode.nodeType !== Node.COMMENT_NODE && childNode.textContent) {\n        return childNode === targetNode;\n      }\n    }\n    return false;\n  }\n\n  public static isLastTextChild(parentNode: Node, targetNode: Node) {\n    const { childNodes } = parentNode;\n\n    // Check if targetNode is the last child node (excluding comments) that has textContent\n    // Note: textContent includes text from all descendants, so element nodes can match too\n    for (let i = childNodes.length - 1; i > -1; i--) {\n      const childNode = childNodes[i];\n      if (childNode.nodeType !== Node.COMMENT_NODE && childNode.textContent) {\n        return childNode === targetNode;\n      }\n    }\n    return false;\n  }\n\n  private static isSpecificTag(node: Node, tagRegex: RegExp) {\n    return !!(node && node.nodeName && tagRegex.test(node.nodeName));\n  }\n\n  private static isContentEditable(node: Node) {\n    return node instanceof HTMLElement && (node.isContentEditable || node.getAttribute('g_editable') === 'true');\n  }\n\n  private static hasIgnoredClass(node: Node) {\n    // Check the node itself if it's an element\n    if (node instanceof Element && node.classList.contains(this.ignoredClass)) {\n      return true;\n    }\n\n    // Check the parent node (for text nodes)\n    if (node.parentNode && node.parentNode instanceof Element && node.parentNode.classList.contains(this.ignoredClass)) {\n      return true;\n    }\n    return false;\n  }\n}\n","export interface TaskSchedulerConfig {\n  enabled: boolean;\n  chunkSize: number;\n  timeout: number;\n}\n\nexport class TaskQueue {\n  private queue: (() => void)[] = [];\n  private isProcessing = false;\n  private onComplete?: () => void;\n\n  add(task: () => void) {\n    this.queue.push(task);\n    this.scheduleProcessing();\n  }\n\n  clear() {\n    this.queue.length = 0;\n    this.onComplete = undefined;\n  }\n\n  setOnComplete(onComplete?: () => void) {\n    this.onComplete = onComplete;\n  }\n\n  get length() {\n    return this.queue.length;\n  }\n\n  private scheduleProcessing() {\n    if (!this.isProcessing && this.queue.length > 0) {\n      this.isProcessing = true;\n      requestIdleCallback((deadline) => this.process(deadline), { timeout: 5000 });\n    }\n  }\n\n  private process(deadline: IdleDeadline) {\n    while (deadline.timeRemaining() > 0 && this.queue.length > 0) {\n      const task = this.queue.shift();\n      task?.();\n    }\n\n    this.isProcessing = false;\n\n    if (this.queue.length > 0) {\n      this.scheduleProcessing();\n    } else {\n      // All task completed, call completion callback\n      this.onComplete?.();\n    }\n  }\n}\n\n/**\n * Schedules and executes text spacing operations during browser idle time to avoid blocking the UI.\n * Uses requestIdleCallback to process task in chunks when the browser has spare time,\n * ensuring smooth user experience even when processing large amounts of text.\n */\nexport class TaskScheduler {\n  public readonly config: TaskSchedulerConfig = {\n    enabled: true,\n    chunkSize: 40, // Process 40 text nodes per idle cycle\n    timeout: 2000, // 2 second timeout for idle processing\n  };\n\n  private taskQueue = new TaskQueue();\n\n  get queue() {\n    return this.taskQueue;\n  }\n\n  processInChunks<T>(items: T[], processor: (chunk: T[]) => void, onComplete?: () => void) {\n    if (!this.config.enabled) {\n      // Process synchronously if idle processing is disabled\n      processor(items);\n      onComplete?.();\n      return;\n    }\n\n    if (items.length === 0) {\n      onComplete?.();\n      return;\n    }\n\n    // Set up completion callback\n    if (onComplete) {\n      this.taskQueue.setOnComplete(onComplete);\n    }\n\n    // Split items into chunks\n    const chunks: T[][] = [];\n    for (let i = 0; i < items.length; i += this.config.chunkSize) {\n      chunks.push(items.slice(i, i + this.config.chunkSize));\n    }\n\n    // Add each chunk as a task item to the task queue\n    for (const chunk of chunks) {\n      this.taskQueue.add(() => {\n        processor(chunk);\n      });\n    }\n  }\n\n  clear() {\n    this.taskQueue.clear();\n  }\n\n  updateConfig(config: Partial<TaskSchedulerConfig>) {\n    Object.assign(this.config, config);\n  }\n}\n","export interface VisibilityDetectorConfig {\n  enabled: boolean;\n  commonHiddenPatterns: {\n    clipRect: boolean;\n    displayNone: boolean;\n    visibilityHidden: boolean;\n    opacityZero: boolean;\n    heightWidth1px: boolean;\n  };\n}\n\nexport class VisibilityDetector {\n  public readonly config: VisibilityDetectorConfig = {\n    enabled: true,\n    commonHiddenPatterns: {\n      clipRect: true, // clip: rect(1px, 1px, 1px, 1px) patterns\n      displayNone: true, // display: none\n      visibilityHidden: true, // visibility: hidden\n      opacityZero: true, // opacity: 0\n      heightWidth1px: true, // height: 1px; width: 1px\n    },\n  };\n\n  public isElementVisuallyHidden(element: Element) {\n    if (!this.config.enabled) {\n      return false;\n    }\n\n    const style = getComputedStyle(element);\n    const patterns = this.config.commonHiddenPatterns;\n\n    // Check display: none\n    if (patterns.displayNone && style.display === 'none') {\n      return true;\n    }\n\n    // Check visibility: hidden\n    if (patterns.visibilityHidden && style.visibility === 'hidden') {\n      return true;\n    }\n\n    // Check opacity: 0\n    if (patterns.opacityZero && parseFloat(style.opacity) === 0) {\n      return true;\n    }\n\n    // Check clip: rect patterns (screen reader only content)\n    if (patterns.clipRect) {\n      const clip = style.clip;\n      // Common patterns: rect(1px, 1px, 1px, 1px) or rect(0, 0, 0, 0)\n      if (clip && (clip.includes('rect(1px, 1px, 1px, 1px)') || clip.includes('rect(0px, 0px, 0px, 0px)') || clip.includes('rect(0, 0, 0, 0)'))) {\n        return true;\n      }\n    }\n\n    // Check height: 1px; width: 1px patterns\n    if (patterns.heightWidth1px) {\n      const height = parseInt(style.height, 10);\n      const width = parseInt(style.width, 10);\n\n      if (height === 1 && width === 1) {\n        // Additional checks for common screen reader patterns\n        const overflow = style.overflow;\n        const position = style.position;\n\n        if (overflow === 'hidden' && position === 'absolute') {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  }\n\n  public shouldSkipSpacingAfterNode(node: Node) {\n    if (!this.config.enabled) {\n      return false;\n    }\n\n    // Check if the node or its parent element is visually hidden\n    let elementToCheck: Element | null = null;\n\n    if (node instanceof Element) {\n      elementToCheck = node;\n    } else if (node.parentElement) {\n      elementToCheck = node.parentElement;\n    }\n\n    if (elementToCheck && this.isElementVisuallyHidden(elementToCheck)) {\n      return true;\n    }\n\n    // Check if any ancestor is visually hidden\n    let currentElement = elementToCheck?.parentElement;\n    while (currentElement) {\n      if (this.isElementVisuallyHidden(currentElement)) {\n        return true;\n      }\n      currentElement = currentElement.parentElement;\n    }\n\n    return false;\n  }\n\n  public shouldSkipSpacingBeforeNode(node: Node) {\n    if (!this.config.enabled) {\n      return false;\n    }\n\n    // Find the previous sibling that might be hidden\n    let previousNode = node.previousSibling;\n    \n    // Walk up the DOM tree to find the actual previous element\n    if (!previousNode && node.parentElement) {\n      let parent: Element | null = node.parentElement;\n      while (parent && !previousNode) {\n        previousNode = parent.previousSibling;\n        if (!previousNode) {\n          parent = parent.parentElement;\n        }\n      }\n    }\n\n    // Check if the previous node is hidden\n    if (previousNode) {\n      if (previousNode instanceof Element && this.isElementVisuallyHidden(previousNode)) {\n        return true;\n      } else if (previousNode instanceof Text && previousNode.parentElement && this.isElementVisuallyHidden(previousNode.parentElement)) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  public updateConfig(config: Partial<VisibilityDetectorConfig>) {\n    Object.assign(this.config, config);\n\n    // Handle nested commonHiddenPatterns object if provided\n    if (config.commonHiddenPatterns) {\n      Object.assign(this.config.commonHiddenPatterns, config.commonHiddenPatterns);\n    }\n  }\n}\n","import { Pangu } from '../shared';\nimport { DomWalker } from './dom-walker';\nimport { TaskScheduler } from './task-scheduler';\nimport { VisibilityDetector } from './visibility-detector';\n\nexport interface AutoSpacingPageConfig {\n  pageDelayMs?: number;\n  nodeDelayMs?: number;\n  nodeMaxWaitMs?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction once<T extends (...args: any[]) => any>(func: T) {\n  let executed = false;\n  return function (...args: Parameters<T>) {\n    if (executed) {\n      return undefined;\n    }\n    executed = true;\n    return func(...args);\n  };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce<T extends (...args: any[]) => void>(func: T, delay: number, mustRunDelay: number = Infinity) {\n  let timer: number | null = null;\n  let startTime: number | null = null;\n\n  return function (...args: Parameters<T>) {\n    const currentTime = Date.now();\n\n    if (timer) {\n      clearTimeout(timer);\n    }\n\n    if (!startTime) {\n      startTime = currentTime;\n    }\n\n    if (currentTime - startTime >= mustRunDelay) {\n      func(...args);\n      startTime = currentTime;\n    } else {\n      timer = window.setTimeout(() => {\n        func(...args);\n      }, delay);\n    }\n  };\n}\n\n// Main call flow from autoSpacingPage() to requestIdleCallback():\n//\n// 1. autoSpacingPage()\n// ↓\n// 2. spacingPage()\n// ↓\n// 3. spacingNode()\n//    - Collects text nodes via DomWalker.collectTextNodes()\n//    - Decision point: taskScheduler.config.enabled?\n//      ├─ YES → calls spacingTextNodesInQueue()\n//      └─ NO  → calls spacingTextNodes() directly (synchronous, no requestIdleCallback)\n// ↓\n// 4. spacingTextNodesInQueue() (only if taskScheduler enabled)\n//    - Decision point: visibilityDetector.config.enabled?\n//      ├─ YES (default: true) → Process all nodes in one batch\n//      │   └─ taskScheduler.queue.add(() => spacingTextNodes(allNodes))\n//      └─ NO → Process in chunks via taskScheduler.processInChunks()\n//          └─ Splits into chunks of 40 nodes\n// ↓\n// 5. TaskQueue.add() → scheduleProcessing() → requestIdleCallback()\n//    - Timeout: 5000ms\n//    - Processes tasks when browser is idle\n//    - Uses IdleDeadline to check remaining time\n//\n// Summary of paths to requestIdleCallback():\n// - taskScheduler.enabled=true + visibilityDetector.enabled=true → Single batch via requestIdleCallback\n// - taskScheduler.enabled=true + visibilityDetector.enabled=false → Multiple chunks via requestIdleCallback  \n// - taskScheduler.enabled=false → No requestIdleCallback (synchronous processing)\nexport class BrowserPangu extends Pangu {\n  private isAutoSpacingPageExecuted = false;\n  private autoSpacingPageObserver: MutationObserver | null = null;\n  public readonly taskScheduler = new TaskScheduler();\n  public readonly visibilityDetector = new VisibilityDetector();\n\n  // PUBLIC\n\n  public autoSpacingPage({ pageDelayMs = 1000, nodeDelayMs = 500, nodeMaxWaitMs = 2000 }: AutoSpacingPageConfig = {}) {\n    if (!(document.body instanceof Node)) {\n      return;\n    }\n\n    if (this.isAutoSpacingPageExecuted) {\n      return;\n    }\n\n    this.isAutoSpacingPageExecuted = true;\n\n    // prettier-ignore\n    this.waitForVideosToLoad(pageDelayMs, once(() => this.spacingPage()));\n    this.setupAutoSpacingPageObserver(nodeDelayMs, nodeMaxWaitMs);\n  }\n\n  public spacingPage() {\n    // Page title\n    const title = document.querySelector('head > title');\n    if (title) {\n      this.spacingNode(title);\n    }\n\n    // Page body\n    this.spacingNode(document.body);\n  }\n\n  public spacingNode(contextNode: Node) {\n    // Only process nodes with actual content (excluding text nodes that contain only whitespace)\n    const textNodes = DomWalker.collectTextNodes(contextNode, true);\n\n    // Choose processing method based on idle spacing configuration\n    if (this.taskScheduler.config.enabled) {\n      this.spacingTextNodesInQueue(textNodes);\n    } else {\n      // Process the collected text nodes using the shared logic (synchronous)\n      this.spacingTextNodes(textNodes);\n    }\n  }\n\n  public stopAutoSpacingPage() {\n    if (this.autoSpacingPageObserver) {\n      this.autoSpacingPageObserver.disconnect();\n      this.autoSpacingPageObserver = null;\n    }\n\n    this.isAutoSpacingPageExecuted = false;\n  }\n\n  public isElementVisuallyHidden(element: Element) {\n    return this.visibilityDetector.isElementVisuallyHidden(element);\n  }\n\n  // INTERNAL\n\n  // TODO: Refactor this method - it's too large and handles too many responsibilities\n  private spacingTextNodes(textNodes: Node[]) {\n    let currentTextNode: Node | null;\n    let nextTextNode: Node | null = null;\n\n    // Process nodes in the order provided\n    for (let i = 0; i < textNodes.length; i++) {\n      currentTextNode = textNodes[i];\n      if (!currentTextNode) {\n        continue;\n      }\n\n      // Skip nodes that should be ignored\n      if (DomWalker.canIgnoreNode(currentTextNode)) {\n        nextTextNode = currentTextNode;\n        continue;\n      }\n\n      if (currentTextNode instanceof Text) {\n        // Check if this text node starts with a space and comes after a hidden element\n        if (this.visibilityDetector.config.enabled && currentTextNode.data.startsWith(' ') && this.visibilityDetector.shouldSkipSpacingBeforeNode(currentTextNode)) {\n          // Remove the leading space that comes after a hidden element\n          currentTextNode.data = currentTextNode.data.substring(1);\n        }\n\n        // Special handling for standalone quote nodes\n        if (currentTextNode.data.length === 1 && /[\"\\u201c\\u201d]/.test(currentTextNode.data)) {\n          // Check context to determine if space is needed before the quote\n          if (currentTextNode.previousSibling) {\n            const prevNode = currentTextNode.previousSibling;\n            if (prevNode.nodeType === Node.ELEMENT_NODE && prevNode.textContent) {\n              const lastChar = prevNode.textContent.slice(-1);\n              // If previous element ends with CJK, add space before quote\n              if (/[\\u4e00-\\u9fff]/.test(lastChar)) {\n                currentTextNode.data = ` ${currentTextNode.data}`;\n              }\n            }\n          }\n        } else {\n          // Normal text processing\n          const newText = this.spacingText(currentTextNode.data);\n          if (currentTextNode.data !== newText) {\n            currentTextNode.data = newText;\n          }\n        }\n      }\n\n      // Handle nested tag text processing\n      if (nextTextNode) {\n        if (currentTextNode.nextSibling && DomWalker.spaceLikeTags.test(currentTextNode.nextSibling.nodeName)) {\n          nextTextNode = currentTextNode;\n          continue;\n        }\n\n        if (!(currentTextNode instanceof Text) || !(nextTextNode instanceof Text)) {\n          continue;\n        }\n\n        // Check if there's already proper spacing between nodes\n        const currentEndsWithSpace = currentTextNode.data.endsWith(' ');\n        const nextStartsWithSpace = nextTextNode.data.startsWith(' ');\n\n        // Check if there's whitespace between the nodes\n        let hasWhitespaceBetween = false;\n\n        // We need to check at different levels of the DOM tree\n        // First, find the highest ancestor that contains only the current text node\n        let currentAncestor = currentTextNode as Node;\n        while (currentAncestor.parentNode && DomWalker.isLastTextChild(currentAncestor.parentNode, currentAncestor) && !DomWalker.spaceSensitiveTags.test(currentAncestor.parentNode.nodeName)) {\n          currentAncestor = currentAncestor.parentNode;\n        }\n\n        // Find the highest ancestor that contains only the next text node\n        let nextAncestor = nextTextNode as Node;\n        while (nextAncestor.parentNode && DomWalker.isFirstTextChild(nextAncestor.parentNode, nextAncestor) && !DomWalker.spaceSensitiveTags.test(nextAncestor.parentNode.nodeName)) {\n          nextAncestor = nextAncestor.parentNode;\n        }\n\n        // Check for whitespace between these ancestors\n        let nodeBetween = currentAncestor.nextSibling;\n        while (nodeBetween && nodeBetween !== nextAncestor) {\n          if (nodeBetween.nodeType === Node.TEXT_NODE && nodeBetween.textContent && /\\s/.test(nodeBetween.textContent)) {\n            hasWhitespaceBetween = true;\n            break;\n          }\n          nodeBetween = nodeBetween.nextSibling;\n        }\n\n        // Skip if proper spacing exists\n        if (currentEndsWithSpace || nextStartsWithSpace || hasWhitespaceBetween) {\n          nextTextNode = currentTextNode;\n          continue;\n        }\n\n        const testText = currentTextNode.data.slice(-1) + nextTextNode.data.slice(0, 1);\n        const testNewText = this.spacingText(testText);\n\n        // Special handling for quotes\n        const currentLast = currentTextNode.data.slice(-1);\n        const nextFirst = nextTextNode.data.slice(0, 1);\n        const isQuote = (char: string) => /[\"\\u201c\\u201d]/.test(char);\n        const isCJK = (char: string) => /[\\u4e00-\\u9fff]/.test(char);\n\n        const skipSpacing = (isQuote(currentLast) && isCJK(nextFirst)) || (isCJK(currentLast) && isQuote(nextFirst));\n\n        if (testNewText !== testText && !skipSpacing) {\n          let nextNode: Node = nextTextNode;\n          while (nextNode.parentNode && !DomWalker.spaceSensitiveTags.test(nextNode.nodeName) && DomWalker.isFirstTextChild(nextNode.parentNode, nextNode)) {\n            nextNode = nextNode.parentNode;\n          }\n\n          let currentNode: Node = currentTextNode;\n          while (currentNode.parentNode && !DomWalker.spaceSensitiveTags.test(currentNode.nodeName) && DomWalker.isLastTextChild(currentNode.parentNode, currentNode)) {\n            currentNode = currentNode.parentNode;\n          }\n\n          if (currentNode.nextSibling) {\n            if (DomWalker.spaceLikeTags.test(currentNode.nextSibling.nodeName)) {\n              nextTextNode = currentTextNode;\n              continue;\n            }\n          }\n\n          if (!DomWalker.blockTags.test(currentNode.nodeName)) {\n            if (!DomWalker.spaceSensitiveTags.test(nextNode.nodeName)) {\n              if (!DomWalker.ignoredTags.test(nextNode.nodeName) && !DomWalker.blockTags.test(nextNode.nodeName)) {\n                if (nextTextNode.previousSibling) {\n                  if (!DomWalker.spaceLikeTags.test(nextTextNode.previousSibling.nodeName)) {\n                    if (nextTextNode instanceof Text && !nextTextNode.data.startsWith(' ')) {\n                      // Check visibility before adding space\n                      if (!this.visibilityDetector.shouldSkipSpacingBeforeNode(nextTextNode)) {\n                        nextTextNode.data = ` ${nextTextNode.data}`;\n                      }\n                    }\n                  }\n                } else {\n                  if (!DomWalker.canIgnoreNode(nextTextNode)) {\n                    if (nextTextNode instanceof Text && !nextTextNode.data.startsWith(' ')) {\n                      // Check visibility before adding space\n                      if (!this.visibilityDetector.shouldSkipSpacingBeforeNode(nextTextNode)) {\n                        nextTextNode.data = ` ${nextTextNode.data}`;\n                      }\n                    }\n                  }\n                }\n              }\n            } else if (!DomWalker.spaceSensitiveTags.test(currentNode.nodeName)) {\n              if (currentTextNode instanceof Text && !currentTextNode.data.endsWith(' ')) {\n                // Check visibility before adding space\n                if (!this.visibilityDetector.shouldSkipSpacingAfterNode(currentTextNode)) {\n                  currentTextNode.data = `${currentTextNode.data} `;\n                }\n              }\n            } else {\n              // Check visibility before inserting space element\n              if (!this.visibilityDetector.shouldSkipSpacingAfterNode(currentTextNode)) {\n                const panguSpace = document.createElement('pangu');\n                panguSpace.innerHTML = ' ';\n\n                if (nextNode.parentNode) {\n                  if (nextNode.previousSibling) {\n                    if (!DomWalker.spaceLikeTags.test(nextNode.previousSibling.nodeName)) {\n                      nextNode.parentNode.insertBefore(panguSpace, nextNode);\n                    }\n                  } else {\n                    nextNode.parentNode.insertBefore(panguSpace, nextNode);\n                  }\n                }\n\n                // Clean up orphaned space element\n                if (!panguSpace.previousElementSibling) {\n                  if (panguSpace.parentNode) {\n                    panguSpace.parentNode.removeChild(panguSpace);\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n\n      nextTextNode = currentTextNode;\n    }\n  }\n\n  private spacingTextNodesInQueue(textNodes: Node[], onComplete?: () => void) {\n    // When visibility detection is enabled, process all nodes together to maintain context between adjacent nodes\n    // This prevents incorrect spacing after hidden elements\n    if (this.visibilityDetector.config.enabled) {\n      // Still use idle callback for performance, but process all nodes in one batch\n      if (this.taskScheduler.config.enabled) {\n        this.taskScheduler.queue.add(() => {\n          this.spacingTextNodes(textNodes);\n        });\n        if (onComplete) {\n          this.taskScheduler.queue.setOnComplete(onComplete);\n        }\n      } else {\n        // Synchronous processing\n        this.spacingTextNodes(textNodes);\n        onComplete?.();\n      }\n      return;\n    }\n\n    // Normal chunked processing when visibility detection is disabled\n    const task = (chunkedTextNodes: Node[]) => this.spacingTextNodes(chunkedTextNodes);\n    this.taskScheduler.processInChunks(textNodes, task, onComplete);\n  }\n\n  private waitForVideosToLoad(delayMs: number, onLoaded: () => void) {\n    // Wait for videos to load before spacing to avoid layout shifts\n    // See: https://github.com/vinta/pangu.js/issues/117\n    const videos = Array.from(document.getElementsByTagName('video'));\n\n    if (videos.length === 0) {\n      // No videos, proceed with normal delay\n      setTimeout(onLoaded, delayMs);\n    } else {\n      // Check if all videos are already loaded\n      const allVideosLoaded = videos.every((video) => video.readyState >= 3);\n\n      if (allVideosLoaded) {\n        // All videos loaded, proceed with normal delay\n        setTimeout(onLoaded, delayMs);\n      } else {\n        // Wait for all videos to load\n        let loadedCount = 0;\n        const videoCount = videos.length;\n\n        const checkAllLoaded = () => {\n          loadedCount++;\n          if (loadedCount >= videoCount) {\n            setTimeout(onLoaded, delayMs);\n          }\n        };\n\n        for (const video of videos) {\n          if (video.readyState >= 3) {\n            checkAllLoaded();\n          } else {\n            video.addEventListener('loadeddata', checkAllLoaded, { once: true });\n          }\n        }\n\n        // Fallback timeout in case videos never load\n        setTimeout(onLoaded, delayMs + 5000);\n      }\n    }\n  }\n\n  private setupAutoSpacingPageObserver(nodeDelayMs: number, nodeMaxWaitMs: number) {\n    // Disconnect any existing auto-spacing observer\n    if (this.autoSpacingPageObserver) {\n      this.autoSpacingPageObserver.disconnect();\n      this.autoSpacingPageObserver = null;\n    }\n\n    const queue: Node[] = [];\n\n    const debouncedSpacingTitle = debounce(\n      () => {\n        const titleElement = document.querySelector('head > title');\n        if (titleElement) {\n          this.spacingNode(titleElement);\n        }\n      },\n      nodeDelayMs,\n      nodeMaxWaitMs,\n    );\n\n    const debouncedSpacingNode = debounce(\n      () => {\n        // NOTE: a single node could be very big which contains a lot of child nodes\n        if (this.taskScheduler.config.enabled) {\n          // Use idle processing for dynamic content\n          const nodesToProcess = [...queue];\n          queue.length = 0; // Clear the queue\n\n          if (nodesToProcess.length > 0) {\n            // Collect all text nodes from all input nodes\n            const allTextNodes: Node[] = [];\n            for (const node of nodesToProcess) {\n              const textNodes = DomWalker.collectTextNodes(node, true);\n              allTextNodes.push(...textNodes);\n            }\n\n            // Process all collected text nodes with idle callback\n            this.spacingTextNodesInQueue(allTextNodes);\n          }\n        } else {\n          // Synchronous processing (original behavior)\n          while (queue.length) {\n            const node = queue.shift();\n            if (node) {\n              this.spacingNode(node);\n            }\n          }\n        }\n      },\n      nodeDelayMs,\n      nodeMaxWaitMs,\n    );\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver\n    this.autoSpacingPageObserver = new MutationObserver((mutations) => {\n      let titleChanged = false;\n\n      // Element: https://developer.mozilla.org/en-US/docs/Web/API/Element\n      // Text: https://developer.mozilla.org/en-US/docs/Web/API/Text\n      for (const mutation of mutations) {\n        // Skip to avoid double processing - title handled separately by debouncedSpacingTitle()\n        if (mutation.target.parentNode?.nodeName === 'TITLE' || mutation.target.nodeName === 'TITLE') {\n          titleChanged = true;\n          continue;\n        }\n\n        // Queue parent elements for spacing processing\n        switch (mutation.type) {\n          case 'characterData':\n            // Text content changed (e.g., textContent = '新文字new text')\n            const { target: node } = mutation;\n            if (node.nodeType === Node.TEXT_NODE && node.parentNode) {\n              // <p>Hello 世界</p>\n              // \"Hello 世界\" is the text node, <p> is the parent element\n              queue.push(node.parentNode); // Queue parent element, not text node\n            }\n            break;\n          case 'childList':\n            // New nodes added to DOM (e.g., innerHTML change, appendChild)\n            for (const node of mutation.addedNodes) {\n              if (node.nodeType === Node.ELEMENT_NODE) {\n                queue.push(node); // Element added, process its text content\n              } else if (node.nodeType === Node.TEXT_NODE && node.parentNode) {\n                queue.push(node.parentNode); // Text node added, process its parent\n              }\n            }\n            break;\n          default:\n            break;\n        }\n      }\n\n      if (titleChanged) {\n        debouncedSpacingTitle();\n      }\n\n      debouncedSpacingNode();\n    });\n\n    // NOTE: A single MutationObserver can observe multiple targets simultaneously\n    // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe:\n\n    // Observe page title changes\n    this.autoSpacingPageObserver.observe(document.head, {\n      characterData: true,\n      childList: true,\n      subtree: true, // Need subtree to observe text node changes inside title\n    });\n\n    // Observe page content changes\n    this.autoSpacingPageObserver.observe(document.body, {\n      characterData: true,\n      childList: true,\n      subtree: true,\n    });\n  }\n}\n\nexport const pangu = new BrowserPangu();\n\nexport default pangu;\n","import pangu, { BrowserPangu } from './pangu';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(pangu as any).BrowserPangu = BrowserPangu;\n\n// Declare global for UMD builds\ndeclare global {\n  interface Window {\n    pangu: typeof pangu & { BrowserPangu: typeof BrowserPangu };\n  }\n}\n\nexport default pangu;\n"]}