domotion-svg 0.2.2 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/FEATURES.md +1 -0
  2. package/README.md +29 -0
  3. package/dist/animation/animator.js +25 -14
  4. package/dist/animation/animator.test.js +54 -21
  5. package/dist/animation/cursor-overlay.js +0 -2
  6. package/dist/capture/emoji.js +29 -18
  7. package/dist/capture/index.js +5 -4
  8. package/dist/capture/script/color-norm.d.ts +1 -0
  9. package/dist/capture/script/color-norm.js +43 -1
  10. package/dist/capture/script/emoji-detect.js +14 -0
  11. package/dist/capture/script/index.js +593 -65
  12. package/dist/capture/script/walker/borders-backgrounds.d.ts +24 -17
  13. package/dist/capture/script/walker/borders-backgrounds.js +123 -7
  14. package/dist/capture/script/walker/counter-style-resolver.d.ts +7 -0
  15. package/dist/capture/script/walker/counter-style-resolver.js +218 -0
  16. package/dist/capture/script/walker/input-value.js +14 -1
  17. package/dist/capture/script/walker/lists-counters.d.ts +3 -1
  18. package/dist/capture/script/walker/lists-counters.js +22 -2
  19. package/dist/capture/script/walker/masks-clips.d.ts +2 -0
  20. package/dist/capture/script/walker/masks-clips.js +41 -1
  21. package/dist/capture/script/walker/pseudo-content.d.ts +14 -1
  22. package/dist/capture/script/walker/pseudo-content.js +301 -61
  23. package/dist/capture/script/walker/pseudo-inject.js +20 -0
  24. package/dist/capture/script/walker/text-segments.js +98 -4
  25. package/dist/capture/script/walker/transforms.d.ts +1 -0
  26. package/dist/capture/script/walker/transforms.js +16 -0
  27. package/dist/capture/script.generated.js +1 -1
  28. package/dist/capture/types.d.ts +213 -2
  29. package/dist/cli/animate.js +151 -15
  30. package/dist/mask.test.js +12 -7
  31. package/dist/render/borders.d.ts +9 -13
  32. package/dist/render/borders.js +379 -14
  33. package/dist/render/element-tree-to-svg.d.ts +11 -12
  34. package/dist/render/element-tree-to-svg.js +2046 -241
  35. package/dist/render/embedded-font-builder.d.ts +49 -0
  36. package/dist/render/embedded-font-builder.js +149 -0
  37. package/dist/render/form-controls.js +45 -24
  38. package/dist/render/gradients.d.ts +15 -0
  39. package/dist/render/gradients.js +103 -2
  40. package/dist/render/gradients.test.js +34 -0
  41. package/dist/render/text-to-path.d.ts +38 -1
  42. package/dist/render/text-to-path.js +654 -29
  43. package/dist/render/text-to-path.test.js +230 -9
  44. package/dist/render/text.d.ts +14 -0
  45. package/dist/render/text.js +344 -40
  46. package/dist/scroll/composer.d.ts +26 -0
  47. package/dist/scroll/composer.js +199 -11
  48. package/dist/scroll/composer.test.js +293 -16
  49. package/dist/scroll/executor.d.ts +3 -1
  50. package/dist/scroll/executor.js +15 -6
  51. package/dist/scroll/executor.test.js +25 -0
  52. package/dist/scroll/hoist-fixed.d.ts +48 -0
  53. package/dist/scroll/hoist-fixed.js +85 -0
  54. package/dist/scroll/hoist-fixed.test.d.ts +1 -0
  55. package/dist/scroll/hoist-fixed.test.js +103 -0
  56. package/dist/scroll/hoist-sticky.d.ts +45 -0
  57. package/dist/scroll/hoist-sticky.js +157 -0
  58. package/dist/scroll/hoist-sticky.test.d.ts +1 -0
  59. package/dist/scroll/hoist-sticky.test.js +154 -0
  60. package/dist/scroll/pattern.d.ts +22 -5
  61. package/dist/scroll/pattern.js +55 -7
  62. package/dist/scroll/pattern.test.js +48 -1
  63. package/dist/tree-ops/frame-merge.d.ts +10 -0
  64. package/dist/tree-ops/frame-merge.js +23 -5
  65. package/dist/tree-ops/frame-merge.test.js +45 -0
  66. package/dist/tree-ops/tree-diff.js +1 -1
  67. package/dist/tree-ops/viewbox-culling.js +32 -18
  68. package/dist/tree-ops/viewbox-culling.test.js +40 -6
  69. package/package.json +8 -2
  70. package/src/animation/animator.test.ts +56 -21
  71. package/src/animation/animator.ts +25 -14
  72. package/src/animation/cursor-overlay.ts +0 -2
  73. package/src/capture/emoji.ts +28 -18
  74. package/src/capture/index.ts +15 -14
  75. package/src/capture/script/color-norm.ts +38 -1
  76. package/src/capture/script/emoji-detect.ts +14 -0
  77. package/src/capture/script/index.ts +555 -48
  78. package/src/capture/script/walker/borders-backgrounds.ts +114 -7
  79. package/src/capture/script/walker/counter-style-resolver.ts +184 -0
  80. package/src/capture/script/walker/input-value.ts +14 -1
  81. package/src/capture/script/walker/lists-counters.ts +24 -2
  82. package/src/capture/script/walker/masks-clips.ts +40 -1
  83. package/src/capture/script/walker/pseudo-content.ts +297 -55
  84. package/src/capture/script/walker/pseudo-inject.ts +20 -0
  85. package/src/capture/script/walker/text-segments.ts +93 -4
  86. package/src/capture/script/walker/transforms.ts +14 -0
  87. package/src/capture/script.generated.ts +1 -1
  88. package/src/capture/types.ts +202 -2
  89. package/src/cli/animate.ts +135 -15
  90. package/src/mask.test.ts +12 -7
  91. package/src/render/borders.ts +383 -17
  92. package/src/render/element-tree-to-svg.ts +2051 -238
  93. package/src/render/embedded-font-builder.ts +221 -0
  94. package/src/render/form-controls.ts +45 -24
  95. package/src/render/gradients.test.ts +46 -0
  96. package/src/render/gradients.ts +94 -2
  97. package/src/render/opentype.js.d.ts +7 -0
  98. package/src/render/text-to-path.test.ts +246 -9
  99. package/src/render/text-to-path.ts +702 -31
  100. package/src/render/text.ts +344 -40
  101. package/src/scroll/composer.test.ts +322 -16
  102. package/src/scroll/composer.ts +246 -13
  103. package/src/scroll/executor.test.ts +27 -0
  104. package/src/scroll/executor.ts +19 -10
  105. package/src/scroll/hoist-fixed.test.ts +117 -0
  106. package/src/scroll/hoist-fixed.ts +95 -0
  107. package/src/scroll/hoist-sticky.test.ts +173 -0
  108. package/src/scroll/hoist-sticky.ts +193 -0
  109. package/src/scroll/pattern.test.ts +58 -1
  110. package/src/scroll/pattern.ts +71 -8
  111. package/src/tree-ops/frame-merge.test.ts +51 -0
  112. package/src/tree-ops/frame-merge.ts +24 -6
  113. package/src/tree-ops/tree-diff.ts +3 -1
  114. package/src/tree-ops/viewbox-culling.test.ts +42 -6
  115. package/src/tree-ops/viewbox-culling.ts +32 -18
@@ -3,4 +3,4 @@
3
3
  //
4
4
  // Run `npm run build:capture-script` (or any of the npm scripts that depend on
5
5
  // it: build, typecheck, test, capture, demos:*) to regenerate.
6
- export const CAPTURE_SCRIPT = "\n(() => {\n// src/capture/script/color-norm.ts\nvar createColorNorm = () => {\n const probe = document.createElement(\"div\");\n probe.style.position = \"absolute\";\n probe.style.visibility = \"hidden\";\n document.body.appendChild(probe);\n const normColor = (c, elColor) => {\n if (c == null || c === \"\" || c === \"transparent\" || c === \"currentcolor\" || c === \"auto\") return c;\n if (/^(rgba?\\(|#[0-9a-f]{3,8}$)/i.test(c)) return c;\n var probeIn = c;\n if (elColor != null && elColor !== \"\" && /\\bcurrentcolor\\b/i.test(c)) {\n probeIn = c.replace(/\\bcurrentcolor\\b/gi, elColor);\n }\n try {\n probe.style.color = \"\";\n probe.style.color = \"color-mix(in srgb, \" + probeIn + \" 100%, transparent 0%)\";\n const v = getComputedStyle(probe).color;\n if (v != null && v !== \"\") return v;\n } catch (e) {\n }\n return c;\n };\n return { normColor };\n};\n\n// src/capture/script/emoji-detect.ts\nvar createEmojiDetect = () => {\n const rasterCps = /* @__PURE__ */ new Set([\n 10003,\n 10004,\n 10006,\n 10007,\n 10024,\n 10067,\n 10068,\n 10069,\n 10071,\n 10060,\n 10062,\n 10133,\n 10134,\n 10135,\n 10145,\n 10160,\n 10175\n ]);\n const emojiPresentation26 = /* @__PURE__ */ new Set([\n 9748,\n 9749,\n 9800,\n 9801,\n 9802,\n 9803,\n 9804,\n 9805,\n 9806,\n 9807,\n 9808,\n 9809,\n 9810,\n 9811,\n 9855,\n 9875,\n 9889,\n 9898,\n 9899,\n 9917,\n 9918,\n 9924,\n 9925,\n 9934,\n 9940,\n 9962,\n 9970,\n 9971,\n 9973,\n 9978,\n 9981\n ]);\n const emojiBaseCps = /* @__PURE__ */ new Set([\n 9728,\n 9729,\n 9730,\n 9731,\n 9732,\n 9742,\n 9745,\n 9752,\n 9757,\n 9760,\n 9762,\n 9763,\n 9766,\n 9770,\n 9774,\n 9775,\n 9784,\n 9785,\n 9786,\n 9792,\n 9794,\n 9823,\n 9824,\n 9827,\n 9829,\n 9830,\n 9832,\n 9851,\n 9854,\n 9874,\n 9876,\n 9877,\n 9878,\n 9879,\n 9881,\n 9883,\n 9884,\n 9888,\n 9895,\n 9904,\n 9905,\n 9928,\n 9935,\n 9937,\n 9939,\n 9961,\n 9968,\n 9969,\n 9972,\n 9975,\n 9976,\n 9977\n ]);\n const needsRaster = (cp, nextCp) => {\n if (rasterCps.has(cp)) return true;\n if (emojiPresentation26.has(cp)) return true;\n if (nextCp === 65039 && (emojiBaseCps.has(cp) || emojiPresentation26.has(cp))) return true;\n if (cp >= 127462 && cp <= 127487) return true;\n if (cp >= 127744 && cp <= 129791) return true;\n return false;\n };\n const textNeedsRaster = (s) => {\n for (let i = 0; i < s.length; i++) {\n const cp = s.codePointAt(i);\n const step = cp > 65535 ? 2 : 1;\n const nextCp = i + step < s.length ? s.codePointAt(i + step) : 0;\n if (needsRaster(cp, nextCp)) return true;\n if (cp > 65535) i++;\n }\n return false;\n };\n return { needsRaster, textNeedsRaster };\n};\n\n// src/capture/script/font-metrics.ts\nvar createFontMetrics = () => {\n const metricsCache = /* @__PURE__ */ new Map();\n const localFaceMap = /* @__PURE__ */ new Map();\n const probeWidthCS = (familyExpr, weight, style) => {\n const span = document.createElement(\"span\");\n span.style.cssText = \"position:absolute;left:-9999px;top:-9999px;visibility:hidden;font-size:16px;line-height:1;white-space:pre\";\n span.style.fontFamily = familyExpr;\n span.style.fontWeight = weight;\n span.style.fontStyle = style;\n span.textContent = \"mIw0\";\n document.body.appendChild(span);\n const w = span.getBoundingClientRect().width;\n document.body.removeChild(span);\n return w;\n };\n for (const sheet of Array.from(document.styleSheets)) {\n let cssRules;\n try {\n cssRules = sheet.cssRules;\n } catch (e) {\n continue;\n }\n for (const rule of Array.from(cssRules)) {\n if (rule.constructor.name !== \"CSSFontFaceRule\") continue;\n const r = rule;\n const family = r.style.getPropertyValue(\"font-family\").trim().replace(/^[\"']|[\"']$/g, \"\").toLowerCase();\n const weight = r.style.getPropertyValue(\"font-weight\") || \"400\";\n const styleDesc = r.style.getPropertyValue(\"font-style\") || \"normal\";\n const src = r.style.getPropertyValue(\"src\");\n if (family === \"\" || /url\\(/.test(src)) continue;\n const matches = src.match(/local\\(\\s*[\"']?[^\"')]+?[\"']?\\s*\\)/g);\n if (matches == null) continue;\n const locals = [];\n for (const mm of matches) {\n const inner = /local\\(\\s*[\"']?([^\"')]+?)[\"']?\\s*\\)/.exec(mm);\n if (inner != null) locals.push(inner[1].trim());\n }\n if (locals.length === 0) continue;\n const stripVariant = (n) => n.replace(/\\s+(Bold Italic|Italic Bold|Bold|Italic|Oblique|Regular|Light|Medium|Semibold|Black)$/i, \"\").trim();\n let resolved = null;\n const aliasW = probeWidthCS('\"' + family + '\"', weight, styleDesc);\n for (const cand of locals) {\n const candW = probeWidthCS('\"' + stripVariant(cand) + '\"', weight, styleDesc);\n if (Math.abs(candW - aliasW) < 0.05) {\n resolved = cand;\n break;\n }\n }\n if (resolved == null) resolved = locals[0];\n if (!localFaceMap.has(family)) localFaceMap.set(family, resolved);\n }\n }\n const substituteAliasedFamilies = (ff) => {\n if (localFaceMap.size === 0) return ff;\n const parts = ff.split(\",\").map((s) => s.trim());\n let changed = false;\n const out = parts.map((p) => {\n const bare = p.replace(/^[\"']|[\"']$/g, \"\").toLowerCase();\n const local = localFaceMap.get(bare);\n if (local == null) return p;\n changed = true;\n return /\\s/.test(local) ? '\"' + local + '\"' : local;\n });\n return changed ? out.join(\", \") : ff;\n };\n const measureFontMetrics = (cs) => {\n const fs = cs.fontStyle || \"normal\";\n const fw = cs.fontWeight || \"400\";\n const fz = cs.fontSize || \"14px\";\n const ff = substituteAliasedFamilies(cs.fontFamily || \"sans-serif\");\n const key = fs + \"|\" + fw + \"|\" + fz + \"|\" + ff;\n let v = metricsCache.get(key);\n if (v != null) return v;\n const c = document.createElement(\"canvas\");\n const ctx = c.getContext(\"2d\");\n ctx.font = fs + \" \" + fw + \" \" + fz + \" \" + ff;\n const m = ctx.measureText(\"Mxgp\");\n v = { ascent: m.fontBoundingBoxAscent, descent: m.fontBoundingBoxDescent };\n metricsCache.set(key, v);\n return v;\n };\n return { measureFontMetrics, substituteAliasedFamilies };\n};\n\n// src/capture/script/utils.ts\nvar isUnsetCssValue = (v) => v === \"\" || v === \"initial\" || v === \"inherit\" || v === \"unset\" || v === \"revert\";\nvar firstColorRe = /(#[0-9a-fA-F]{3,8}|rgba?\\([^)]*\\)|hsla?\\([^)]*\\)|\\b(?:white|black|red|green|blue|yellow|purple|orange|gray|grey|currentColor)\\b)/;\n\n// src/capture/script/placeholder-shown.ts\nvar createPlaceholderShown = () => {\n const rules = [];\n const collect = (cssRules) => {\n if (cssRules == null) return;\n for (let i = 0; i < cssRules.length; i++) {\n const rule = cssRules[i];\n if (rule == null) continue;\n const sel = rule.selectorText;\n if (typeof sel === \"string\" && sel.indexOf(\":placeholder-shown\") >= 0) {\n const hostSel = sel.replace(/:placeholder-shown/g, \"\").trim() || \"*\";\n const decl = rule.style;\n let bg = \"\";\n if (!isUnsetCssValue(decl.backgroundColor)) bg = decl.backgroundColor;\n else if (!isUnsetCssValue(decl.background)) {\n const cm = decl.background.match(firstColorRe);\n if (cm != null) bg = cm[1];\n }\n if (bg !== \"\") rules.push({ hostSel, bg });\n }\n if (rule.cssRules != null && rule.cssRules.length > 0) collect(rule.cssRules);\n }\n };\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n collect(document.styleSheets[i].cssRules);\n } catch (e) {\n }\n }\n const resolvePlaceholderShownBg = (el) => {\n let bg = \"\";\n for (let i = 0; i < rules.length; i++) {\n const r = rules[i];\n let isMatch = false;\n try {\n isMatch = el.matches(r.hostSel);\n } catch (e) {\n }\n if (isMatch) bg = r.bg;\n }\n return bg;\n };\n return { resolvePlaceholderShownBg };\n};\n\n// src/capture/script/pseudo-rules.ts\nvar _pseudoKindRe = /^(.*?)::?(-webkit-slider-runnable-track|-webkit-slider-thumb|-webkit-progress-bar|-webkit-progress-value|-webkit-meter-bar|-webkit-meter-optimum-value|-webkit-meter-suboptimum-value|-webkit-meter-even-less-good-value|-webkit-color-swatch|-webkit-color-swatch-wrapper|-webkit-inner-spin-button|-webkit-search-cancel-button)$/;\nvar _kindMap = {\n \"-webkit-slider-runnable-track\": \"track\",\n \"-webkit-slider-thumb\": \"thumb\",\n \"-webkit-progress-bar\": \"progress-bar\",\n \"-webkit-progress-value\": \"progress-value\",\n \"-webkit-meter-bar\": \"meter-bar\",\n \"-webkit-meter-optimum-value\": \"meter-optimum\",\n \"-webkit-meter-suboptimum-value\": \"meter-suboptimum\",\n \"-webkit-meter-even-less-good-value\": \"meter-even-less-good\",\n \"-webkit-color-swatch\": \"color-swatch\",\n \"-webkit-color-swatch-wrapper\": \"color-swatch-wrapper\",\n \"-webkit-inner-spin-button\": \"inner-spin-button\",\n \"-webkit-search-cancel-button\": \"search-cancel-button\"\n};\nvar _gradientRe = /^\\s*(repeating-)?(linear|radial|conic)-gradient\\s*\\(/i;\nvar _needsResolve = (v) => v != null && v !== \"\" && (v.indexOf(\"var(\") >= 0 || v.indexOf(\"calc(\") >= 0);\nvar _propMap = {\n backgroundColor: \"background-color\",\n backgroundImage: \"background-image\",\n borderRadius: \"border-radius\",\n width: \"width\",\n height: \"height\"\n};\nvar _extractGradients = (text) => {\n const re = /(repeating-)?(linear|radial|conic)-gradient\\s*\\(/gi;\n const out = [];\n let m;\n while ((m = re.exec(text)) != null) {\n const start = m.index;\n let depth = 0;\n let i = start;\n for (; i < text.length; i++) {\n const c = text[i];\n if (c === \"(\") depth++;\n else if (c === \")\") {\n depth--;\n if (depth === 0) {\n i++;\n break;\n }\n }\n }\n out.push(text.slice(start, i));\n re.lastIndex = i;\n }\n return out.join(\", \");\n};\nvar createPseudoRules = () => {\n const rules = [];\n const collect = (cssRules) => {\n if (cssRules == null) return;\n for (let i = 0; i < cssRules.length; i++) {\n const rule = cssRules[i];\n if (rule == null) continue;\n const selectorText = rule.selectorText;\n if (typeof selectorText === \"string\") {\n const selectors = selectorText.split(\",\").map(function(s) {\n return s.trim();\n });\n for (let j = 0; j < selectors.length; j++) {\n const sel = selectors[j];\n const m = sel.match(_pseudoKindRe);\n if (m == null) continue;\n const kind = _kindMap[m[2]];\n if (kind == null) continue;\n const hostSel = m[1].trim();\n rules.push({ kind, hostSel, decl: rule.style });\n }\n }\n if (rule.cssRules != null && rule.cssRules.length > 0) collect(rule.cssRules);\n }\n };\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n collect(document.styleSheets[i].cssRules);\n } catch (e) {\n }\n }\n const _resolveOne = (host, propKey, value) => {\n if (!_needsResolve(value)) return value;\n const cssProp = _propMap[propKey] || propKey;\n const saved = host.style.getPropertyValue(cssProp);\n const savedPriority = host.style.getPropertyPriority(cssProp);\n host.style.setProperty(cssProp, value);\n const resolved = window.getComputedStyle(host).getPropertyValue(cssProp);\n if (saved === \"\") host.style.removeProperty(cssProp);\n else host.style.setProperty(cssProp, saved, savedPriority);\n return resolved !== \"\" ? resolved : value;\n };\n const resolveCornerRadius = (v, w, h) => {\n if (v == null || v === \"\") return \"0px 0px\";\n const parts = v.split(/\\s+/);\n const a = parts[0] || \"0\";\n const b = parts[1] != null ? parts[1] : a;\n const aPx = a.endsWith(\"%\") ? (parseFloat(a) || 0) * w / 100 : parseFloat(a) || 0;\n const bPx = b.endsWith(\"%\") ? (parseFloat(b) || 0) * h / 100 : parseFloat(b) || 0;\n return aPx + \"px \" + bPx + \"px\";\n };\n const resolvePseudo = (el, kind) => {\n let width = \"\", height = \"\", backgroundColor = \"\", borderRadius = \"\", backgroundImage = \"\";\n let border = \"\", padding = \"\", boxShadow = \"\";\n let matched = false;\n for (let i = 0; i < rules.length; i++) {\n const r = rules[i];\n if (r.kind !== kind) continue;\n let isMatch = false;\n try {\n isMatch = el.matches(r.hostSel);\n } catch (e) {\n }\n if (!isMatch) continue;\n matched = true;\n const d = r.decl;\n if (!isUnsetCssValue(d.width)) width = d.width;\n if (!isUnsetCssValue(d.height)) height = d.height;\n if (!isUnsetCssValue(d.borderRadius)) borderRadius = d.borderRadius;\n if (!isUnsetCssValue(d.border)) border = d.border;\n if (!isUnsetCssValue(d.padding)) padding = d.padding;\n if (!isUnsetCssValue(d.boxShadow)) boxShadow = d.boxShadow;\n if (!isUnsetCssValue(d.backgroundColor)) {\n backgroundColor = d.backgroundColor;\n } else if (!isUnsetCssValue(d.background)) {\n const cm = d.background.match(firstColorRe);\n if (cm != null) backgroundColor = cm[1];\n else if (_needsResolve(d.background)) backgroundColor = d.background;\n }\n if (!isUnsetCssValue(d.backgroundImage) && _gradientRe.test(d.backgroundImage)) {\n backgroundImage = _extractGradients(d.backgroundImage);\n } else if (!isUnsetCssValue(d.background) && _gradientRe.test(d.background)) {\n backgroundImage = _extractGradients(d.background);\n }\n }\n return {\n matched,\n width: _resolveOne(el, \"width\", width),\n height: _resolveOne(el, \"height\", height),\n backgroundColor: _resolveOne(el, \"backgroundColor\", backgroundColor),\n borderRadius: _resolveOne(el, \"borderRadius\", borderRadius),\n // Resolve var()/calc() inside gradient text via the same host-probe\n // (Chromium rewrites the gradient to fully-resolved rgb()/deg form).\n backgroundImage: _resolveOne(el, \"backgroundImage\", backgroundImage),\n border,\n padding,\n boxShadow\n };\n };\n return { resolvePseudo, resolveCornerRadius };\n};\n\n// src/capture/script/warnings.ts\nvar createWarnings = () => {\n const warnings = [];\n const seen = /* @__PURE__ */ new Set();\n const shortSelector = (el) => {\n const parts = [];\n let cur = el;\n while (cur != null && cur.nodeType === 1 && cur !== document.documentElement && parts.length < 5) {\n let p = cur.tagName.toLowerCase();\n if (cur.id) {\n p += \"#\" + cur.id;\n parts.unshift(p);\n break;\n }\n if (cur.className && typeof cur.className === \"string\") {\n const cls = cur.className.trim().split(/\\s+/).slice(0, 2).join(\".\");\n if (cls !== \"\") p += \".\" + cls;\n }\n parts.unshift(p);\n cur = cur.parentElement;\n }\n return parts.join(\" > \");\n };\n const warn = (sel, feature, detail) => {\n const k = feature + \"|\" + sel;\n if (seen.has(k)) return;\n seen.add(k);\n warnings.push({ selector: sel, feature, detail });\n };\n return { warn, shortSelector, warnings };\n};\n\n// src/capture/script/walker/lists-counters.ts\nvar createListsCountersHandler = ({ normColor }) => {\n const captureListsCounters = (el, cs, tag) => {\n const isListItem = cs.display != null && cs.display.includes(\"list-item\");\n let listMarkerIntrinsic = void 0;\n let listItemIndex = void 0;\n if (isListItem) {\n if (cs.listStyleImage && cs.listStyleImage !== \"none\") {\n const u = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.listStyleImage);\n if (u != null) {\n const img = new Image();\n img.src = u[1];\n if (img.naturalWidth > 0) listMarkerIntrinsic = { w: img.naturalWidth, h: img.naturalHeight };\n }\n }\n const parent = el.parentElement;\n if (parent != null) {\n if (tag === \"li\") {\n const siblings = Array.from(parent.children).filter((c) => c.tagName.toLowerCase() === \"li\");\n const parentTag = parent.tagName.toLowerCase();\n const reversed = parentTag === \"ol\" && parent.hasAttribute(\"reversed\");\n let start = 1;\n if (parentTag === \"ol\" && parent.hasAttribute(\"start\")) start = parseInt(parent.getAttribute(\"start\"), 10) || 1;\n if (reversed) start = siblings.length;\n let cur = start;\n for (const s of siblings) {\n if (s.hasAttribute(\"value\")) cur = parseInt(s.getAttribute(\"value\"), 10) || cur;\n if (s === el) {\n listItemIndex = cur;\n break;\n }\n cur += reversed ? -1 : 1;\n }\n } else {\n let cur = 1;\n for (const s of parent.children) {\n const sd = window.getComputedStyle(s).display;\n if (sd != null && sd.includes(\"list-item\")) {\n if (s === el) {\n listItemIndex = cur;\n break;\n }\n cur += 1;\n }\n }\n }\n }\n }\n const markerCs = isListItem ? window.getComputedStyle(el, \"::marker\") : null;\n return {\n listMarkerIntrinsic,\n listItemIndex,\n markerColor: markerCs ? normColor(markerCs.color) : void 0,\n markerFontWeight: markerCs ? markerCs.fontWeight : void 0,\n markerFontSize: markerCs ? markerCs.fontSize : void 0,\n markerContent: markerCs ? markerCs.content : void 0,\n markerFontFamily: markerCs ? markerCs.fontFamily : void 0\n };\n };\n return { captureListsCounters };\n};\n\n// src/capture/script/walker/replaced-elements.ts\nvar createReplacedElementsHandler = ({ vp }) => {\n let _replacedIdx = 0;\n const handleReplacedElement = (el, cs, tag, rect, captured, bordersOnlyCell) => {\n if (bordersOnlyCell || cs.display === \"none\" || rect.width <= 0 || rect.height <= 0) return;\n const isCustomEl = tag.indexOf(\"-\") > 0;\n const hasOpenShadow = isCustomEl && el.shadowRoot != null;\n const customElNeedsSnapshot = isCustomEl && hasOpenShadow;\n if (tag === \"iframe\" || tag === \"canvas\" || tag === \"video\" || tag === \"object\" || tag === \"embed\" || customElNeedsSnapshot) {\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const cw = rect.width - bl - br - pl - pr;\n const ch = rect.height - bt - bb - pt - pb;\n if (cw > 0 && ch > 0) {\n const rid = \"dr\" + _replacedIdx++;\n el.setAttribute(\"data-domotion-rid\", rid);\n captured.replacedSnapshot = {\n x: rect.left - vp.x + bl + pl,\n y: rect.top - vp.y + bt + pt,\n width: cw,\n height: ch,\n rid\n };\n }\n }\n if (captured.replacedSnapshot != null || captured.imageSrc != null) return;\n const ti = parseFloat(cs.textIndent) || 0;\n const ovX = cs.overflowX === \"hidden\" || cs.overflow === \"hidden\";\n const hasBgImage = cs.backgroundImage != null && cs.backgroundImage !== \"none\" && cs.backgroundImage !== \"\";\n const phark = ti <= -1e3;\n const modern = ti < 0 && ovX && cs.whiteSpace === \"nowrap\";\n if ((phark || modern) && hasBgImage) {\n const rid = \"dr\" + _replacedIdx++;\n el.setAttribute(\"data-domotion-rid\", rid);\n const titleText = (el.getAttribute && el.getAttribute(\"aria-label\") || captured.text || \"\").trim();\n captured.replacedSnapshot = {\n x: rect.left - vp.x,\n y: rect.top - vp.y,\n width: rect.width,\n height: rect.height,\n rid\n };\n captured.imageReplacement = { titleText };\n captured.styles.backgroundImage = void 0;\n captured.text = \"\";\n captured.textSegments = void 0;\n }\n };\n return { handleReplacedElement };\n};\n\n// src/capture/script/walker/masks-clips.ts\nvar createMasksClipsHandler = ({ vp, warn }) => {\n const maskDefs = /* @__PURE__ */ new Map();\n const maskRasters = /* @__PURE__ */ new Map();\n let maskRasterIdx = 0;\n const discoverMasks = (el, cs, sel) => {\n if (!cs.mask || cs.mask === \"none\" || cs.mask === \"\") return;\n const miSrc = cs.maskImage || cs.webkitMaskImage || \"\";\n const fragMatch = /^url\\(\\s*(?:\"|')?#([^\"')\\s]+)(?:\"|')?\\s*\\)$/i.exec(miSrc);\n if (fragMatch != null) {\n const fragId = fragMatch[1];\n if (!maskDefs.has(fragId)) {\n const target = document.getElementById(fragId);\n if (target != null && target.tagName.toLowerCase() === \"mask\") {\n maskDefs.set(fragId, { id: fragId, outerHTML: target.outerHTML });\n } else {\n warn(sel, \"mask\", 'mask-image fragment \"#' + fragId + '\" did not resolve to an inline <mask> element');\n }\n }\n return;\n }\n const extFragMatch = /^url\\(\\s*(?:\"|')?[^\"')#]+#[^\"')\\s]+(?:\"|')?\\s*\\)$/i.exec(miSrc);\n if (extFragMatch != null) {\n warn(sel, \"mask\", 'external-file SVG fragment refs (url(\"./file.svg#id\")) are not yet emitted (DM-496)');\n return;\n }\n const elementMatch = /^element\\(\\s*#([^)\\s]+)\\s*\\)$/i.exec(miSrc);\n if (elementMatch != null) {\n const refId = elementMatch[1];\n if (maskRasters.has(refId)) return;\n const refTarget = document.getElementById(refId);\n if (refTarget == null) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target not found in document\");\n return;\n }\n const refCs = window.getComputedStyle(refTarget);\n if (refCs.display === \"none\" || refCs.visibility === \"hidden\") {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target is display:none / hidden \\u2014 emitting empty mask\");\n maskRasters.set(refId, null);\n return;\n }\n const refRect = refTarget.getBoundingClientRect();\n if (refRect.width <= 0 || refRect.height <= 0) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target has zero-area painted box \\u2014 emitting empty mask\");\n maskRasters.set(refId, null);\n return;\n }\n if (typeof refTarget.getAnimations === \"function\") {\n try {\n const anims = refTarget.getAnimations();\n if (anims != null && anims.length > 0) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target has \" + anims.length + \" active animation(s); the rasterized snapshot is t=0 only\");\n }\n } catch (e) {\n }\n }\n const refRid = \"mr\" + maskRasterIdx++;\n refTarget.setAttribute(\"data-domotion-rid\", refRid);\n maskRasters.set(refId, {\n id: refId,\n rid: refRid,\n width: refRect.width,\n height: refRect.height,\n rect: {\n x: refRect.left - vp.x,\n y: refRect.top - vp.y,\n width: refRect.width,\n height: refRect.height\n }\n });\n return;\n }\n const supported = /^(?:repeating-)?(?:linear|radial)-gradient\\(/i.test(miSrc) || /^url\\(/i.test(miSrc);\n if (!supported) {\n warn(sel, \"mask\", \"non-gradient/non-url()/non-element() mask source \\u2014 not emitted\");\n }\n };\n return { discoverMasks, maskDefs, maskRasters };\n};\n\n// src/capture/script/walker/form-controls.ts\nvar createFormControlsHandler = ({ normColor, resolvePseudo }) => {\n const captureFormControls = (el, cs, tag) => {\n const out = {\n inputType: tag === \"input\" ? el.type || \"text\" : void 0,\n // CSS appearance / -webkit-appearance longhand for inputs. When 'none'\n // (the appearance:none custom-styled pattern) the renderer suppresses\n // its UA-default checkbox / radio chrome so the host's author-styled\n // border + background show through, with only the :checked indicator\n // overlaid on top. DM-285.\n inputAppearance: tag === \"input\" ? cs.webkitAppearance || cs.appearance || \"\" : void 0,\n checked: tag === \"input\" && (el.type === \"checkbox\" || el.type === \"radio\") ? !!el.checked : void 0,\n indeterminate: tag === \"input\" && el.type === \"checkbox\" ? !!el.indeterminate : void 0,\n disabled: tag === \"input\" || tag === \"button\" || tag === \"select\" || tag === \"textarea\" ? !!el.disabled : void 0,\n progressValue: tag === \"progress\" ? el.hasAttribute(\"value\") ? +el.value : void 0 : void 0,\n progressMax: tag === \"progress\" ? el.max || 1 : void 0,\n meterValue: tag === \"meter\" ? el.value != null ? +el.value : void 0 : void 0,\n meterMin: tag === \"meter\" ? el.min || 0 : void 0,\n meterMax: tag === \"meter\" ? el.max || 1 : void 0,\n meterLow: tag === \"meter\" ? el.low != null ? +el.low : void 0 : void 0,\n meterHigh: tag === \"meter\" ? el.high != null ? +el.high : void 0 : void 0,\n meterOptimum: tag === \"meter\" ? el.optimum != null ? +el.optimum : void 0 : void 0,\n detailsOpen: tag === \"details\" ? !!el.open : void 0,\n // Detect if author CSS hid the summary's UA disclosure marker (e.g.\n // ::marker { color: transparent }). If so, skip painting our own\n // triangle — the author's custom marker (typically ::before) is the\n // only one that should show. DM-448.\n summaryMarkerSuppressed: tag === \"details\" ? (() => {\n const sum = el.querySelector(\":scope > summary\");\n if (sum == null) return false;\n const mc = window.getComputedStyle(sum, \"::marker\").color;\n if (mc === \"transparent\") return true;\n const am = /^rgba\\(\\s*[0-9.]+\\s*,\\s*[0-9.]+\\s*,\\s*[0-9.]+\\s*,\\s*([0-9.]+)\\s*\\)$/.exec(mc);\n if (am != null && parseFloat(am[1]) === 0) return true;\n return false;\n })() : void 0,\n // Native chevron only when the select keeps UA chrome — appearance:\n // none means the page draws its own arrow via background-image, and\n // we should not stack our default chevron on top. DM-308.\n selectChevron: tag === \"select\" && el.size <= 1 && !el.multiple && cs.appearance !== \"none\" && cs.webkitAppearance !== \"none\",\n selectDisplayText: tag === \"select\" && el.size <= 1 && !el.multiple ? el.selectedOptions && el.selectedOptions.length > 0 ? (el.selectedOptions[0].textContent || \"\").trim() : el.options && el.options.length > 0 ? (el.options[0].textContent || \"\").trim() : \"\" : void 0,\n // Listbox-mode selects (size > 1 or multiple) flatten their option /\n // optgroup children into a captured row list. The renderer walks this\n // list and paints one row per entry inside the select's content rect.\n // Optgroup labels are emitted as italic+bold rows that don't count\n // against selection. DM-282.\n selectListboxOptions: tag === \"select\" && (el.size > 1 || el.multiple) ? (function() {\n const list = [];\n const kids = el.children;\n for (let ki = 0; ki < kids.length; ki++) {\n const c = kids[ki];\n if (c.tagName === \"OPTGROUP\") {\n list.push({ text: c.label || \"\", selected: false, disabled: !!c.disabled, isOptgroupLabel: true });\n const og = c.children;\n for (let gi = 0; gi < og.length; gi++) {\n const o = og[gi];\n if (o.tagName !== \"OPTION\") continue;\n list.push({ text: (o.textContent || \"\").trim(), selected: !!o.selected, disabled: !!o.disabled, isOptgroupChild: true });\n }\n } else if (c.tagName === \"OPTION\") {\n list.push({ text: (c.textContent || \"\").trim(), selected: !!c.selected, disabled: !!c.disabled });\n }\n }\n return list;\n })() : void 0,\n accentColor: tag === \"input\" || tag === \"progress\" || tag === \"meter\" ? normColor(cs.accentColor || \"auto\") : void 0,\n caretColor: tag === \"input\" || tag === \"textarea\" ? normColor(cs.caretColor || \"auto\") : void 0,\n inputValue: tag === \"input\" ? el.value || \"\" : void 0,\n inputMin: tag === \"input\" ? el.min || \"\" : void 0,\n inputMax: tag === \"input\" ? el.max || \"\" : void 0,\n inputStep: tag === \"input\" ? el.step || \"\" : void 0,\n inputMultiple: tag === \"input\" ? !!el.multiple : void 0,\n inputFileName: tag === \"input\" && el.type === \"file\" && el.files && el.files.length > 0 ? el.files[0].name : void 0\n };\n if (tag === \"progress\") {\n const bar = resolvePseudo(el, \"progress-bar\");\n const val = resolvePseudo(el, \"progress-value\");\n out.progressBarBg = bar.matched && bar.backgroundColor !== \"\" ? normColor(bar.backgroundColor) : void 0;\n out.progressBarBgImage = bar.matched && bar.backgroundImage !== \"\" ? bar.backgroundImage : void 0;\n out.progressBarRadius = bar.matched && bar.borderRadius !== \"\" ? bar.borderRadius : void 0;\n out.progressValueBg = val.matched && val.backgroundColor !== \"\" ? normColor(val.backgroundColor) : void 0;\n out.progressValueBgImage = val.matched && val.backgroundImage !== \"\" ? val.backgroundImage : void 0;\n out.progressValueRadius = val.matched && val.borderRadius !== \"\" ? val.borderRadius : void 0;\n }\n if (tag === \"meter\") {\n const bar = resolvePseudo(el, \"meter-bar\");\n const opt = resolvePseudo(el, \"meter-optimum\");\n const sub = resolvePseudo(el, \"meter-suboptimum\");\n const elg = resolvePseudo(el, \"meter-even-less-good\");\n out.meterBarBg = bar.matched && bar.backgroundColor !== \"\" ? normColor(bar.backgroundColor) : void 0;\n out.meterBarBgImage = bar.matched && bar.backgroundImage !== \"\" ? bar.backgroundImage : void 0;\n out.meterBarRadius = bar.matched && bar.borderRadius !== \"\" ? bar.borderRadius : void 0;\n out.meterOptimumBg = opt.matched && opt.backgroundColor !== \"\" ? normColor(opt.backgroundColor) : void 0;\n out.meterOptimumBgImage = opt.matched && opt.backgroundImage !== \"\" ? opt.backgroundImage : void 0;\n out.meterSuboptimumBg = sub.matched && sub.backgroundColor !== \"\" ? normColor(sub.backgroundColor) : void 0;\n out.meterSuboptimumBgImage = sub.matched && sub.backgroundImage !== \"\" ? sub.backgroundImage : void 0;\n out.meterEvenLessGoodBg = elg.matched && elg.backgroundColor !== \"\" ? normColor(elg.backgroundColor) : void 0;\n out.meterEvenLessGoodBgImage = elg.matched && elg.backgroundImage !== \"\" ? elg.backgroundImage : void 0;\n }\n if (tag === \"input\" && el.type === \"color\") {\n const swatch = resolvePseudo(el, \"color-swatch\");\n const wrap = resolvePseudo(el, \"color-swatch-wrapper\");\n out.colorSwatchBg = swatch.matched && swatch.backgroundColor !== \"\" ? normColor(swatch.backgroundColor) : void 0;\n out.colorSwatchBgImage = swatch.matched && swatch.backgroundImage !== \"\" ? swatch.backgroundImage : void 0;\n out.colorSwatchBorder = swatch.matched && swatch.border !== \"\" ? swatch.border : void 0;\n out.colorSwatchRadius = swatch.matched && swatch.borderRadius !== \"\" ? swatch.borderRadius : void 0;\n out.colorSwatchWrapperPadding = wrap.matched && wrap.padding !== \"\" ? wrap.padding : void 0;\n }\n if (tag === \"input\" && el.type === \"number\") {\n const spin = resolvePseudo(el, \"inner-spin-button\");\n out.numberSpinButtonBg = spin.matched && spin.backgroundColor !== \"\" ? normColor(spin.backgroundColor) : void 0;\n out.numberSpinButtonBorder = spin.matched && spin.border !== \"\" ? spin.border : void 0;\n out.numberSpinButtonRadius = spin.matched && spin.borderRadius !== \"\" ? spin.borderRadius : void 0;\n }\n if (tag === \"input\" && el.type === \"search\") {\n const cancel = resolvePseudo(el, \"search-cancel-button\");\n out.searchCancelButtonBg = cancel.matched && cancel.backgroundColor !== \"\" ? normColor(cancel.backgroundColor) : void 0;\n out.searchCancelButtonBorder = cancel.matched && cancel.border !== \"\" ? cancel.border : void 0;\n out.searchCancelButtonRadius = cancel.matched && cancel.borderRadius !== \"\" ? cancel.borderRadius : void 0;\n }\n if (tag === \"input\" && el.type === \"range\") {\n const ts = resolvePseudo(el, \"track\");\n const ms = resolvePseudo(el, \"thumb\");\n const elAppearance = cs.webkitAppearance || cs.appearance;\n const customAppearance = elAppearance === \"none\";\n const styledTrack = ts.matched || customAppearance;\n const styledThumb = ms.matched || customAppearance;\n out.rangeTrackBg = styledTrack && ts.backgroundColor !== \"\" ? normColor(ts.backgroundColor) : styledTrack ? \"rgba(0, 0, 0, 0)\" : void 0;\n out.rangeTrackHeight = styledTrack ? ts.height : void 0;\n out.rangeTrackRadius = styledTrack ? ts.borderRadius : void 0;\n out.rangeTrackBgImage = styledTrack && ts.backgroundImage !== \"\" ? ts.backgroundImage : void 0;\n out.rangeThumbBg = styledThumb && ms.backgroundColor !== \"\" ? normColor(ms.backgroundColor) : styledThumb ? \"rgba(0, 0, 0, 0)\" : void 0;\n out.rangeThumbWidth = styledThumb ? ms.width : void 0;\n out.rangeThumbHeight = styledThumb ? ms.height : void 0;\n out.rangeThumbRadius = styledThumb ? ms.borderRadius : void 0;\n out.rangeThumbBgImage = styledThumb && ms.backgroundImage !== \"\" ? ms.backgroundImage : void 0;\n out.rangeTrackBorder = styledTrack && ts.border !== \"\" ? ts.border : void 0;\n out.rangeThumbBorder = styledThumb && ms.border !== \"\" ? ms.border : void 0;\n out.rangeThumbBoxShadow = styledThumb && ms.boxShadow !== \"\" ? ms.boxShadow : void 0;\n }\n if (tag === \"input\" && el.type === \"file\") {\n const pseudoCs = window.getComputedStyle(el, \"::file-selector-button\");\n out.fileButtonBg = normColor(pseudoCs.backgroundColor);\n out.fileButtonColor = normColor(pseudoCs.color);\n out.fileButtonBorder = pseudoCs.border;\n out.fileButtonBorderRadius = pseudoCs.borderRadius;\n out.fileButtonPadding = pseudoCs.padding;\n out.fileButtonFontWeight = pseudoCs.fontWeight;\n out.fileButtonFontSize = pseudoCs.fontSize;\n out.fileButtonFontFamily = pseudoCs.fontFamily;\n out.fileButtonMarginRight = pseudoCs.marginRight;\n const c = document.createElement(\"canvas\");\n const ctx = c.getContext(\"2d\");\n if (ctx != null) {\n const weight = pseudoCs.fontWeight || \"400\";\n const size = pseudoCs.fontSize || \"13px\";\n const family = pseudoCs.fontFamily || \"sans-serif\";\n ctx.font = weight + \" \" + size + \" \" + family;\n const label = el.multiple ? \"Choose Files\" : \"Choose File\";\n out.fileButtonLabelWidth = ctx.measureText(label).width;\n }\n }\n return out;\n };\n return { captureFormControls };\n};\n\n// src/capture/script/walker/transforms.ts\nvar transformHasRotationOrSkew = (transformStr) => {\n if (!transformStr || transformStr === \"none\") return false;\n const m2 = /^matrix\\(\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)/.exec(transformStr);\n if (m2) {\n const b = parseFloat(m2[2]);\n const c = parseFloat(m2[3]);\n return Math.abs(b) > 1e-6 || Math.abs(c) > 1e-6;\n }\n const m3 = /^matrix3d\\(\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*[-\\d.eE]+\\s*,\\s*[-\\d.eE]+\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)/.exec(transformStr);\n if (m3) {\n const b = parseFloat(m3[2]);\n const c = parseFloat(m3[3]);\n return Math.abs(b) > 1e-6 || Math.abs(c) > 1e-6;\n }\n return false;\n};\nvar createTransformsHandler = () => {\n const wrapWithFrozenTransform = (el, cs, captureInner) => {\n const originalTransform = cs.transform;\n const hasTransform = originalTransform && originalTransform !== \"none\";\n if (!hasTransform) {\n return captureInner(el, cs, null, null);\n }\n if (transformHasRotationOrSkew(originalTransform)) {\n const inline = el.style.transform;\n el.style.transform = \"translate(0)\";\n try {\n return captureInner(el, cs, originalTransform, cs.transformOrigin);\n } finally {\n el.style.transform = inline;\n }\n }\n return captureInner(el, cs, originalTransform, cs.transformOrigin);\n };\n const threadFrozenTransform = (cs, frozenTransform, _frozenTransformOrigin) => ({\n // For elements with rotation/skew, record the ORIGINAL transform so the\n // renderer wraps a `<g transform=...>` around the (un-rotated) captured\n // rect. For pure translate/scale (or no transform), record `'none'` so\n // the renderer skips the wrap and paints the rect at its captured (=live)\n // position directly. frozenTransform is non-null whenever the element\n // originally had a non-none transform; we only stash the rotation/skew\n // string back into styles.transform.\n transform: frozenTransform != null && transformHasRotationOrSkew(frozenTransform) ? frozenTransform : \"none\",\n transformOrigin: cs.transformOrigin,\n // DM-587: separately flag elements that ORIGINALLY had a non-none\n // transform — even though we discard the value to suppress the wrap,\n // CSS Transforms 2 §4 says any non-none transform creates a stacking\n // context, and `establishesStackingContext` needs to know that for\n // z-index ordering (e.g. a `transform: translate(0)` on a positioned\n // element creates an SC that traps its descendants' z-index resolution).\n // `frozenTransform != null` is true exactly when the live cs.transform\n // was non-none at capture time.\n transformCreatesSc: frozenTransform != null\n });\n return { wrapWithFrozenTransform, threadFrozenTransform };\n};\n\n// src/capture/script/walker/borders-backgrounds.ts\nvar createBordersBackgroundsHandler = ({ normColor, resolvePlaceholderShownBg, resolveCornerRadius }) => {\n const isUaColorBorder = (tag, el, cs, side) => tag === \"input\" && el.type === \"color\" && normColor(cs[side], cs.color).replace(/\\s+/g, \"\") === \"rgb(0,0,0)\";\n const tintedBorderColor = (tag, el, cs, side) => isUaColorBorder(tag, el, cs, side) ? \"rgb(118,118,118)\" : normColor(cs[side], cs.color);\n const computeFrostedBgFallback = (cs) => {\n const bdf = cs.backdropFilter || cs.webkitBackdropFilter || \"\";\n if (bdf === \"\" || bdf === \"none\") return void 0;\n const bgCol = normColor(cs.backgroundColor, cs.color);\n let a = 1;\n const m = /rgba?\\(\\s*[^,)\\s]+[ ,]+[^,)\\s]+[ ,]+[^,)\\s]+(?:[ ,/]+([^)]+))?\\)/.exec(bgCol);\n if (m != null && m[1] != null) {\n const av = parseFloat(m[1]);\n if (!isNaN(av)) a = av;\n }\n if (a > 0.1) return void 0;\n const bodyBg = normColor(window.getComputedStyle(document.body).backgroundColor);\n let bodyA = 1;\n const bm = /rgba?\\(\\s*[^,)\\s]+[ ,]+[^,)\\s]+[ ,]+[^,)\\s]+(?:[ ,/]+([^)]+))?\\)/.exec(bodyBg);\n if (bm != null && bm[1] != null) {\n const bav = parseFloat(bm[1]);\n if (!isNaN(bav)) bodyA = bav;\n }\n return bodyA <= 0.1 ? \"rgb(255,255,255)\" : bodyBg;\n };\n const computeBackgroundIntrinsic = (cs) => {\n const bgImage = cs.backgroundImage;\n if (bgImage == null || bgImage === \"none\" || bgImage === \"\") return void 0;\n const layers = [];\n let depth = 0, start = 0;\n for (let i = 0; i < bgImage.length; i++) {\n const c = bgImage[i];\n if (c === \"(\") depth++;\n else if (c === \")\") depth--;\n else if (c === \",\" && depth === 0) {\n layers.push(bgImage.slice(start, i));\n start = i + 1;\n }\n }\n layers.push(bgImage.slice(start));\n return layers.map((layer) => {\n const u = /^\\s*url\\(\\s*(?:\"((?:\\\\.|[^\"\\\\])*)\"|'((?:\\\\.|[^'\\\\])*)'|([^)\\s]+))\\s*\\)/.exec(layer);\n if (u == null) return null;\n const raw = u[1] || u[2] || u[3] || \"\";\n if (raw === \"\") return null;\n const url = raw.replace(/\\\\(.)/g, \"$1\");\n const img = new Image();\n img.src = url;\n const w = img.naturalWidth || 0;\n const h = img.naturalHeight || 0;\n return w > 0 && h > 0 ? { w, h } : null;\n });\n };\n const computeBorderImageIntrinsic = (cs, dim) => {\n const m = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.borderImageSource || \"\");\n if (m == null) return void 0;\n const img = new Image();\n img.src = m[1];\n return img[dim] || void 0;\n };\n const captureBordersBackgrounds = (el, cs, tag, rect, isPlaceholderCapture) => ({\n backgroundColor: (function() {\n if (isPlaceholderCapture) {\n const psBg = resolvePlaceholderShownBg(el);\n if (psBg !== \"\") return normColor(psBg);\n }\n return normColor(cs.backgroundColor, cs.color);\n })(),\n borderColor: normColor(cs.borderColor, cs.color),\n borderWidth: cs.borderWidth,\n borderRadius: cs.borderRadius,\n borderTopLeftRadius: resolveCornerRadius(cs.borderTopLeftRadius, rect.width, rect.height),\n borderTopRightRadius: resolveCornerRadius(cs.borderTopRightRadius, rect.width, rect.height),\n borderBottomRightRadius: resolveCornerRadius(cs.borderBottomRightRadius, rect.width, rect.height),\n borderBottomLeftRadius: resolveCornerRadius(cs.borderBottomLeftRadius, rect.width, rect.height),\n borderTopWidth: cs.borderTopWidth,\n borderRightWidth: cs.borderRightWidth,\n borderBottomWidth: cs.borderBottomWidth,\n borderLeftWidth: cs.borderLeftWidth,\n borderTopStyle: cs.borderTopStyle,\n borderRightStyle: cs.borderRightStyle,\n borderBottomStyle: cs.borderBottomStyle,\n borderLeftStyle: cs.borderLeftStyle,\n borderTopColor: tintedBorderColor(tag, el, cs, \"borderTopColor\"),\n borderRightColor: tintedBorderColor(tag, el, cs, \"borderRightColor\"),\n borderBottomColor: tintedBorderColor(tag, el, cs, \"borderBottomColor\"),\n borderLeftColor: tintedBorderColor(tag, el, cs, \"borderLeftColor\"),\n borderCollapse: cs.borderCollapse,\n frostedBgFallback: computeFrostedBgFallback(cs),\n backgroundImage: cs.backgroundImage,\n backgroundSize: cs.backgroundSize,\n backgroundPosition: cs.backgroundPosition,\n backgroundRepeat: cs.backgroundRepeat,\n backgroundClip: cs.backgroundClip,\n // DM-462: -webkit-text-fill-color is the property that actually makes\n // the headline text transparent in the background-clip:text idiom\n // (cs.color may still report a normal value).\n webkitTextFillColor: cs.webkitTextFillColor || cs.WebkitTextFillColor || void 0,\n backgroundOrigin: cs.backgroundOrigin,\n backgroundAttachment: cs.backgroundAttachment,\n backgroundIntrinsic: computeBackgroundIntrinsic(cs),\n borderImageSource: cs.borderImageSource,\n borderImageSlice: cs.borderImageSlice,\n borderImageWidth: cs.borderImageWidth,\n borderImageOutset: cs.borderImageOutset,\n borderImageRepeat: cs.borderImageRepeat,\n borderImageIntrinsicWidth: computeBorderImageIntrinsic(cs, \"naturalWidth\"),\n borderImageIntrinsicHeight: computeBorderImageIntrinsic(cs, \"naturalHeight\"),\n outlineStyle: cs.outlineStyle,\n outlineWidth: cs.outlineWidth,\n outlineColor: normColor(cs.outlineColor),\n outlineOffset: cs.outlineOffset,\n boxShadow: cs.boxShadow\n });\n return { captureBordersBackgrounds };\n};\n\n// src/capture/script/walker/pseudo-content.ts\nvar createPseudoContentHandler = ({ vp, normColor, measureFontMetrics, textNeedsRaster }) => {\n const pickQuoteChar = (forEl, isOpen) => {\n let depth = 0;\n let p = forEl.parentElement;\n while (p != null) {\n if (p.tagName === \"Q\") depth++;\n p = p.parentElement;\n }\n const cs = window.getComputedStyle(forEl).quotes;\n if (cs == null || cs === \"\" || cs === \"none\" || cs === \"auto\") {\n const pairs = [[\"\\u201C\", \"\\u201D\"], [\"\\u2018\", \"\\u2019\"]];\n const pair = pairs[Math.min(depth, pairs.length - 1)];\n return isOpen ? pair[0] : pair[1];\n }\n const tokens = [];\n let i = 0;\n while (i < cs.length) {\n if (cs[i] === '\"') {\n let j = i + 1;\n let s = \"\";\n while (j < cs.length && cs[j] !== '\"') {\n if (cs[j] === \"\\\\\") {\n s += cs[j + 1];\n j += 2;\n } else {\n s += cs[j];\n j++;\n }\n }\n tokens.push(s);\n i = j + 1;\n } else {\n i++;\n }\n }\n if (tokens.length < 2) {\n const pair = [\"\\u201C\", \"\\u201D\"];\n return isOpen ? pair[0] : pair[1];\n }\n const pairIdx = Math.min(depth, Math.floor((tokens.length - 1) / 2));\n return isOpen ? tokens[pairIdx * 2] : tokens[pairIdx * 2 + 1];\n };\n const capturePseudoContent = (el, cs, rect, counterSnapshot) => {\n const pseudoSegments = [];\n const pseudoBoxes = [];\n for (const pseudo of [\"::before\", \"::after\"]) {\n const pcs = window.getComputedStyle(el, pseudo);\n const content = pcs.content;\n if (content == null || content === \"none\" || content === \"normal\" || content === \"\") continue;\n let text = \"\";\n let imageUrl = \"\";\n let i = 0;\n while (i < content.length) {\n const c = content[i];\n if (c === '\"' || c === \"'\") {\n const end = content.indexOf(c, i + 1);\n if (end < 0) break;\n text += content.slice(i + 1, end);\n i = end + 1;\n } else if (content.startsWith(\"attr(\", i)) {\n const end = content.indexOf(\")\", i);\n if (end < 0) break;\n const attrName = content.slice(i + 5, end).trim();\n text += el.getAttribute(attrName) || \"\";\n i = end + 1;\n } else if (content.startsWith(\"url(\", i)) {\n const end = content.indexOf(\")\", i);\n if (end < 0) break;\n let url = content.slice(i + 4, end).trim();\n if (url.startsWith('\"') && url.endsWith('\"') || url.startsWith(\"'\") && url.endsWith(\"'\")) {\n url = url.slice(1, -1);\n }\n imageUrl = url;\n i = end + 1;\n } else if (content.startsWith(\"counter(\", i) || content.startsWith(\"counters(\", i)) {\n const isCounters = content.startsWith(\"counters(\", i);\n const openIdx = i + (isCounters ? \"counters(\".length : \"counter(\".length);\n const closeIdx = content.indexOf(\")\", openIdx);\n if (closeIdx < 0) {\n i++;\n continue;\n }\n const args = content.slice(openIdx, closeIdx).split(\",\").map((s) => {\n const t = s.trim();\n if (t.startsWith('\"') && t.endsWith('\"') || t.startsWith(\"'\") && t.endsWith(\"'\")) {\n return t.slice(1, -1);\n }\n return t;\n });\n const cname = args[0];\n const sep = isCounters ? args[1] ?? \"\" : \"\";\n const snapshot = counterSnapshot.get(el) || [];\n const matches = snapshot.filter((s) => s.name === cname).map((s) => String(s.value));\n if (isCounters) {\n text += matches.length > 0 ? matches.join(sep) : \"0\";\n } else {\n text += matches.length > 0 ? matches[matches.length - 1] : \"0\";\n }\n i = closeIdx + 1;\n } else if (content.startsWith(\"open-quote\", i)) {\n text += pickQuoteChar(el, true);\n i += \"open-quote\".length;\n } else if (content.startsWith(\"close-quote\", i)) {\n text += pickQuoteChar(el, false);\n i += \"close-quote\".length;\n } else if (content.startsWith(\"no-open-quote\", i)) {\n i += \"no-open-quote\".length;\n } else if (content.startsWith(\"no-close-quote\", i)) {\n i += \"no-close-quote\".length;\n } else {\n i++;\n }\n }\n if (text === \"\" && imageUrl === \"\") {\n const bgRaw = pcs.backgroundColor;\n const hasBg = bgRaw && bgRaw !== \"\" && bgRaw !== \"rgba(0, 0, 0, 0)\" && bgRaw !== \"transparent\";\n const bwT = parseFloat(pcs.borderTopWidth) || 0;\n const bwR = parseFloat(pcs.borderRightWidth) || 0;\n const bwB = parseFloat(pcs.borderBottomWidth) || 0;\n const bwL = parseFloat(pcs.borderLeftWidth) || 0;\n const hasBorder = bwT > 0 || bwR > 0 || bwB > 0 || bwL > 0;\n const isBlockLike = pcs.display === \"block\" || pcs.display === \"inline-block\" || pcs.display === \"flex\";\n if (isBlockLike && (hasBg || hasBorder)) {\n const hostPadL = parseFloat(cs.paddingLeft) || 0;\n const hostPadT = parseFloat(cs.paddingTop) || 0;\n const hostBorL = parseFloat(cs.borderLeftWidth) || 0;\n const hostBorT = parseFloat(cs.borderTopWidth) || 0;\n const hostBorR = parseFloat(cs.borderRightWidth) || 0;\n const pMarL = parseFloat(pcs.marginLeft) || 0;\n const pPadL = parseFloat(pcs.paddingLeft) || 0;\n const pPadR = parseFloat(pcs.paddingRight) || 0;\n const pPadT = parseFloat(pcs.paddingTop) || 0;\n const pPadB = parseFloat(pcs.paddingBottom) || 0;\n const hostContentW = rect.width - hostBorL - hostBorR - hostPadL - (parseFloat(cs.paddingRight) || 0);\n const pcsW = parseFloat(pcs.width);\n const pcsH = parseFloat(pcs.height);\n const contentW = !isNaN(pcsW) ? pcsW : hostContentW - pMarL - (parseFloat(pcs.marginRight) || 0);\n const contentH = !isNaN(pcsH) ? pcsH : 0;\n const borderBoxW = contentW + pPadL + pPadR + bwL + bwR;\n const borderBoxH = contentH + pPadT + pPadB + bwT + bwB;\n let borderBoxX;\n let borderBoxY;\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pcsLeft = parseFloat(pcs.left);\n const pcsTop = parseFloat(pcs.top);\n const pcsRight = parseFloat(pcs.right);\n const pcsBottom = parseFloat(pcs.bottom);\n const paddingBoxL = rect.left - vp.x + hostBorL;\n const paddingBoxT = rect.top - vp.y + hostBorT;\n const paddingBoxR = rect.right - vp.x - hostBorR;\n const paddingBoxB = rect.bottom - vp.y - (parseFloat(cs.borderBottomWidth) || 0);\n if (!isNaN(pcsLeft)) borderBoxX = paddingBoxL + pcsLeft;\n else if (!isNaN(pcsRight)) borderBoxX = paddingBoxR - pcsRight - borderBoxW;\n else borderBoxX = paddingBoxL;\n if (!isNaN(pcsTop)) borderBoxY = paddingBoxT + pcsTop;\n else if (!isNaN(pcsBottom)) borderBoxY = paddingBoxB - pcsBottom - borderBoxH;\n else borderBoxY = paddingBoxT;\n } else {\n const pMarT = parseFloat(pcs.marginTop) || 0;\n borderBoxX = rect.left - vp.x + hostBorL + hostPadL + pMarL;\n borderBoxY = rect.top - vp.y + hostBorT + hostPadT + pMarT;\n }\n if (borderBoxW > 0 && borderBoxH > 0) {\n pseudoBoxes.push({\n x: borderBoxX,\n y: borderBoxY,\n width: borderBoxW,\n height: borderBoxH,\n backgroundColor: hasBg ? normColor(bgRaw) : void 0,\n borderTopWidth: bwT,\n borderTopColor: bwT > 0 ? normColor(pcs.borderTopColor) : void 0,\n borderTopStyle: pcs.borderTopStyle,\n borderRightWidth: bwR,\n borderRightColor: bwR > 0 ? normColor(pcs.borderRightColor) : void 0,\n borderRightStyle: pcs.borderRightStyle,\n borderBottomWidth: bwB,\n borderBottomColor: bwB > 0 ? normColor(pcs.borderBottomColor) : void 0,\n borderBottomStyle: pcs.borderBottomStyle,\n borderLeftWidth: bwL,\n borderLeftColor: bwL > 0 ? normColor(pcs.borderLeftColor) : void 0,\n borderLeftStyle: pcs.borderLeftStyle,\n borderRadius: parseFloat(pcs.borderRadius) || 0\n });\n }\n }\n continue;\n }\n if (imageUrl !== \"\" && text === \"\") {\n const probeImg = new Image();\n probeImg.src = imageUrl;\n const intrinsicW = probeImg.naturalWidth || 0;\n const intrinsicH = probeImg.naturalHeight || 0;\n let layoutW = parseFloat(pcs.width) || 0;\n let layoutH = parseFloat(pcs.height) || 0;\n if (layoutW <= 0) layoutW = intrinsicW || 24;\n if (layoutH <= 0) layoutH = intrinsicH || 24;\n const renderW = intrinsicW > 0 ? intrinsicW : layoutW;\n const renderH = intrinsicH > 0 ? intrinsicH : layoutH;\n const elTop2 = rect.top - vp.y + (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.borderTopWidth) || 0);\n const elLeft2 = rect.left - vp.x + (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.borderLeftWidth) || 0);\n const elFontSizeForImg = parseFloat(pcs.fontSize) || 14;\n const lineHImg = parseFloat(pcs.lineHeight) || elFontSizeForImg * 1.2;\n const yPosImg = elTop2 + (lineHImg - layoutH) / 2;\n pseudoSegments.push({\n isBefore: pseudo === \"::before\",\n imageUrl,\n seg: { text: \"\", x: elLeft2, y: yPosImg, width: layoutW, height: layoutH },\n renderWidth: renderW,\n renderHeight: renderH,\n color: pcs.color,\n boxMarginLeft: parseFloat(pcs.marginLeft) || 0,\n boxMarginRight: parseFloat(pcs.marginRight) || 0,\n boxBorderLeft: parseFloat(pcs.borderLeftWidth) || 0,\n boxBorderRight: parseFloat(pcs.borderRightWidth) || 0,\n boxPaddingLeft: parseFloat(pcs.paddingLeft) || 0,\n boxPaddingRight: parseFloat(pcs.paddingRight) || 0\n });\n continue;\n }\n if (text === \"\") continue;\n const fontSpec = pcs.font || pcs.fontWeight + \" \" + pcs.fontSize + \" \" + pcs.fontFamily;\n const measureCanvas = document.createElement(\"canvas\");\n const mctx = measureCanvas.getContext(\"2d\");\n mctx.font = fontSpec;\n let pseudoWidth = mctx.measureText(text).width;\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pcsW = parseFloat(pcs.width);\n if (!isNaN(pcsW) && pcsW > 0) pseudoWidth = pcsW;\n }\n const elTop = rect.top - vp.y + (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.borderTopWidth) || 0);\n const elLeft = rect.left - vp.x + (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.borderLeftWidth) || 0);\n const elFontSize = parseFloat(pcs.fontSize) || 14;\n const lineH = parseFloat(pcs.lineHeight) || elFontSize * 1.2;\n const pseudoMetrics = measureFontMetrics(pcs);\n let xPos;\n let yPos;\n let pseudoIsPositioned = false;\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pcsLeft = parseFloat(pcs.left);\n const pcsTop = parseFloat(pcs.top);\n const pcsRight = parseFloat(pcs.right);\n const pcsBottom = parseFloat(pcs.bottom);\n const paddingBoxLeft = rect.left - vp.x + (parseFloat(cs.borderLeftWidth) || 0);\n const paddingBoxTop = rect.top - vp.y + (parseFloat(cs.borderTopWidth) || 0);\n const paddingBoxRight = rect.right - vp.x - (parseFloat(cs.borderRightWidth) || 0);\n const paddingBoxBottom = rect.bottom - vp.y - (parseFloat(cs.borderBottomWidth) || 0);\n const pPadL = parseFloat(pcs.paddingLeft) || 0;\n const pPadR = parseFloat(pcs.paddingRight) || 0;\n const pPadT = parseFloat(pcs.paddingTop) || 0;\n const pPadB = parseFloat(pcs.paddingBottom) || 0;\n const pBorL = parseFloat(pcs.borderLeftWidth) || 0;\n const pBorR = parseFloat(pcs.borderRightWidth) || 0;\n const pBorT = parseFloat(pcs.borderTopWidth) || 0;\n const pBorB = parseFloat(pcs.borderBottomWidth) || 0;\n if (!isNaN(pcsLeft)) xPos = paddingBoxLeft + pcsLeft;\n else if (!isNaN(pcsRight)) xPos = paddingBoxRight - pcsRight - pseudoWidth - pPadL - pPadR - pBorL - pBorR;\n else xPos = paddingBoxLeft;\n if (!isNaN(pcsTop)) yPos = paddingBoxTop + pcsTop;\n else if (!isNaN(pcsBottom)) yPos = paddingBoxBottom - pcsBottom - lineH - pPadT - pPadB - pBorT - pBorB;\n else yPos = paddingBoxTop;\n xPos += pPadL + pBorL;\n yPos += pPadT + pBorT;\n yPos += (lineH - elFontSize) / 2;\n pseudoIsPositioned = true;\n } else {\n yPos = elTop + (lineH - elFontSize) / 2;\n const pcsMarginL = parseFloat(pcs.marginLeft) || 0;\n const pcsBorderL = parseFloat(pcs.borderLeftWidth) || 0;\n const pcsPaddingL = parseFloat(pcs.paddingLeft) || 0;\n if (pseudo === \"::before\") {\n xPos = elLeft + pcsMarginL + pcsBorderL + pcsPaddingL;\n } else {\n xPos = elLeft + rect.width - pseudoWidth - 2 * (parseFloat(cs.paddingRight) || 0);\n }\n }\n const pseudoSeg = {\n text,\n x: xPos,\n y: yPos,\n width: pseudoWidth,\n height: elFontSize,\n // Carry pseudo-specific typography so the renderer can respect\n // per-pseudo color, font-size, font-weight, font-family (CSS\n // lets pseudos style independently of their parent).\n color: pcs.color,\n fontSize: elFontSize,\n fontWeight: pcs.fontWeight,\n fontFamily: pcs.fontFamily,\n fontAscent: pseudoMetrics.ascent\n };\n const pseudoBgRaw = pcs.backgroundColor;\n const pseudoBgColor = pseudoBgRaw && pseudoBgRaw !== \"\" && pseudoBgRaw !== \"rgba(0, 0, 0, 0)\" && pseudoBgRaw !== \"transparent\" ? normColor(pseudoBgRaw) : \"\";\n const pseudoBR = parseFloat(pcs.borderRadius) || 0;\n const bw = parseFloat(pcs.borderTopWidth) || 0;\n const bwUniform = bw > 0 && (parseFloat(pcs.borderRightWidth) || 0) === bw && (parseFloat(pcs.borderBottomWidth) || 0) === bw && (parseFloat(pcs.borderLeftWidth) || 0) === bw;\n const pseudoBC = bwUniform ? normColor(pcs.borderTopColor) : \"\";\n let pseudoBoxStyles = null;\n if (pseudoBgColor !== \"\" || pseudoBR > 0 || bwUniform && pseudoBC !== \"\" && pseudoBC !== \"rgba(0, 0, 0, 0)\") {\n pseudoBoxStyles = {\n padL: parseFloat(pcs.paddingLeft) || 0,\n padR: parseFloat(pcs.paddingRight) || 0,\n padT: parseFloat(pcs.paddingTop) || 0,\n padB: parseFloat(pcs.paddingBottom) || 0,\n borL: parseFloat(pcs.borderLeftWidth) || 0,\n borR: parseFloat(pcs.borderRightWidth) || 0,\n borT: parseFloat(pcs.borderTopWidth) || 0,\n borB: parseFloat(pcs.borderBottomWidth) || 0,\n // Inline-box bg paints at line-height, not at font-size — so\n // the box's vertical extent is lineH + padding + border (not\n // fontSize). Capture lineH alongside the metrics; the post-\n // injection block uses it to compute boxH and boxY (centered\n // on the line box).\n lineH,\n fontSize: elFontSize,\n backgroundColor: pseudoBgColor !== \"\" ? pseudoBgColor : void 0,\n borderRadius: pseudoBR > 0 ? pseudoBR : void 0,\n borderWidth: bwUniform ? bw : void 0,\n borderColor: bwUniform && pseudoBC !== \"\" && pseudoBC !== \"rgba(0, 0, 0, 0)\" ? pseudoBC : void 0\n };\n }\n let allPua = text.length > 0;\n for (let _ci = 0; _ci < text.length; ) {\n const cp = text.codePointAt(_ci);\n const inPua = cp >= 57344 && cp <= 63743 || cp >= 983040 && cp <= 1048573 || cp >= 1048576 && cp <= 1114109;\n if (!inPua) {\n allPua = false;\n break;\n }\n _ci += cp > 65535 ? 2 : 1;\n }\n if (textNeedsRaster(text) || allPua) {\n if (allPua && !textNeedsRaster(text)) {\n pseudoSeg.rasterRect = {\n x: rect.left - vp.x,\n y: rect.top - vp.y,\n width: rect.width,\n height: rect.height\n };\n } else {\n pseudoSeg.rasterRect = {\n x: pseudoSeg.x,\n y: elTop,\n width: pseudoWidth,\n height: lineH\n };\n }\n }\n pseudoSegments.push({\n isBefore: pseudo === \"::before\",\n seg: pseudoSeg,\n color: pcs.color,\n isPositioned: pseudoIsPositioned,\n boxStyles: pseudoBoxStyles\n });\n }\n return { pseudoSegments, pseudoBoxes };\n };\n return { capturePseudoContent };\n};\n\n// src/capture/script/walker/input-value.ts\nvar SKIP_VALUE_TYPES = /* @__PURE__ */ new Set([\n \"range\",\n \"color\",\n \"checkbox\",\n \"radio\",\n \"file\",\n \"image\",\n \"hidden\",\n \"date\",\n \"time\",\n \"datetime-local\",\n \"month\",\n \"week\"\n]);\nvar NOT_APPLIED = { applied: false };\nvar createInputValueHandler = ({ vp, normColor, measureFontMetrics }) => {\n const captureInputValue = (el, cs, tag, rect) => {\n if (tag !== \"input\" && tag !== \"textarea\") return NOT_APPLIED;\n const inputType = tag === \"input\" ? el.type || \"text\" : \"\";\n if (SKIP_VALUE_TYPES.has(inputType)) return NOT_APPLIED;\n let isPlaceholderCapture = false;\n let text = \"\";\n if (!el.value) {\n const placeholder = el.getAttribute && el.getAttribute(\"placeholder\");\n if (placeholder != null && placeholder !== \"\") {\n isPlaceholderCapture = true;\n text = placeholder;\n } else {\n return NOT_APPLIED;\n }\n } else {\n text = inputType === \"password\" ? \"\\u2022\".repeat(el.value.length) : el.value;\n }\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n let textLeft = rect.left - vp.x + bl + pl;\n let textTop = rect.top - vp.y + bt + pt;\n const textHeight = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2;\n const textWidth = rect.width - bl * 2 - pl * 2;\n const display = cs.display;\n const isFlexLike = display === \"flex\" || display === \"inline-flex\" || display === \"grid\" || display === \"inline-grid\";\n if (isFlexLike && cs.alignItems === \"center\") {\n const contentH = rect.height - bt - bb - pt - pb;\n if (contentH > textHeight + 0.5) {\n textTop = rect.top - vp.y + bt + pt + (contentH - textHeight) / 2;\n }\n }\n const metrics = measureFontMetrics(cs);\n const fontAscent = metrics.ascent;\n const fontDescent = metrics.descent;\n const fontH = fontAscent + fontDescent;\n if (fontH > textHeight + 0.5) {\n textTop -= (fontH - textHeight) / 2;\n }\n let inputXOffsets;\n if (text.length > 0 && tag === \"input\") {\n const probe = document.createElement(\"span\");\n probe.style.position = \"absolute\";\n probe.style.left = \"-9999px\";\n probe.style.top = \"-9999px\";\n probe.style.visibility = \"hidden\";\n probe.style.whiteSpace = \"pre\";\n probe.style.fontFamily = cs.fontFamily;\n probe.style.fontSize = cs.fontSize;\n probe.style.fontWeight = cs.fontWeight;\n probe.style.fontStyle = cs.fontStyle;\n probe.style.letterSpacing = cs.letterSpacing;\n probe.style.fontKerning = cs.fontKerning;\n probe.style.fontVariationSettings = cs.fontVariationSettings;\n probe.style.fontFeatureSettings = cs.fontFeatureSettings;\n probe.textContent = text;\n document.body.appendChild(probe);\n const probeNode = probe.firstChild;\n if (probeNode != null) {\n const probeBox = probe.getBoundingClientRect();\n const probeOriginX = probeBox.left;\n const xs = [];\n let i = 0;\n while (i < text.length) {\n const code = text.charCodeAt(i);\n const isHigh = code >= 55296 && code <= 56319 && i + 1 < text.length;\n const step = isHigh ? 2 : 1;\n const rng = document.createRange();\n rng.setStart(probeNode, i);\n rng.setEnd(probeNode, i + step);\n const cr = rng.getBoundingClientRect();\n const left = cr.left - probeOriginX + textLeft;\n for (let k = 0; k < step; k++) xs.push(left);\n i += step;\n }\n const contentBoxW = rect.width - bl - br - pl - pr;\n const probeW = probeBox.width;\n const slack = contentBoxW - probeW;\n const align = cs.textAlign;\n const dir = cs.direction;\n let shift = 0;\n if (slack > 0) {\n if (align === \"center\") shift = slack / 2;\n else if (align === \"right\" || align === \"end\" && dir !== \"rtl\" || align === \"start\" && dir === \"rtl\") shift = slack;\n }\n if (shift !== 0) {\n textLeft += shift;\n for (let k = 0; k < xs.length; k++) xs[k] += shift;\n }\n inputXOffsets = xs;\n }\n document.body.removeChild(probe);\n }\n let placeholderColor;\n let placeholderFontStyle;\n let placeholderFontWeight;\n if (isPlaceholderCapture) {\n const phCs = window.getComputedStyle(el, \"::placeholder\");\n placeholderColor = normColor(phCs.color || cs.color);\n placeholderFontStyle = phCs.fontStyle;\n placeholderFontWeight = phCs.fontWeight;\n }\n return {\n applied: true,\n text,\n textLeft,\n textTop,\n textHeight,\n textWidth,\n fontAscent,\n fontDescent,\n inputXOffsets,\n isPlaceholderCapture,\n placeholderColor,\n placeholderFontStyle,\n placeholderFontWeight\n };\n };\n return { captureInputValue };\n};\n\n// src/capture/script/walker/text-segments.ts\nvar computeElementRaster = (el, cs, tag, rect, vp) => {\n const hasTextareaValue = tag === \"textarea\" && el.value;\n const hasNonHorizontalText = cs.writingMode && cs.writingMode !== \"horizontal-tb\" && (el.textContent || \"\").trim() !== \"\";\n const isTextInput = tag === \"input\" && (el.type === \"text\" || el.type === \"search\" || el.type === \"email\" || el.type === \"tel\" || el.type === \"url\" || el.type === \"password\" || el.type === \"number\" || el.type === \"\" || el.type == null);\n const hasInputText = isTextInput && (el.value || el.getAttribute && el.getAttribute(\"placeholder\"));\n if (!hasTextareaValue && !hasNonHorizontalText && !hasInputText) return void 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n return {\n x: rect.left - vp.x + bl + pl,\n y: rect.top - vp.y + bt + pt,\n width: Math.max(1, rect.width - bl - br - pl - pr),\n height: Math.max(1, rect.height - bt - bb - pt - pb)\n };\n};\nvar createTextSegmentsHandler = ({ vp, measureFontMetrics, needsRaster }) => {\n const captureTextSegments = (el, cs) => {\n const textSegments = [];\n let text = \"\";\n let minLeft = Infinity;\n let minTop = Infinity;\n let maxRight = -Infinity;\n let maxBottom = -Infinity;\n const flStyle = window.getComputedStyle(el, \"::first-letter\");\n const elFsRaw = parseFloat(cs.fontSize) || 0;\n const flFsRaw = parseFloat(flStyle.fontSize) || 0;\n const firstLetterStyled = flFsRaw > 0 && Math.abs(flFsRaw - elFsRaw) > 0.5;\n let firstCharSeen = false;\n for (const node of el.childNodes) {\n if (node.nodeType !== Node.TEXT_NODE) continue;\n let raw = node.textContent || \"\";\n const tt = cs.textTransform;\n if (tt === \"uppercase\") raw = raw.toUpperCase();\n else if (tt === \"lowercase\") raw = raw.toLowerCase();\n else if (tt === \"capitalize\") raw = raw.replace(/\\b\\p{L}/gu, (ch) => ch.toUpperCase());\n if (!raw.trim()) continue;\n text += raw.trim() + \" \";\n const lines = [];\n let cur = null;\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n const isHighSurrogate = code >= 55296 && code <= 56319 && i + 1 < raw.length;\n const step = isHighSurrogate ? 2 : 1;\n const r = document.createRange();\n r.setStart(node, i);\n r.setEnd(node, i + step);\n const cr = r.getBoundingClientRect();\n const isWs = step === 1 && /\\s/.test(raw[i]);\n if (cr.width === 0 && (cr.height === 0 || isWs)) {\n i += step - 1;\n continue;\n }\n const ch = raw.slice(i, i + step);\n const charRec = { ch, left: cr.left, top: cr.top, right: cr.right, bottom: cr.bottom };\n if (cur == null || Math.abs(cr.top - cur.top) > 1) {\n if (cur != null) lines.push(cur);\n cur = { chars: [charRec], top: cr.top, bottom: cr.bottom, left: cr.left, right: cr.right };\n } else {\n cur.chars.push(charRec);\n cur.left = Math.min(cur.left, cr.left);\n cur.right = Math.max(cur.right, cr.right);\n cur.bottom = Math.max(cur.bottom, cr.bottom);\n }\n i += step - 1;\n }\n if (cur != null) lines.push(cur);\n const fragmentedLines = [];\n for (const ln of lines) {\n if (ln.chars.length <= 1) {\n fragmentedLines.push(ln);\n continue;\n }\n let frag = { chars: [ln.chars[0]], top: ln.top, bottom: ln.bottom };\n const fragments = [frag];\n for (let ci = 1; ci < ln.chars.length; ci++) {\n const prev = ln.chars[ci - 1];\n const cc = ln.chars[ci];\n const leftJump = cc.left < prev.left - 80;\n const rightJump = cc.left > prev.right + 80;\n if (leftJump || rightJump) {\n frag = { chars: [cc], top: ln.top, bottom: ln.bottom };\n fragments.push(frag);\n } else {\n frag.chars.push(cc);\n }\n }\n for (const f of fragments) {\n let l = Infinity;\n let r = -Infinity;\n for (const c of f.chars) {\n if (c.left < l) l = c.left;\n if (c.right > r) r = c.right;\n }\n f.left = l;\n f.right = r;\n fragmentedLines.push(f);\n }\n }\n lines.length = 0;\n for (const fl of fragmentedLines) lines.push(fl);\n for (const ln of lines) {\n ln.text = ln.chars.map((c) => c.ch).join(\"\");\n const xo = [];\n for (const c of ln.chars) {\n for (let k = 0; k < c.ch.length; k++) xo.push(c.left);\n }\n ln.xOffsets = xo;\n }\n for (const line of lines) {\n const visualText = line.text.replace(/[\\t\\n\\r]/g, \" \");\n if (visualText.replace(/\\s/g, \"\") === \"\") continue;\n const rasterGlyphs = [];\n let utf16Idx = 0;\n for (let ci = 0; ci < line.chars.length; ci++) {\n const cRec = line.chars[ci];\n const cp = cRec.ch.codePointAt(0);\n const nextCh = ci + 1 < line.chars.length ? line.chars[ci + 1].ch : \"\";\n const nextCp = nextCh ? nextCh.codePointAt(0) : 0;\n const isFirstLetter = firstLetterStyled && !firstCharSeen && /\\S/.test(cRec.ch);\n if (isFirstLetter) firstCharSeen = true;\n if (cp != null && needsRaster(cp, nextCp) || isFirstLetter) {\n rasterGlyphs.push({\n charIndex: utf16Idx,\n rect: {\n x: cRec.left - vp.x,\n y: cRec.top - vp.y,\n width: cRec.right - cRec.left,\n height: cRec.bottom - cRec.top\n },\n // ::first-letter drop caps: suppress the path glyph so\n // only the rasterized big letter paints (DM-439).\n suppressGlyph: isFirstLetter ? true : void 0\n });\n }\n utf16Idx += cRec.ch.length;\n }\n textSegments.push({\n text: visualText,\n x: line.left - vp.x,\n y: line.top - vp.y,\n width: line.right - line.left,\n height: line.bottom - line.top,\n xOffsets: line.xOffsets.map((v) => v - vp.x),\n rasterGlyphs: rasterGlyphs.length > 0 ? rasterGlyphs : void 0\n });\n minLeft = Math.min(minLeft, line.left);\n minTop = Math.min(minTop, line.top);\n maxRight = Math.max(maxRight, line.right);\n maxBottom = Math.max(maxBottom, line.bottom);\n }\n }\n if (textSegments.length > 0) {\n const flLineStyle = window.getComputedStyle(el, \"::first-line\");\n const firstSeg = textSegments[0];\n if (flLineStyle.fontVariant !== \"\" && flLineStyle.fontVariant !== cs.fontVariant) {\n firstSeg.fontVariant = flLineStyle.fontVariant;\n }\n if (flLineStyle.color !== \"\" && flLineStyle.color !== cs.color) {\n firstSeg.color = flLineStyle.color;\n }\n if (flLineStyle.fontWeight !== \"\" && flLineStyle.fontWeight !== cs.fontWeight) {\n firstSeg.fontWeight = flLineStyle.fontWeight;\n }\n if (flLineStyle.fontStyle !== \"\" && flLineStyle.fontStyle !== cs.fontStyle) {\n firstSeg.fontStyle = flLineStyle.fontStyle;\n }\n const flFs = parseFloat(flLineStyle.fontSize);\n const elFs2 = parseFloat(cs.fontSize);\n if (flFs > 0 && Math.abs(flFs - elFs2) > 0.1) {\n firstSeg.fontSize = flFs;\n }\n }\n text = text.trim();\n if (minLeft < Infinity) {\n const metrics = measureFontMetrics(cs);\n return {\n applied: true,\n text,\n textSegments,\n textLeft: minLeft - vp.x,\n textTop: minTop - vp.y,\n textWidth: maxRight - minLeft,\n textHeight: maxBottom - minTop,\n fontAscent: metrics.ascent,\n fontDescent: metrics.descent\n };\n }\n return { applied: true, text, textSegments };\n };\n return { captureTextSegments };\n};\n\n// src/capture/script/walker/pseudo-inject.ts\nvar createPseudoInjectHandler = () => {\n const injectPseudoSegments = (el, pseudoSegments, textSegments, state) => {\n const pseudoImages = [];\n let { text, textLeft, textTop, textWidth, textHeight, fontAscent } = state;\n for (const p of pseudoSegments) {\n if (p.imageUrl) {\n const mL = p.boxMarginLeft || 0;\n const mR = p.boxMarginRight || 0;\n const bL = p.boxBorderLeft || 0;\n const bR = p.boxBorderRight || 0;\n const pL = p.boxPaddingLeft || 0;\n const pR = p.boxPaddingRight || 0;\n if (p.isBefore && textSegments.length > 0) {\n const firstSeg = textSegments[0];\n p.seg.x = firstSeg.x - p.seg.width - pR - bR - mR;\n p.seg.y = firstSeg.y + (firstSeg.height - p.seg.height) / 2;\n } else if (!p.isBefore && textSegments.length > 0) {\n const lastSeg = textSegments[textSegments.length - 1];\n p.seg.x = lastSeg.x + lastSeg.width + mL + bL + pL;\n p.seg.y = lastSeg.y + (lastSeg.height - p.seg.height) / 2;\n }\n pseudoImages.push({\n url: p.imageUrl,\n x: p.seg.x,\n y: p.seg.y,\n width: p.renderWidth,\n height: p.renderHeight\n });\n continue;\n }\n if (p.isPositioned) {\n if (p.isBefore) textSegments.unshift(p.seg);\n else textSegments.push(p.seg);\n } else if (p.isBefore && textSegments.length > 0) {\n const firstSeg = textSegments[0];\n const bs = p.boxStyles || {};\n const mRb = parseFloat(window.getComputedStyle(el, \"::before\").marginRight) || 0;\n p.seg.x = firstSeg.x - p.seg.width - (bs.padR || 0) - (bs.borR || 0) - mRb;\n p.seg.y = firstSeg.y;\n p.seg.height = firstSeg.height;\n textSegments.unshift(p.seg);\n } else if (!p.isBefore && textSegments.length > 0) {\n const lastSeg = textSegments[textSegments.length - 1];\n const bs = p.boxStyles || {};\n const mLa = parseFloat(window.getComputedStyle(el, \"::after\").marginLeft) || 0;\n p.seg.x = lastSeg.x + lastSeg.width + mLa + (bs.borL || 0) + (bs.padL || 0);\n p.seg.y = lastSeg.y;\n p.seg.height = lastSeg.height;\n textSegments.push(p.seg);\n } else {\n textSegments.push(p.seg);\n }\n if (textSegments.length === 1 && textSegments[0] === p.seg) {\n textLeft = p.seg.x;\n textTop = p.seg.y;\n textWidth = p.seg.width;\n textHeight = p.seg.height;\n if (p.seg.fontAscent != null) fontAscent = p.seg.fontAscent;\n }\n if (p.seg.rasterRect != null) {\n const isHostSized = p.seg.rasterRect.width > p.seg.width + 1;\n if (!isHostSized) {\n p.seg.rasterRect.x = p.seg.x;\n p.seg.rasterRect.y = p.seg.y;\n p.seg.rasterRect.height = p.seg.height;\n }\n }\n if (p.boxStyles != null) {\n const bs = p.boxStyles;\n const lineCenter = p.seg.y + bs.fontSize / 2;\n const boxTop = lineCenter - bs.lineH / 2 - bs.padT - bs.borT;\n const bx = p.seg.x - bs.padL - bs.borL;\n const bw = p.seg.width + bs.padL + bs.padR + bs.borL + bs.borR;\n const bh = bs.lineH + bs.padT + bs.padB + bs.borT + bs.borB;\n if (bw > 0 && bh > 0) {\n p.seg.pseudoBox = {\n x: bx,\n y: boxTop,\n width: bw,\n height: bh,\n backgroundColor: bs.backgroundColor,\n borderRadius: bs.borderRadius,\n borderWidth: bs.borderWidth,\n borderColor: bs.borderColor\n };\n }\n }\n text = (p.isBefore ? p.seg.text + \" \" : \" \" + p.seg.text) + text;\n }\n return { pseudoImages, text, textLeft, textTop, textWidth, textHeight, fontAscent };\n };\n return { injectPseudoSegments };\n};\n\n// src/capture/script/index.ts\nreturn ((args) => {\n const sel = args.sel;\n const vp = args.vp;\n const { normColor } = createColorNorm();\n const { needsRaster, textNeedsRaster } = createEmojiDetect();\n const { measureFontMetrics: _measureFontMetrics, substituteAliasedFamilies: _substituteAliasedFamilies } = createFontMetrics();\n const { resolvePlaceholderShownBg: _resolvePlaceholderShownBg } = createPlaceholderShown();\n const { resolvePseudo: _resolvePseudo, resolveCornerRadius: _resolveCornerRadius } = createPseudoRules();\n const { warn, shortSelector, warnings: _warnings } = createWarnings();\n const { captureListsCounters } = createListsCountersHandler({ normColor });\n const { handleReplacedElement } = createReplacedElementsHandler({ vp });\n const { discoverMasks, maskDefs: _maskDefs, maskRasters: _maskRasters } = createMasksClipsHandler({ vp, warn });\n const { captureFormControls } = createFormControlsHandler({ normColor, resolvePseudo: _resolvePseudo });\n const { wrapWithFrozenTransform, threadFrozenTransform } = createTransformsHandler();\n const { captureBordersBackgrounds } = createBordersBackgroundsHandler({\n normColor,\n resolvePlaceholderShownBg: _resolvePlaceholderShownBg,\n resolveCornerRadius: _resolveCornerRadius\n });\n const { capturePseudoContent } = createPseudoContentHandler({\n vp,\n normColor,\n measureFontMetrics: _measureFontMetrics,\n textNeedsRaster\n });\n const { captureInputValue } = createInputValueHandler({ vp, normColor, measureFontMetrics: _measureFontMetrics });\n const { captureTextSegments } = createTextSegmentsHandler({ vp, measureFontMetrics: _measureFontMetrics, needsRaster });\n const { injectPseudoSegments } = createPseudoInjectHandler();\n const capture = (el) => {\n const cs = window.getComputedStyle(el);\n return wrapWithFrozenTransform(el, cs, captureInner);\n };\n const captureInner = (el, cs, frozenTransform, frozenTransformOrigin) => {\n const rect = el.getBoundingClientRect();\n const outsideViewport = rect.right < vp.x || rect.bottom < vp.y || rect.left > vp.x + vp.width || rect.top > vp.y + vp.height;\n if (outsideViewport && !_fixedAncestors.has(el) && !_transformInfluenced.has(el)) return null;\n const _earlyTag = el.tagName.toLowerCase();\n const bordersOnlyCell = (_earlyTag === \"td\" || _earlyTag === \"th\") && (cs.visibility === \"hidden\" || cs.visibility === \"collapse\") && cs.borderCollapse === \"collapse\";\n if (cs.display === \"none\") return null;\n if ((cs.visibility === \"hidden\" || cs.visibility === \"collapse\") && !bordersOnlyCell) return null;\n const _clip = cs.clip || \"\";\n if (_clip !== \"auto\" && _clip !== \"\" && _clip !== \"normal\") {\n const _cm = _clip.match(/rect\\(\\s*([^,\\s]+)[ ,]+([^,\\s]+)[ ,]+([^,\\s]+)[ ,]+([^)\\s]+)\\s*\\)/);\n if (_cm != null && parseFloat(_cm[1]) === 0 && parseFloat(_cm[2]) === 0 && parseFloat(_cm[3]) === 0 && parseFloat(_cm[4]) === 0) {\n return null;\n }\n }\n const _cp = cs.clipPath || \"\";\n if (_cp.indexOf(\"inset(\") === 0) {\n const _ipm = _cp.match(/inset\\(\\s*([0-9.]+)\\s*%/);\n if (_ipm != null && parseFloat(_ipm[1]) >= 50) return null;\n }\n if (rect.width <= 1 && rect.height <= 1 && (cs.overflow === \"hidden\" || cs.overflowX === \"hidden\" || cs.overflowY === \"hidden\") && (cs.position === \"absolute\" || cs.position === \"fixed\")) {\n return null;\n }\n const zeroSized = rect.width === 0 || rect.height === 0;\n const _hasAnim = el.dataset != null && el.dataset.domotionAnim != null && el.dataset.domotionAnim !== \"\";\n if (zeroSized && el.children.length === 0 && !_hasAnim) return null;\n const tag = el.tagName.toLowerCase();\n const sel2 = shortSelector(el);\n if (cs.transform && cs.transform.startsWith(\"matrix3d\")) {\n warn(sel2, \"transform-3d\", \"matrix3d/translate3d/rotate3d/perspective downgraded to 2D submatrix; z component + perspective dropped (SK-1135)\");\n }\n if (cs.backdropFilter && cs.backdropFilter !== \"none\") {\n warn(sel2, \"backdrop-filter\", \"captured but not emitted \\u2014 no SVG equivalent\");\n }\n if (cs.position === \"fixed\" || cs.position === \"sticky\") {\n warn(sel2, \"position:\" + cs.position, \"rendered as a static snapshot at t=0; scroll-following behavior is not animated\");\n }\n discoverMasks(el, cs, sel2);\n if (cs.borderImageSource && cs.borderImageSource !== \"none\") {\n warn(sel2, \"border-image\", \"9-slice composition pending (SK-466); border-image-source ignored\");\n }\n if (tag === \"iframe\" || tag === \"canvas\" || tag === \"video\" || tag === \"object\" || tag === \"embed\") {\n warn(sel2, \"<\" + tag + \">\", \"element type is not rendered by domotion\");\n }\n if ((cs.overflowX === \"auto\" || cs.overflowX === \"scroll\" || cs.overflowY === \"auto\" || cs.overflowY === \"scroll\") && (el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1)) {\n warn(sel2, \"scrollbar\", \"native scrollbar chrome not emulated yet (SK-468); content is clipped but no scroll indicator\");\n }\n if (cs.textAlign === \"justify\") {\n warn(sel2, \"text-align:justify\", \"path-mode renderer does not space-stretch justified text\");\n }\n let text = \"\";\n let imageSrc = void 0;\n let svgContent = void 0;\n let textTop = 0;\n let textLeft = 0;\n let textHeight = 0;\n let textWidth = 0;\n let fontAscent = 0;\n let fontDescent = 0;\n let inputXOffsets;\n let placeholderColor;\n let placeholderFontStyle;\n let placeholderFontWeight;\n const textSegments = [];\n const _pcResult = capturePseudoContent(el, cs, rect, _counterSnapshot);\n const pseudoSegments = _pcResult.pseudoSegments;\n const pseudoBoxes = _pcResult.pseudoBoxes;\n const textIsHiddenFallback = tag === \"meter\" || tag === \"progress\" || tag === \"datalist\" || tag === \"option\" || tag === \"optgroup\";\n if (tag !== \"svg\" && tag !== \"img\" && !textIsHiddenFallback) {\n const _iv = captureInputValue(el, cs, tag, rect);\n var isPlaceholderCapture = false;\n if (_iv.applied) {\n text = _iv.text;\n textLeft = _iv.textLeft;\n textTop = _iv.textTop;\n textHeight = _iv.textHeight;\n textWidth = _iv.textWidth;\n fontAscent = _iv.fontAscent;\n fontDescent = _iv.fontDescent;\n inputXOffsets = _iv.inputXOffsets;\n isPlaceholderCapture = _iv.isPlaceholderCapture;\n placeholderColor = _iv.placeholderColor;\n placeholderFontStyle = _iv.placeholderFontStyle;\n placeholderFontWeight = _iv.placeholderFontWeight;\n } else {\n const _ts = captureTextSegments(el, cs);\n text = _ts.text;\n for (const seg of _ts.textSegments) textSegments.push(seg);\n if (_ts.textLeft != null) {\n textLeft = _ts.textLeft;\n textTop = _ts.textTop;\n textWidth = _ts.textWidth;\n textHeight = _ts.textHeight;\n fontAscent = _ts.fontAscent;\n fontDescent = _ts.fontDescent;\n }\n }\n }\n const _pi = injectPseudoSegments(el, pseudoSegments, textSegments, {\n text,\n textLeft,\n textTop,\n textWidth,\n textHeight,\n fontAscent\n });\n const pseudoImages = _pi.pseudoImages;\n text = _pi.text;\n textLeft = _pi.textLeft;\n textTop = _pi.textTop;\n textWidth = _pi.textWidth;\n textHeight = _pi.textHeight;\n fontAscent = _pi.fontAscent;\n let textImageUri = void 0;\n const textImageScale = 2;\n if (tag === \"img\") {\n imageSrc = el.currentSrc || el.src;\n if (el.naturalWidth > 0 && el.naturalHeight > 0) {\n var imageIntrinsic = { w: el.naturalWidth, h: el.naturalHeight };\n }\n var imageBroken = el.complete && el.naturalWidth === 0;\n var imageAlt = el.alt || \"\";\n } else if (tag === \"input\" && el.type === \"image\") {\n imageSrc = el.src;\n }\n const _listsCounters = captureListsCounters(el, cs, tag);\n if (tag === \"svg\") {\n let _isUnresolvedCssExpr2 = function(v) {\n return v != null && _unresolvedCssExprRe.test(v);\n }, _hasConcreteAttr2 = function(node, attr) {\n return node.hasAttribute(attr) && !_isUnresolvedCssExpr2(node.getAttribute(attr));\n };\n var _isUnresolvedCssExpr = _isUnresolvedCssExpr2, _hasConcreteAttr = _hasConcreteAttr2;\n const svgFill = cs.fill;\n const svgStroke = cs.stroke;\n const svgStrokeWidth = cs.strokeWidth;\n const svgFontFamily = cs.fontFamily;\n const clone = el.cloneNode(true);\n const _unresolvedCssExprRe = /\\b(?:var|calc|env|attr)\\s*\\(/;\n if (svgFill && svgFill !== \"\" && !_hasConcreteAttr2(el, \"fill\")) clone.setAttribute(\"fill\", svgFill);\n if (svgStroke && svgStroke !== \"\" && svgStroke !== \"none\" && !_hasConcreteAttr2(el, \"stroke\")) clone.setAttribute(\"stroke\", svgStroke);\n if (svgStrokeWidth && svgStrokeWidth !== \"\" && !_hasConcreteAttr2(el, \"stroke-width\")) clone.setAttribute(\"stroke-width\", svgStrokeWidth);\n if (svgFontFamily && svgFontFamily !== \"\" && !el.hasAttribute(\"font-family\")) {\n clone.setAttribute(\"font-family\", svgFontFamily);\n }\n const _bakeSvgAttrs = [\"fill\", \"stroke\", \"stroke-width\", \"stroke-dasharray\", \"stroke-linecap\", \"stroke-linejoin\", \"stroke-opacity\", \"fill-opacity\", \"opacity\"];\n const _walkBake = (origNode, cloneNode) => {\n if (origNode.nodeType !== 1) return;\n const ns = origNode.namespaceURI;\n if (ns === \"http://www.w3.org/2000/svg\" && origNode !== el) {\n const ocs = window.getComputedStyle(origNode);\n for (const attr of _bakeSvgAttrs) {\n const camel = attr.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n const val = ocs[camel];\n if (val != null && val !== \"\" && !_hasConcreteAttr2(origNode, attr)) {\n cloneNode.setAttribute(attr, val);\n }\n }\n var transformVal = ocs.transform;\n if (transformVal != null && transformVal !== \"\" && transformVal !== \"none\") {\n var transformOriginVal = ocs.transformOrigin || \"0 0\";\n var originParts = transformOriginVal.trim().split(/\\s+/);\n var ox = parseFloat(originParts[0] || \"0\") || 0;\n var oy = parseFloat(originParts[1] || \"0\") || 0;\n try {\n if (typeof origNode.getBBox === \"function\") {\n var bbox = origNode.getBBox();\n ox += bbox.x;\n oy += bbox.y;\n }\n } catch (e) {\n }\n var composed;\n if (ox === 0 && oy === 0) {\n composed = transformVal;\n } else {\n composed = \"translate(\" + ox + \",\" + oy + \") \" + transformVal + \" translate(\" + -ox + \",\" + -oy + \")\";\n }\n cloneNode.setAttribute(\"transform\", composed);\n }\n }\n const oChildren = origNode.children;\n const cChildren = cloneNode.children;\n const n = Math.min(oChildren.length, cChildren.length);\n for (let i = 0; i < n; i++) _walkBake(oChildren[i], cChildren[i]);\n };\n _walkBake(el, clone);\n const _svgNS = \"http://www.w3.org/2000/svg\";\n const _xlinkNS = \"http://www.w3.org/1999/xlink\";\n const _resolveUseRefs = (root2, depth) => {\n if (depth > 5) return;\n var uses = root2.querySelectorAll ? root2.querySelectorAll(\"use\") : [];\n for (var ui = 0; ui < uses.length; ui++) {\n var useEl = uses[ui];\n var href = useEl.getAttribute(\"href\");\n if (href == null || href === \"\") href = useEl.getAttributeNS(_xlinkNS, \"href\") || \"\";\n if (href.charAt(0) !== \"#\") continue;\n var targetId = href.slice(1);\n var target = document.getElementById(targetId);\n if (target == null) continue;\n if (target.namespaceURI !== _svgNS) continue;\n if (typeof target.getAnimations === \"function\") {\n try {\n var anims = target.getAnimations({ subtree: true });\n if (anims != null && anims.length > 0) {\n warn(sel2, \"inline-svg\", '<use href=\"#' + targetId + '\"> resolved to a CSS-animated subtree; the inlined SVG carries the t=0 computed paint state (no animation in the output)');\n }\n } catch (e) {\n }\n }\n var ux = parseFloat(useEl.getAttribute(\"x\") || \"0\") || 0;\n var uy = parseFloat(useEl.getAttribute(\"y\") || \"0\") || 0;\n var uw = useEl.getAttribute(\"width\");\n var uh = useEl.getAttribute(\"height\");\n var targetTag = target.tagName.toLowerCase();\n var replacement;\n if (targetTag === \"symbol\") {\n var vb = target.getAttribute(\"viewBox\") || \"\";\n var par = target.getAttribute(\"preserveAspectRatio\") || \"\";\n replacement = document.createElementNS(_svgNS, \"svg\");\n if (ux !== 0) replacement.setAttribute(\"x\", String(ux));\n if (uy !== 0) replacement.setAttribute(\"y\", String(uy));\n if (uw != null) replacement.setAttribute(\"width\", uw);\n if (uh != null) replacement.setAttribute(\"height\", uh);\n if (vb !== \"\") replacement.setAttribute(\"viewBox\", vb);\n if (par !== \"\") replacement.setAttribute(\"preserveAspectRatio\", par);\n for (var ci = 0; ci < target.children.length; ci++) {\n var clonedChild = target.children[ci].cloneNode(true);\n replacement.appendChild(clonedChild);\n _walkBake(target.children[ci], clonedChild);\n }\n } else {\n replacement = document.createElementNS(_svgNS, \"g\");\n if (ux !== 0 || uy !== 0) {\n replacement.setAttribute(\"transform\", \"translate(\" + ux + \",\" + uy + \")\");\n }\n var clonedTarget = target.cloneNode(true);\n if (clonedTarget.removeAttribute) clonedTarget.removeAttribute(\"id\");\n replacement.appendChild(clonedTarget);\n _walkBake(target, clonedTarget);\n }\n var _useAttrs = [\"fill\", \"stroke\", \"stroke-width\", \"opacity\", \"class\", \"style\"];\n for (var ai = 0; ai < _useAttrs.length; ai++) {\n var av = useEl.getAttribute(_useAttrs[ai]);\n if (av != null && av !== \"\") replacement.setAttribute(_useAttrs[ai], av);\n }\n useEl.parentNode.replaceChild(replacement, useEl);\n _resolveUseRefs(replacement, depth + 1);\n }\n };\n _resolveUseRefs(clone, 0);\n var _hostColor = cs.color;\n var _substCurrentColor = (node) => {\n if (node.nodeType !== 1) return;\n var fa = node.getAttribute && node.getAttribute(\"fill\");\n if (fa != null && /^currentcolor$/i.test(fa)) node.setAttribute(\"fill\", _hostColor);\n var sa = node.getAttribute && node.getAttribute(\"stroke\");\n if (sa != null && /^currentcolor$/i.test(sa)) node.setAttribute(\"stroke\", _hostColor);\n for (var ci = 0; ci < node.children.length; ci++) _substCurrentColor(node.children[ci]);\n };\n _substCurrentColor(clone);\n svgContent = clone.outerHTML;\n }\n const children = [];\n for (const child of el.children) {\n if (tag === \"details\" && !el.open && child.tagName.toLowerCase() !== \"summary\") continue;\n if (tag === \"select\" && (child.tagName.toLowerCase() === \"option\" || child.tagName.toLowerCase() === \"optgroup\")) continue;\n const c = capture(child);\n if (c) children.push(c);\n }\n const _animId = el.dataset != null ? el.dataset.domotionAnim : void 0;\n let fieldsetLegendNotch;\n let fsX = rect.left - vp.x;\n let fsY = rect.top - vp.y;\n let fsW = rect.width;\n let fsH = rect.height;\n if (tag === \"fieldset\") {\n for (let i = 0; i < el.children.length; i++) {\n const ch = el.children[i];\n if (ch.tagName.toLowerCase() !== \"legend\") continue;\n const lr = ch.getBoundingClientRect();\n if (lr.height > 0 && lr.width > 0 && Math.abs(lr.top - rect.top) < 2) {\n const inset = lr.height / 2;\n fsY = rect.top - vp.y + inset;\n fsH = rect.height - inset;\n fieldsetLegendNotch = { x: lr.left - vp.x, y: lr.top - vp.y, w: lr.width, h: lr.height };\n }\n break;\n }\n }\n const _captured = {\n tag,\n text,\n x: fsX,\n y: fsY,\n width: fsW,\n height: fsH,\n fieldsetLegendNotch,\n animId: _animId,\n styles: {\n // Border + background + outline + box-shadow fields — see\n // walker/borders-backgrounds.ts. Includes the\n // backgroundColor placeholder-shown fallback (DM-283), %-resolved\n // corner radii (SK-1093), per-side color-input border tint\n // workaround (DM-434), frosted-bg fallback (DM-476), per-layer\n // background-image intrinsic dims (DM-308), and border-image\n // intrinsic dims.\n ...captureBordersBackgrounds(el, cs, tag, rect, isPlaceholderCapture),\n overflowX: cs.overflowX,\n overflowY: cs.overflowY,\n scrollbarGutter: cs.scrollbarGutter || \"auto\",\n scrollWidth: el.scrollWidth,\n scrollHeight: el.scrollHeight,\n clientWidth: el.clientWidth,\n clientHeight: el.clientHeight,\n scrollTop: el.scrollTop,\n scrollLeft: el.scrollLeft,\n objectFit: cs.objectFit,\n objectPosition: cs.objectPosition,\n filter: cs.filter,\n backdropFilter: cs.backdropFilter || cs.webkitBackdropFilter || \"\",\n mixBlendMode: cs.mixBlendMode,\n clipPath: cs.clipPath,\n mask: cs.mask || cs.webkitMask || \"\",\n maskImage: cs.maskImage || cs.webkitMaskImage || \"\",\n maskMode: cs.maskMode || \"match-source\",\n maskSize: cs.maskSize || cs.webkitMaskSize || \"auto\",\n maskPosition: cs.maskPosition || cs.webkitMaskPosition || \"0% 0%\",\n maskRepeat: cs.maskRepeat || cs.webkitMaskRepeat || \"repeat\",\n maskComposite: cs.maskComposite || cs.webkitMaskComposite || \"add\",\n listStyleType: cs.listStyleType,\n listStyleImage: cs.listStyleImage,\n display: cs.display,\n listStylePosition: cs.listStylePosition,\n paddingTop: cs.paddingTop,\n paddingRight: cs.paddingRight,\n paddingBottom: cs.paddingBottom,\n paddingLeft: cs.paddingLeft,\n zIndex: cs.zIndex,\n position: cs.position,\n float: cs.float,\n order: cs.order,\n flexDirection: cs.flexDirection,\n emptyCellsHidden: (tag === \"td\" || tag === \"th\") && cs.emptyCells === \"hide\" && (el.textContent || \"\").trim() === \"\" && el.children.length === 0,\n // Form-control fields — input / progress / meter / select / details\n // + ::-webkit-* pseudos for slider track/thumb, color swatch, number\n // spin button, search cancel, file-selector button. See\n // walker/form-controls.ts. Input value-capture-as-text and color-\n // input border tinting deliberately stay inline (entangled with\n // text-shaping and border-color emission respectively).\n ...captureFormControls(el, cs, tag),\n textShadow: cs.textShadow,\n ...threadFrozenTransform(cs, frozenTransform, frozenTransformOrigin),\n // CSS Transforms 2 §4: `transform-style` != `flat` (i.e. `preserve-3d`)\n // creates a stacking context. Captured so the renderer's SC detection\n // sees it; otherwise z-index:-1 descendants hoist past their intended\n // SC and end up behind the wrong background (DM-589).\n transformStyle: cs.transformStyle,\n willChange: cs.willChange,\n contain: cs.contain,\n isolation: cs.isolation,\n writingMode: cs.writingMode,\n textOrientation: cs.textOrientation,\n // CSS resize: 'none' / 'both' / 'vertical' / 'horizontal' / 'block' /\n // 'inline'. When non-none on a <textarea> Chrome paints a small\n // diagonal-line resize handle in the bottom-right corner. (DM-339)\n resize: cs.resize,\n textOverflow: cs.textOverflow,\n whiteSpace: cs.whiteSpace,\n color: normColor(cs.color),\n // DM-587: live-rect capture records text bboxes at scaled (live)\n // viewport coords, but `cs.fontSize` and `canvas.measureText` are in\n // CSS px (unscaled). Multiply by the cumulative ancestor scale so\n // the renderer's text-Y math (baseline = top + ascent) lands the\n // baseline inside the scaled bbox — without this, glyphs inside e.g.\n // a `transform: scale(0.7)` container overflow their captured cell\n // and escape per-label `overflow: hidden` clip-paths. _cumulativeScale\n // is pre-computed in the pre-pass above. Defaults to 1 for elements\n // outside any scaled ancestor (the common case).\n fontSize: (function() {\n var _fs = parseFloat(cs.fontSize);\n if (!isFinite(_fs)) return cs.fontSize;\n var _s = _cumulativeScale.get(el) || 1;\n if (_s === 1) return cs.fontSize;\n return (_fs * _s).toFixed(4) + \"px\";\n })(),\n fontFamily: cs.fontFamily,\n fontWeight: cs.fontWeight,\n fontStyle: cs.fontStyle,\n opacity: cs.opacity,\n lineHeight: cs.lineHeight,\n letterSpacing: cs.letterSpacing,\n fontKerning: cs.fontKerning,\n fontStretch: cs.fontStretch,\n fontVariationSettings: cs.fontVariationSettings,\n fontFeatureSettings: cs.fontFeatureSettings,\n // CSS font-variant-caps. 'small-caps' / 'all-small-caps' route to\n // the OpenType smcp feature; renderer applies synthesized small-caps\n // when the active font lacks smcp (Helvetica, Times, etc.). DM-361.\n fontVariantCaps: cs.fontVariantCaps,\n direction: cs.direction,\n // Computed BCP-47 language tag from el.lang or nearest ancestor\n // [lang], falling back to document.documentElement.lang. Used by the\n // path renderer to route CJK Han fallback to the right PingFang\n // regional variant. (DM-394)\n lang: (function() {\n var n = el;\n while (n != null && n.nodeType === 1) {\n if (n.lang) return n.lang;\n n = n.parentElement;\n }\n return document.documentElement.lang || \"\";\n })(),\n textDecorationLine: cs.textDecorationLine,\n textDecorationColor: cs.textDecorationColor,\n textDecorationStyle: cs.textDecorationStyle,\n textDecorationThickness: cs.textDecorationThickness,\n textUnderlineOffset: cs.textUnderlineOffset,\n textDecorationSkipInk: cs.textDecorationSkipInk\n },\n children,\n imageSrc,\n imageIntrinsic,\n imageBroken,\n imageAlt,\n svgContent,\n pseudoImages,\n pseudoBoxes: pseudoBoxes.length > 0 ? pseudoBoxes : void 0,\n // SK-1115: ::marker pseudo styles plus list-marker intrinsic dims and\n // list-item index — see walker/lists-counters.ts.\n ..._listsCounters,\n textSegments: textSegments.length > 0 ? textSegments : void 0,\n textTop,\n textLeft,\n textHeight,\n textWidth,\n // DM-587: fontAscent + fontDescent come from `canvas.measureText` using\n // the unscaled `cs.fontSize`, so scale them to match the also-scaled\n // captured fontSize. Otherwise the renderer's baseline math reads\n // unscaled ascent values, and glyphs sit too far below their captured\n // bbox top inside a `transform: scale(<1)` container.\n fontAscent: fontAscent != null ? fontAscent * (_cumulativeScale.get(el) || 1) : fontAscent,\n fontDescent: fontDescent != null ? fontDescent * (_cumulativeScale.get(el) || 1) : fontDescent,\n inputXOffsets,\n textImageUri,\n textImageScale,\n // Placeholder metadata (SK-1097 / SK-1100 / SK-1099): captured in\n // walker/input-value.ts when the host is a placeholder-shown input\n // or textarea. Undefined elsewhere.\n isPlaceholderText: isPlaceholderCapture || void 0,\n placeholderColor,\n placeholderFontStyle,\n placeholderFontWeight,\n // SK-1108 / SK-1128: textarea soft-wrap + writing-mode != horizontal-tb\n // content-box raster rect — see walker/text-segments.ts.\n elementRaster: computeElementRaster(el, cs, tag, rect, vp)\n };\n if (bordersOnlyCell) {\n _captured.text = \"\";\n _captured.children = [];\n _captured.styles.backgroundColor = \"rgba(0, 0, 0, 0)\";\n _captured.styles.backgroundImage = void 0;\n _captured.textSegments = void 0;\n _captured.imageSrc = void 0;\n _captured.svgContent = void 0;\n _captured.pseudoImages = void 0;\n _captured.elementRaster = void 0;\n }\n handleReplacedElement(el, cs, tag, rect, _captured, bordersOnlyCell);\n return _captured;\n };\n const root = document.querySelector(sel);\n if (!root) return { tree: [], warnings: [] };\n const _fixedAncestors = /* @__PURE__ */ new Set();\n const _allEls = root.getElementsByTagName(\"*\");\n for (let _i = 0; _i < _allEls.length; _i++) {\n const _el = _allEls[_i];\n const _pos = getComputedStyle(_el).position;\n if (_pos !== \"fixed\" && _pos !== \"sticky\") continue;\n const _r = _el.getBoundingClientRect();\n const _outside = _r.right < vp.x || _r.bottom < vp.y || _r.left > vp.x + vp.width || _r.top > vp.y + vp.height;\n if (_outside) continue;\n let _cur = _el.parentElement;\n while (_cur != null && _cur !== root.parentElement) {\n if (_fixedAncestors.has(_cur)) break;\n _fixedAncestors.add(_cur);\n _cur = _cur.parentElement;\n }\n }\n const _transformInfluenced = /* @__PURE__ */ new Set();\n for (let _ti = 0; _ti < _allEls.length; _ti++) {\n const _tel = _allEls[_ti];\n const _tt = getComputedStyle(_tel).transform;\n if (_tt === \"none\" || _tt === \"\") continue;\n _transformInfluenced.add(_tel);\n const _tdescs = _tel.getElementsByTagName(\"*\");\n for (let _tj = 0; _tj < _tdescs.length; _tj++) {\n _transformInfluenced.add(_tdescs[_tj]);\n }\n }\n const _cumulativeScale = /* @__PURE__ */ new Map();\n const _computeOwnScale = (_tt) => {\n if (_tt == null || _tt === \"none\" || _tt === \"\") return 1;\n const _m2 = /^matrix\\(\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)/.exec(_tt);\n let _sa = 1, _sd = 1;\n if (_m2 != null) {\n _sa = parseFloat(_m2[1]);\n _sd = parseFloat(_m2[4]);\n } else {\n const _m3 = /^matrix3d\\(([^)]+)\\)/.exec(_tt);\n if (_m3 != null) {\n const _parts = _m3[1].split(\",\");\n _sa = parseFloat(_parts[0]);\n _sd = parseFloat(_parts[5]);\n }\n }\n if (!isFinite(_sa) || !isFinite(_sd)) return 1;\n const _s = Math.sqrt(Math.abs(_sa * _sd));\n return _s > 0 ? _s : 1;\n };\n for (let _si = 0; _si < _allEls.length; _si++) {\n const _el = _allEls[_si];\n let _cum = 1;\n const _pe = _el.parentElement;\n if (_pe != null && _cumulativeScale.has(_pe)) _cum = _cumulativeScale.get(_pe);\n const _ownT = getComputedStyle(_el).transform;\n if (_ownT != null && _ownT !== \"none\" && _ownT !== \"\") {\n _cum *= _computeOwnScale(_ownT);\n }\n if (_cum !== 1) _cumulativeScale.set(_el, _cum);\n }\n const _counterSnapshot = /* @__PURE__ */ new WeakMap();\n function _parseCounterDecl(declStr, defaultValue) {\n if (!declStr || declStr === \"none\") return [];\n const tokens = declStr.split(/\\s+/);\n const out = [];\n let i = 0;\n while (i < tokens.length) {\n const name = tokens[i++];\n if (!name) continue;\n let value = defaultValue;\n if (i < tokens.length && /^-?\\d+$/.test(tokens[i])) {\n value = parseInt(tokens[i++], 10);\n }\n out.push({ name, value });\n }\n return out;\n }\n const _activeScopes = [];\n function _findInnermost(name) {\n for (let i = _activeScopes.length - 1; i >= 0; i--) {\n if (_activeScopes[i].name === name) return _activeScopes[i];\n }\n return null;\n }\n function _counterPreWalk(el) {\n const cs = window.getComputedStyle(el);\n const owned = [];\n _parseCounterDecl(cs.counterReset, 0).forEach(({ name, value }) => {\n const scope = { name, value, owner: el };\n _activeScopes.push(scope);\n owned.push(scope);\n });\n _parseCounterDecl(cs.counterSet, 0).forEach(({ name, value }) => {\n const s = _findInnermost(name);\n if (s) s.value = value;\n else {\n const ns = { name, value, owner: el };\n _activeScopes.push(ns);\n owned.push(ns);\n }\n });\n _parseCounterDecl(cs.counterIncrement, 1).forEach(({ name, value }) => {\n const s = _findInnermost(name);\n if (s) s.value += value;\n else {\n const ns = { name, value, owner: el };\n _activeScopes.push(ns);\n owned.push(ns);\n }\n });\n _counterSnapshot.set(el, _activeScopes.map((s) => ({ name: s.name, value: s.value })));\n for (const child of el.children) _counterPreWalk(child);\n while (_activeScopes.length > 0 && owned.length > 0 && _activeScopes[_activeScopes.length - 1] === owned[owned.length - 1]) {\n _activeScopes.pop();\n owned.pop();\n }\n }\n _counterPreWalk(root);\n const result = [];\n const rootCs = window.getComputedStyle(root);\n const rootHasBorder = (parseFloat(rootCs.borderTopWidth) || 0) > 0 || (parseFloat(rootCs.borderRightWidth) || 0) > 0 || (parseFloat(rootCs.borderBottomWidth) || 0) > 0 || (parseFloat(rootCs.borderLeftWidth) || 0) > 0;\n const rootBg = rootCs.backgroundColor;\n const rootHasBg = rootBg != null && rootBg !== \"rgba(0, 0, 0, 0)\" && rootBg !== \"transparent\";\n let rootHasDirectText = false;\n for (const node of root.childNodes) {\n if (node.nodeType === Node.TEXT_NODE && (node.textContent || \"\").trim() !== \"\") {\n rootHasDirectText = true;\n break;\n }\n }\n if (rootHasBorder || rootHasBg || rootHasDirectText) {\n const c = capture(root);\n if (c) result.push(c);\n } else {\n for (const child of root.children) {\n const c = capture(child);\n if (c) result.push(c);\n }\n }\n if (_maskDefs.size > 0 && result.length > 0) {\n result[0].maskDefs = Array.from(_maskDefs.values());\n }\n if (_maskRasters.size > 0 && result.length > 0) {\n var rasterArr = [];\n for (var entry of _maskRasters.values()) {\n if (entry != null) rasterArr.push(entry);\n }\n if (rasterArr.length > 0) result[0].maskRasters = rasterArr;\n }\n if (result.length > 0) {\n try {\n var _isDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n result[0].styles.rootColorScheme = _isDark ? \"dark\" : \"light\";\n result[0].styles.rootBgComputed = window.getComputedStyle(document.documentElement).backgroundColor;\n } catch (_e) {\n }\n }\n return { tree: result, warnings: _warnings };\n});\n})()\n";
6
+ export const CAPTURE_SCRIPT = "\n(() => {\n// src/capture/script/color-norm.ts\nvar createColorNorm = () => {\n const probe = document.createElement(\"div\");\n probe.style.position = \"absolute\";\n probe.style.visibility = \"hidden\";\n document.body.appendChild(probe);\n const normColor = (c, elColor) => {\n if (c == null || c === \"\" || c === \"transparent\" || c === \"currentcolor\" || c === \"auto\") return c;\n if (/^(rgba?\\(|#[0-9a-f]{3,8}$)/i.test(c)) return c;\n var probeIn = c;\n if (elColor != null && elColor !== \"\" && /\\bcurrentcolor\\b/i.test(c)) {\n probeIn = c.replace(/\\bcurrentcolor\\b/gi, elColor);\n }\n try {\n probe.style.color = \"\";\n probe.style.color = \"color-mix(in srgb, \" + probeIn + \" 100%, transparent 0%)\";\n const v = getComputedStyle(probe).color;\n if (v != null && v !== \"\") return v;\n } catch (e) {\n }\n return c;\n };\n const normGradientColors = (text, elColor) => {\n if (text == null || text === \"\" || text === \"none\") return text;\n const fnRe = /\\b(oklch|oklab|lab|lch|hwb|hsl|hsla|color|color-mix)\\(/gi;\n var out = \"\";\n var i = 0;\n while (i < text.length) {\n fnRe.lastIndex = i;\n const m = fnRe.exec(text);\n if (m == null) {\n out += text.slice(i);\n break;\n }\n out += text.slice(i, m.index);\n var depth = 1;\n var j = m.index + m[0].length;\n while (j < text.length && depth > 0) {\n const ch = text[j++];\n if (ch === \"(\") depth++;\n else if (ch === \")\") depth--;\n }\n const call = text.slice(m.index, j);\n out += normColor(call, elColor);\n i = j;\n }\n return out;\n };\n return { normColor, normGradientColors };\n};\n\n// src/capture/script/emoji-detect.ts\nvar createEmojiDetect = () => {\n const rasterCps = /* @__PURE__ */ new Set([\n 10003,\n 10004,\n 10006,\n 10007,\n 10024,\n 10067,\n 10068,\n 10069,\n 10071,\n 10060,\n 10062,\n 10133,\n 10134,\n 10135,\n 10145,\n 10160,\n 10175,\n // DM-728: U+2B?? \"Miscellaneous Symbols and Arrows\" block with default\n // emoji presentation per Unicode emoji-data — Chrome paints these as\n // Apple Color Emoji glyphs without needing the U+FE0F variation\n // selector. The fixture's ⭐ U+2B50 in `20-deep-font-palette.html` was\n // painting as a hollow tofu before this list was extended.\n 11013,\n 11014,\n 11015,\n 11035,\n 11036,\n 11088,\n 11093\n ]);\n const emojiPresentation26 = /* @__PURE__ */ new Set([\n 9748,\n 9749,\n 9800,\n 9801,\n 9802,\n 9803,\n 9804,\n 9805,\n 9806,\n 9807,\n 9808,\n 9809,\n 9810,\n 9811,\n 9855,\n 9875,\n 9889,\n 9898,\n 9899,\n 9917,\n 9918,\n 9924,\n 9925,\n 9934,\n 9940,\n 9962,\n 9970,\n 9971,\n 9973,\n 9978,\n 9981\n ]);\n const emojiBaseCps = /* @__PURE__ */ new Set([\n 9728,\n 9729,\n 9730,\n 9731,\n 9732,\n 9742,\n 9745,\n 9752,\n 9757,\n 9760,\n 9762,\n 9763,\n 9766,\n 9770,\n 9774,\n 9775,\n 9784,\n 9785,\n 9786,\n 9792,\n 9794,\n 9823,\n 9824,\n 9827,\n 9829,\n 9830,\n 9832,\n 9851,\n 9854,\n 9874,\n 9876,\n 9877,\n 9878,\n 9879,\n 9881,\n 9883,\n 9884,\n 9888,\n 9895,\n 9904,\n 9905,\n 9928,\n 9935,\n 9937,\n 9939,\n 9961,\n 9968,\n 9969,\n 9972,\n 9975,\n 9976,\n 9977,\n // DM-728: Dingbats block (U+27??) codepoints with text-default\n // presentation that flip to color emoji when paired with U+FE0F. The\n // fixture's ❤️ (U+2764 + U+FE0F) heart was painting as a small black\n // monochrome glyph before this entry was added; with it, the VS-16\n // pairing routes through the raster overlay path so Apple Color Emoji\n // paints the red heart Chrome shows.\n 9986,\n 9992,\n 9993,\n 9996,\n 9997,\n 9999,\n 10002,\n 10006,\n 10035,\n 10036,\n 10052,\n 10055,\n 10083,\n 10084\n ]);\n const needsRaster = (cp, nextCp) => {\n if (rasterCps.has(cp)) return true;\n if (emojiPresentation26.has(cp)) return true;\n if (nextCp === 65039 && (emojiBaseCps.has(cp) || emojiPresentation26.has(cp))) return true;\n if (cp >= 127462 && cp <= 127487) return true;\n if (cp >= 127744 && cp <= 129791) return true;\n return false;\n };\n const textNeedsRaster = (s) => {\n for (let i = 0; i < s.length; i++) {\n const cp = s.codePointAt(i);\n const step = cp > 65535 ? 2 : 1;\n const nextCp = i + step < s.length ? s.codePointAt(i + step) : 0;\n if (needsRaster(cp, nextCp)) return true;\n if (cp > 65535) i++;\n }\n return false;\n };\n return { needsRaster, textNeedsRaster };\n};\n\n// src/capture/script/font-metrics.ts\nvar createFontMetrics = () => {\n const metricsCache = /* @__PURE__ */ new Map();\n const localFaceMap = /* @__PURE__ */ new Map();\n const probeWidthCS = (familyExpr, weight, style) => {\n const span = document.createElement(\"span\");\n span.style.cssText = \"position:absolute;left:-9999px;top:-9999px;visibility:hidden;font-size:16px;line-height:1;white-space:pre\";\n span.style.fontFamily = familyExpr;\n span.style.fontWeight = weight;\n span.style.fontStyle = style;\n span.textContent = \"mIw0\";\n document.body.appendChild(span);\n const w = span.getBoundingClientRect().width;\n document.body.removeChild(span);\n return w;\n };\n for (const sheet of Array.from(document.styleSheets)) {\n let cssRules;\n try {\n cssRules = sheet.cssRules;\n } catch (e) {\n continue;\n }\n for (const rule of Array.from(cssRules)) {\n if (rule.constructor.name !== \"CSSFontFaceRule\") continue;\n const r = rule;\n const family = r.style.getPropertyValue(\"font-family\").trim().replace(/^[\"']|[\"']$/g, \"\").toLowerCase();\n const weight = r.style.getPropertyValue(\"font-weight\") || \"400\";\n const styleDesc = r.style.getPropertyValue(\"font-style\") || \"normal\";\n const src = r.style.getPropertyValue(\"src\");\n if (family === \"\" || /url\\(/.test(src)) continue;\n const matches = src.match(/local\\(\\s*[\"']?[^\"')]+?[\"']?\\s*\\)/g);\n if (matches == null) continue;\n const locals = [];\n for (const mm of matches) {\n const inner = /local\\(\\s*[\"']?([^\"')]+?)[\"']?\\s*\\)/.exec(mm);\n if (inner != null) locals.push(inner[1].trim());\n }\n if (locals.length === 0) continue;\n const stripVariant = (n) => n.replace(/\\s+(Bold Italic|Italic Bold|Bold|Italic|Oblique|Regular|Light|Medium|Semibold|Black)$/i, \"\").trim();\n let resolved = null;\n const aliasW = probeWidthCS('\"' + family + '\"', weight, styleDesc);\n for (const cand of locals) {\n const candW = probeWidthCS('\"' + stripVariant(cand) + '\"', weight, styleDesc);\n if (Math.abs(candW - aliasW) < 0.05) {\n resolved = cand;\n break;\n }\n }\n if (resolved == null) resolved = locals[0];\n if (!localFaceMap.has(family)) localFaceMap.set(family, resolved);\n }\n }\n const substituteAliasedFamilies = (ff) => {\n if (localFaceMap.size === 0) return ff;\n const parts = ff.split(\",\").map((s) => s.trim());\n let changed = false;\n const out = parts.map((p) => {\n const bare = p.replace(/^[\"']|[\"']$/g, \"\").toLowerCase();\n const local = localFaceMap.get(bare);\n if (local == null) return p;\n changed = true;\n return /\\s/.test(local) ? '\"' + local + '\"' : local;\n });\n return changed ? out.join(\", \") : ff;\n };\n const measureFontMetrics = (cs) => {\n const fs = cs.fontStyle || \"normal\";\n const fw = cs.fontWeight || \"400\";\n const fz = cs.fontSize || \"14px\";\n const ff = substituteAliasedFamilies(cs.fontFamily || \"sans-serif\");\n const key = fs + \"|\" + fw + \"|\" + fz + \"|\" + ff;\n let v = metricsCache.get(key);\n if (v != null) return v;\n const c = document.createElement(\"canvas\");\n const ctx = c.getContext(\"2d\");\n ctx.font = fs + \" \" + fw + \" \" + fz + \" \" + ff;\n const m = ctx.measureText(\"Mxgp\");\n v = { ascent: m.fontBoundingBoxAscent, descent: m.fontBoundingBoxDescent };\n metricsCache.set(key, v);\n return v;\n };\n return { measureFontMetrics, substituteAliasedFamilies };\n};\n\n// src/capture/script/utils.ts\nvar isUnsetCssValue = (v) => v === \"\" || v === \"initial\" || v === \"inherit\" || v === \"unset\" || v === \"revert\";\nvar firstColorRe = /(#[0-9a-fA-F]{3,8}|rgba?\\([^)]*\\)|hsla?\\([^)]*\\)|\\b(?:white|black|red|green|blue|yellow|purple|orange|gray|grey|currentColor)\\b)/;\n\n// src/capture/script/placeholder-shown.ts\nvar createPlaceholderShown = () => {\n const rules = [];\n const collect = (cssRules) => {\n if (cssRules == null) return;\n for (let i = 0; i < cssRules.length; i++) {\n const rule = cssRules[i];\n if (rule == null) continue;\n const sel = rule.selectorText;\n if (typeof sel === \"string\" && sel.indexOf(\":placeholder-shown\") >= 0) {\n const hostSel = sel.replace(/:placeholder-shown/g, \"\").trim() || \"*\";\n const decl = rule.style;\n let bg = \"\";\n if (!isUnsetCssValue(decl.backgroundColor)) bg = decl.backgroundColor;\n else if (!isUnsetCssValue(decl.background)) {\n const cm = decl.background.match(firstColorRe);\n if (cm != null) bg = cm[1];\n }\n if (bg !== \"\") rules.push({ hostSel, bg });\n }\n if (rule.cssRules != null && rule.cssRules.length > 0) collect(rule.cssRules);\n }\n };\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n collect(document.styleSheets[i].cssRules);\n } catch (e) {\n }\n }\n const resolvePlaceholderShownBg = (el) => {\n let bg = \"\";\n for (let i = 0; i < rules.length; i++) {\n const r = rules[i];\n let isMatch = false;\n try {\n isMatch = el.matches(r.hostSel);\n } catch (e) {\n }\n if (isMatch) bg = r.bg;\n }\n return bg;\n };\n return { resolvePlaceholderShownBg };\n};\n\n// src/capture/script/pseudo-rules.ts\nvar _pseudoKindRe = /^(.*?)::?(-webkit-slider-runnable-track|-webkit-slider-thumb|-webkit-progress-bar|-webkit-progress-value|-webkit-meter-bar|-webkit-meter-optimum-value|-webkit-meter-suboptimum-value|-webkit-meter-even-less-good-value|-webkit-color-swatch|-webkit-color-swatch-wrapper|-webkit-inner-spin-button|-webkit-search-cancel-button)$/;\nvar _kindMap = {\n \"-webkit-slider-runnable-track\": \"track\",\n \"-webkit-slider-thumb\": \"thumb\",\n \"-webkit-progress-bar\": \"progress-bar\",\n \"-webkit-progress-value\": \"progress-value\",\n \"-webkit-meter-bar\": \"meter-bar\",\n \"-webkit-meter-optimum-value\": \"meter-optimum\",\n \"-webkit-meter-suboptimum-value\": \"meter-suboptimum\",\n \"-webkit-meter-even-less-good-value\": \"meter-even-less-good\",\n \"-webkit-color-swatch\": \"color-swatch\",\n \"-webkit-color-swatch-wrapper\": \"color-swatch-wrapper\",\n \"-webkit-inner-spin-button\": \"inner-spin-button\",\n \"-webkit-search-cancel-button\": \"search-cancel-button\"\n};\nvar _gradientRe = /^\\s*(repeating-)?(linear|radial|conic)-gradient\\s*\\(/i;\nvar _needsResolve = (v) => v != null && v !== \"\" && (v.indexOf(\"var(\") >= 0 || v.indexOf(\"calc(\") >= 0);\nvar _propMap = {\n backgroundColor: \"background-color\",\n backgroundImage: \"background-image\",\n borderRadius: \"border-radius\",\n width: \"width\",\n height: \"height\"\n};\nvar _extractGradients = (text) => {\n const re = /(repeating-)?(linear|radial|conic)-gradient\\s*\\(/gi;\n const out = [];\n let m;\n while ((m = re.exec(text)) != null) {\n const start = m.index;\n let depth = 0;\n let i = start;\n for (; i < text.length; i++) {\n const c = text[i];\n if (c === \"(\") depth++;\n else if (c === \")\") {\n depth--;\n if (depth === 0) {\n i++;\n break;\n }\n }\n }\n out.push(text.slice(start, i));\n re.lastIndex = i;\n }\n return out.join(\", \");\n};\nvar createPseudoRules = () => {\n const rules = [];\n const collect = (cssRules) => {\n if (cssRules == null) return;\n for (let i = 0; i < cssRules.length; i++) {\n const rule = cssRules[i];\n if (rule == null) continue;\n const selectorText = rule.selectorText;\n if (typeof selectorText === \"string\") {\n const selectors = selectorText.split(\",\").map(function(s) {\n return s.trim();\n });\n for (let j = 0; j < selectors.length; j++) {\n const sel = selectors[j];\n const m = sel.match(_pseudoKindRe);\n if (m == null) continue;\n const kind = _kindMap[m[2]];\n if (kind == null) continue;\n const hostSel = m[1].trim();\n rules.push({ kind, hostSel, decl: rule.style });\n }\n }\n if (rule.cssRules != null && rule.cssRules.length > 0) collect(rule.cssRules);\n }\n };\n for (let i = 0; i < document.styleSheets.length; i++) {\n try {\n collect(document.styleSheets[i].cssRules);\n } catch (e) {\n }\n }\n const _resolveOne = (host, propKey, value) => {\n if (!_needsResolve(value)) return value;\n const cssProp = _propMap[propKey] || propKey;\n const saved = host.style.getPropertyValue(cssProp);\n const savedPriority = host.style.getPropertyPriority(cssProp);\n host.style.setProperty(cssProp, value);\n const resolved = window.getComputedStyle(host).getPropertyValue(cssProp);\n if (saved === \"\") host.style.removeProperty(cssProp);\n else host.style.setProperty(cssProp, saved, savedPriority);\n return resolved !== \"\" ? resolved : value;\n };\n const resolveCornerRadius = (v, w, h) => {\n if (v == null || v === \"\") return \"0px 0px\";\n const parts = v.split(/\\s+/);\n const a = parts[0] || \"0\";\n const b = parts[1] != null ? parts[1] : a;\n const aPx = a.endsWith(\"%\") ? (parseFloat(a) || 0) * w / 100 : parseFloat(a) || 0;\n const bPx = b.endsWith(\"%\") ? (parseFloat(b) || 0) * h / 100 : parseFloat(b) || 0;\n return aPx + \"px \" + bPx + \"px\";\n };\n const resolvePseudo = (el, kind) => {\n let width = \"\", height = \"\", backgroundColor = \"\", borderRadius = \"\", backgroundImage = \"\";\n let border = \"\", padding = \"\", boxShadow = \"\";\n let matched = false;\n for (let i = 0; i < rules.length; i++) {\n const r = rules[i];\n if (r.kind !== kind) continue;\n let isMatch = false;\n try {\n isMatch = el.matches(r.hostSel);\n } catch (e) {\n }\n if (!isMatch) continue;\n matched = true;\n const d = r.decl;\n if (!isUnsetCssValue(d.width)) width = d.width;\n if (!isUnsetCssValue(d.height)) height = d.height;\n if (!isUnsetCssValue(d.borderRadius)) borderRadius = d.borderRadius;\n if (!isUnsetCssValue(d.border)) border = d.border;\n if (!isUnsetCssValue(d.padding)) padding = d.padding;\n if (!isUnsetCssValue(d.boxShadow)) boxShadow = d.boxShadow;\n if (!isUnsetCssValue(d.backgroundColor)) {\n backgroundColor = d.backgroundColor;\n } else if (!isUnsetCssValue(d.background)) {\n const cm = d.background.match(firstColorRe);\n if (cm != null) backgroundColor = cm[1];\n else if (_needsResolve(d.background)) backgroundColor = d.background;\n }\n if (!isUnsetCssValue(d.backgroundImage) && _gradientRe.test(d.backgroundImage)) {\n backgroundImage = _extractGradients(d.backgroundImage);\n } else if (!isUnsetCssValue(d.background) && _gradientRe.test(d.background)) {\n backgroundImage = _extractGradients(d.background);\n }\n }\n return {\n matched,\n width: _resolveOne(el, \"width\", width),\n height: _resolveOne(el, \"height\", height),\n backgroundColor: _resolveOne(el, \"backgroundColor\", backgroundColor),\n borderRadius: _resolveOne(el, \"borderRadius\", borderRadius),\n // Resolve var()/calc() inside gradient text via the same host-probe\n // (Chromium rewrites the gradient to fully-resolved rgb()/deg form).\n backgroundImage: _resolveOne(el, \"backgroundImage\", backgroundImage),\n border,\n padding,\n boxShadow\n };\n };\n return { resolvePseudo, resolveCornerRadius };\n};\n\n// src/capture/script/warnings.ts\nvar createWarnings = () => {\n const warnings = [];\n const seen = /* @__PURE__ */ new Set();\n const shortSelector = (el) => {\n const parts = [];\n let cur = el;\n while (cur != null && cur.nodeType === 1 && cur !== document.documentElement && parts.length < 5) {\n let p = cur.tagName.toLowerCase();\n if (cur.id) {\n p += \"#\" + cur.id;\n parts.unshift(p);\n break;\n }\n if (cur.className && typeof cur.className === \"string\") {\n const cls = cur.className.trim().split(/\\s+/).slice(0, 2).join(\".\");\n if (cls !== \"\") p += \".\" + cls;\n }\n parts.unshift(p);\n cur = cur.parentElement;\n }\n return parts.join(\" > \");\n };\n const warn = (sel, feature, detail) => {\n const k = feature + \"|\" + sel;\n if (seen.has(k)) return;\n seen.add(k);\n warnings.push({ selector: sel, feature, detail });\n };\n return { warn, shortSelector, warnings };\n};\n\n// src/capture/script/walker/counter-style-resolver.ts\nvar createCounterStyleResolver = ({ counterStyles }) => {\n const BUILTINS = /* @__PURE__ */ new Set([\n \"decimal\",\n \"decimal-leading-zero\",\n \"lower-alpha\",\n \"lower-latin\",\n \"upper-alpha\",\n \"upper-latin\",\n \"lower-roman\",\n \"upper-roman\",\n \"lower-greek\",\n \"disc\",\n \"circle\",\n \"square\",\n \"none\"\n ]);\n const resolveCounterStyle = (name, n) => _resolve(name, n, 0, true);\n const resolveCounterValue = (name, n) => _resolve(name, n, 0, false);\n const isCustomCounterStyle = (name) => counterStyles[name] != null;\n const _resolve = (name, n, depth, wrap) => {\n if (depth > 16) return null;\n if (BUILTINS.has(name)) return _formatBuiltin(name, n);\n const def = counterStyles[name];\n if (def == null) return _formatBuiltin(\"decimal\", n);\n if (def.system === \"extends\" && def.extendsName != null) {\n const childSym = _resolve(def.extendsName, n, depth + 1, wrap);\n if (childSym == null) return null;\n const padded2 = _applyPad(childSym, def.padLen, def.padSym);\n return wrap ? def.prefix + padded2 + def.suffix : padded2;\n }\n if (n < def.rangeLo || n > def.rangeHi) {\n return _resolve(def.fallback ?? \"decimal\", n, depth + 1, wrap);\n }\n const negative = n < 0;\n const abs = Math.abs(n);\n let core = null;\n switch (def.system) {\n case \"cyclic\":\n if (def.symbols.length === 0) break;\n core = def.symbols[((abs - 1) % def.symbols.length + def.symbols.length) % def.symbols.length];\n break;\n case \"fixed\": {\n const idx0 = abs - 1;\n if (idx0 >= 0 && idx0 < def.symbols.length) core = def.symbols[idx0];\n break;\n }\n case \"numeric\": {\n if (def.symbols.length < 2) break;\n if (abs === 0) {\n core = def.symbols[0];\n break;\n }\n const base = def.symbols.length;\n let v = abs;\n let s = \"\";\n while (v > 0) {\n s = def.symbols[v % base] + s;\n v = Math.floor(v / base);\n }\n core = s;\n break;\n }\n case \"alphabetic\": {\n if (def.symbols.length === 0 || abs <= 0) break;\n const base = def.symbols.length;\n let v = abs;\n let s = \"\";\n while (v > 0) {\n v--;\n s = def.symbols[v % base] + s;\n v = Math.floor(v / base);\n }\n core = s;\n break;\n }\n case \"symbolic\": {\n if (def.symbols.length === 0 || abs <= 0) break;\n const base = def.symbols.length;\n const copies = Math.ceil(abs / base);\n const sym = def.symbols[(abs - 1) % base];\n core = sym.repeat(copies);\n break;\n }\n case \"additive\": {\n if (def.additiveSymbols.length === 0) break;\n if (abs === 0) {\n const zero = def.additiveSymbols.find((s) => s.weight === 0);\n core = zero ? zero.sym : null;\n } else {\n let v = abs;\n let s = \"\";\n for (const { weight, sym } of def.additiveSymbols) {\n if (weight <= 0) continue;\n const count = Math.floor(v / weight);\n for (let i = 0; i < count; i++) s += sym;\n v -= count * weight;\n }\n core = v === 0 ? s : null;\n }\n break;\n }\n }\n if (core == null) return _resolve(def.fallback ?? \"decimal\", n, depth + 1, wrap);\n const padded = _applyPad(core, def.padLen, def.padSym);\n const sign = negative ? def.negPrefix : \"\";\n const signTail = negative ? def.negSuffix : \"\";\n return wrap ? def.prefix + sign + padded + signTail + def.suffix : sign + padded + signTail;\n };\n const _applyPad = (s, len, sym) => {\n if (!len || !sym) return s;\n while ([...s].length < len) s = sym + s;\n return s;\n };\n const _formatBuiltin = (type, n) => {\n switch (type) {\n case \"decimal\":\n return String(n);\n case \"decimal-leading-zero\":\n return n < 10 && n >= 0 ? \"0\" + n : String(n);\n case \"lower-alpha\":\n case \"lower-latin\":\n return _alphaMarker(n, false);\n case \"upper-alpha\":\n case \"upper-latin\":\n return _alphaMarker(n, true);\n case \"lower-roman\":\n return _romanMarker(n).toLowerCase();\n case \"upper-roman\":\n return _romanMarker(n);\n case \"lower-greek\":\n return _greekMarker(n);\n case \"disc\":\n case \"circle\":\n case \"square\":\n case \"none\":\n return null;\n default:\n return String(n);\n }\n };\n const _alphaMarker = (n, upper) => {\n if (n <= 0) return String(n);\n const base = upper ? 65 : 97;\n let s = \"\";\n let v = n;\n while (v > 0) {\n v--;\n s = String.fromCharCode(base + v % 26) + s;\n v = Math.floor(v / 26);\n }\n return s;\n };\n const _greekMarker = (n) => {\n if (n <= 0) return String(n);\n const greek = \"\\u03B1\\u03B2\\u03B3\\u03B4\\u03B5\\u03B6\\u03B7\\u03B8\\u03B9\\u03BA\\u03BB\\u03BC\\u03BD\\u03BE\\u03BF\\u03C0\\u03C1\\u03C3\\u03C4\\u03C5\\u03C6\\u03C7\\u03C8\\u03C9\";\n let s = \"\";\n let v = n;\n while (v > 0) {\n v--;\n s = greek.charAt(v % 24) + s;\n v = Math.floor(v / 24);\n }\n return s;\n };\n const _romanMarker = (n) => {\n if (n <= 0 || n >= 4e3) return String(n);\n const vals = [1e3, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];\n const syms = [\"M\", \"CM\", \"D\", \"CD\", \"C\", \"XC\", \"L\", \"XL\", \"X\", \"IX\", \"V\", \"IV\", \"I\"];\n let s = \"\";\n let v = n;\n for (let i = 0; i < vals.length; i++) {\n while (v >= vals[i]) {\n s += syms[i];\n v -= vals[i];\n }\n }\n return s;\n };\n return { resolveCounterStyle, resolveCounterValue, isCustomCounterStyle };\n};\n\n// src/capture/script/walker/lists-counters.ts\nvar createListsCountersHandler = ({ normColor, resolveCounterStyle, isCustomCounterStyle }) => {\n const captureListsCounters = (el, cs, tag) => {\n const isListItem = cs.display != null && cs.display.includes(\"list-item\");\n let listMarkerIntrinsic = void 0;\n let listItemIndex = void 0;\n if (isListItem) {\n if (cs.listStyleImage && cs.listStyleImage !== \"none\") {\n const u = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.listStyleImage);\n if (u != null) {\n const img = new Image();\n img.src = u[1];\n if (img.naturalWidth > 0) listMarkerIntrinsic = { w: img.naturalWidth, h: img.naturalHeight };\n }\n }\n const parent = el.parentElement;\n if (parent != null) {\n if (tag === \"li\") {\n const siblings = Array.from(parent.children).filter((c) => c.tagName.toLowerCase() === \"li\");\n const parentTag = parent.tagName.toLowerCase();\n const reversed = parentTag === \"ol\" && parent.hasAttribute(\"reversed\");\n let start = 1;\n if (parentTag === \"ol\" && parent.hasAttribute(\"start\")) start = parseInt(parent.getAttribute(\"start\"), 10) || 1;\n if (reversed) start = siblings.length;\n let cur = start;\n for (const s of siblings) {\n if (s.hasAttribute(\"value\")) cur = parseInt(s.getAttribute(\"value\"), 10) || cur;\n if (s === el) {\n listItemIndex = cur;\n break;\n }\n cur += reversed ? -1 : 1;\n }\n } else {\n let cur = 1;\n for (const s of parent.children) {\n const sd = window.getComputedStyle(s).display;\n if (sd != null && sd.includes(\"list-item\")) {\n if (s === el) {\n listItemIndex = cur;\n break;\n }\n cur += 1;\n }\n }\n }\n }\n }\n const markerCs = isListItem ? window.getComputedStyle(el, \"::marker\") : null;\n let markerContent = markerCs ? markerCs.content : void 0;\n if (isListItem && resolveCounterStyle != null && listItemIndex != null) {\n const lsType = cs.listStyleType;\n const isCustom = lsType != null && isCustomCounterStyle != null && isCustomCounterStyle(lsType);\n const noAuthorContent = markerContent == null || markerContent === \"\" || markerContent === \"normal\";\n if (isCustom && noAuthorContent) {\n const resolved = resolveCounterStyle(lsType, listItemIndex);\n if (resolved != null) {\n markerContent = '\"' + resolved.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"') + '\"';\n }\n }\n }\n return {\n listMarkerIntrinsic,\n listItemIndex,\n markerColor: markerCs ? normColor(markerCs.color) : void 0,\n markerFontWeight: markerCs ? markerCs.fontWeight : void 0,\n markerFontSize: markerCs ? markerCs.fontSize : void 0,\n markerContent,\n markerFontFamily: markerCs ? markerCs.fontFamily : void 0\n };\n };\n return { captureListsCounters };\n};\n\n// src/capture/script/walker/replaced-elements.ts\nvar createReplacedElementsHandler = ({ vp }) => {\n let _replacedIdx = 0;\n const handleReplacedElement = (el, cs, tag, rect, captured, bordersOnlyCell) => {\n if (bordersOnlyCell || cs.display === \"none\" || rect.width <= 0 || rect.height <= 0) return;\n const isCustomEl = tag.indexOf(\"-\") > 0;\n const hasOpenShadow = isCustomEl && el.shadowRoot != null;\n const customElNeedsSnapshot = isCustomEl && hasOpenShadow;\n if (tag === \"iframe\" || tag === \"canvas\" || tag === \"video\" || tag === \"object\" || tag === \"embed\" || customElNeedsSnapshot) {\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const cw = rect.width - bl - br - pl - pr;\n const ch = rect.height - bt - bb - pt - pb;\n if (cw > 0 && ch > 0) {\n const rid = \"dr\" + _replacedIdx++;\n el.setAttribute(\"data-domotion-rid\", rid);\n captured.replacedSnapshot = {\n x: rect.left - vp.x + bl + pl,\n y: rect.top - vp.y + bt + pt,\n width: cw,\n height: ch,\n rid\n };\n }\n }\n if (captured.replacedSnapshot != null || captured.imageSrc != null) return;\n const ti = parseFloat(cs.textIndent) || 0;\n const ovX = cs.overflowX === \"hidden\" || cs.overflow === \"hidden\";\n const hasBgImage = cs.backgroundImage != null && cs.backgroundImage !== \"none\" && cs.backgroundImage !== \"\";\n const phark = ti <= -1e3;\n const modern = ti < 0 && ovX && cs.whiteSpace === \"nowrap\";\n if ((phark || modern) && hasBgImage) {\n const rid = \"dr\" + _replacedIdx++;\n el.setAttribute(\"data-domotion-rid\", rid);\n const titleText = (el.getAttribute && el.getAttribute(\"aria-label\") || captured.text || \"\").trim();\n captured.replacedSnapshot = {\n x: rect.left - vp.x,\n y: rect.top - vp.y,\n width: rect.width,\n height: rect.height,\n rid\n };\n captured.imageReplacement = { titleText };\n captured.styles.backgroundImage = void 0;\n captured.text = \"\";\n captured.textSegments = void 0;\n }\n };\n return { handleReplacedElement };\n};\n\n// src/capture/script/walker/masks-clips.ts\nvar createMasksClipsHandler = ({ vp, warn }) => {\n const maskDefs = /* @__PURE__ */ new Map();\n const maskRasters = /* @__PURE__ */ new Map();\n const clipPathDefs = /* @__PURE__ */ new Map();\n let maskRasterIdx = 0;\n const discoverMasks = (el, cs, sel) => {\n if (!cs.mask || cs.mask === \"none\" || cs.mask === \"\") return;\n const miSrc = cs.maskImage || cs.webkitMaskImage || \"\";\n const fragMatch = /^url\\(\\s*(?:\"|')?#([^\"')\\s]+)(?:\"|')?\\s*\\)$/i.exec(miSrc);\n if (fragMatch != null) {\n const fragId = fragMatch[1];\n if (!maskDefs.has(fragId)) {\n const target = document.getElementById(fragId);\n if (target != null && target.tagName.toLowerCase() === \"mask\") {\n maskDefs.set(fragId, { id: fragId, outerHTML: target.outerHTML });\n } else {\n warn(sel, \"mask\", 'mask-image fragment \"#' + fragId + '\" did not resolve to an inline <mask> element');\n }\n }\n return;\n }\n const extFragMatch = /^url\\(\\s*(?:\"|')?[^\"')#]+#[^\"')\\s]+(?:\"|')?\\s*\\)$/i.exec(miSrc);\n if (extFragMatch != null) {\n warn(sel, \"mask\", 'external-file SVG fragment refs (url(\"./file.svg#id\")) are not yet emitted (DM-496)');\n return;\n }\n const elementMatch = /^element\\(\\s*#([^)\\s]+)\\s*\\)$/i.exec(miSrc);\n if (elementMatch != null) {\n const refId = elementMatch[1];\n if (maskRasters.has(refId)) return;\n const refTarget = document.getElementById(refId);\n if (refTarget == null) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target not found in document\");\n return;\n }\n const refCs = window.getComputedStyle(refTarget);\n if (refCs.display === \"none\" || refCs.visibility === \"hidden\") {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target is display:none / hidden \\u2014 emitting empty mask\");\n maskRasters.set(refId, null);\n return;\n }\n const refRect = refTarget.getBoundingClientRect();\n if (refRect.width <= 0 || refRect.height <= 0) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target has zero-area painted box \\u2014 emitting empty mask\");\n maskRasters.set(refId, null);\n return;\n }\n if (typeof refTarget.getAnimations === \"function\") {\n try {\n const anims = refTarget.getAnimations();\n if (anims != null && anims.length > 0) {\n warn(sel, \"mask\", \"mask-image: element(#\" + refId + \") target has \" + anims.length + \" active animation(s); the rasterized snapshot is t=0 only\");\n }\n } catch (e) {\n }\n }\n const refRid = \"mr\" + maskRasterIdx++;\n refTarget.setAttribute(\"data-domotion-rid\", refRid);\n maskRasters.set(refId, {\n id: refId,\n rid: refRid,\n width: refRect.width,\n height: refRect.height,\n rect: {\n x: refRect.left - vp.x,\n y: refRect.top - vp.y,\n width: refRect.width,\n height: refRect.height\n }\n });\n return;\n }\n const supported = /^(?:repeating-)?(?:linear|radial)-gradient\\(/i.test(miSrc) || /^url\\(/i.test(miSrc);\n if (!supported) {\n warn(sel, \"mask\", \"non-gradient/non-url()/non-element() mask source \\u2014 not emitted\");\n }\n };\n const discoverClipPaths = (el, cs, sel) => {\n const cp = cs.clipPath;\n if (!cp || cp === \"none\" || cp === \"\") return;\n const cpShape = cp.replace(/\\b(?:content-box|padding-box|border-box|margin-box|fill-box|stroke-box|view-box)\\b/i, \"\").trim();\n const fragMatch = /^url\\(\\s*(?:\"|')?#([^\"')\\s]+)(?:\"|')?\\s*\\)$/i.exec(cpShape);\n if (fragMatch != null) {\n const fragId = fragMatch[1];\n if (!clipPathDefs.has(fragId)) {\n const target = document.getElementById(fragId);\n if (target != null && target.tagName.toLowerCase() === \"clippath\") {\n clipPathDefs.set(fragId, { id: fragId, outerHTML: target.outerHTML });\n } else {\n warn(sel, \"clip-path\", 'clip-path fragment \"#' + fragId + '\" did not resolve to an inline <clipPath> element');\n }\n }\n return;\n }\n const extFragMatch = /^url\\(\\s*(?:\"|')?[^\"')#]+#[^\"')\\s]+(?:\"|')?\\s*\\)$/i.exec(cpShape);\n if (extFragMatch != null) {\n warn(sel, \"clip-path\", 'external-file SVG fragment refs (url(\"./file.svg#id\")) are not yet emitted');\n }\n };\n return { discoverMasks, discoverClipPaths, maskDefs, maskRasters, clipPathDefs };\n};\n\n// src/capture/script/walker/form-controls.ts\nvar createFormControlsHandler = ({ normColor, resolvePseudo }) => {\n const captureFormControls = (el, cs, tag) => {\n const out = {\n inputType: tag === \"input\" ? el.type || \"text\" : void 0,\n // CSS appearance / -webkit-appearance longhand for inputs. When 'none'\n // (the appearance:none custom-styled pattern) the renderer suppresses\n // its UA-default checkbox / radio chrome so the host's author-styled\n // border + background show through, with only the :checked indicator\n // overlaid on top. DM-285.\n inputAppearance: tag === \"input\" ? cs.webkitAppearance || cs.appearance || \"\" : void 0,\n checked: tag === \"input\" && (el.type === \"checkbox\" || el.type === \"radio\") ? !!el.checked : void 0,\n indeterminate: tag === \"input\" && el.type === \"checkbox\" ? !!el.indeterminate : void 0,\n disabled: tag === \"input\" || tag === \"button\" || tag === \"select\" || tag === \"textarea\" ? !!el.disabled : void 0,\n progressValue: tag === \"progress\" ? el.hasAttribute(\"value\") ? +el.value : void 0 : void 0,\n progressMax: tag === \"progress\" ? el.max || 1 : void 0,\n meterValue: tag === \"meter\" ? el.value != null ? +el.value : void 0 : void 0,\n meterMin: tag === \"meter\" ? el.min || 0 : void 0,\n meterMax: tag === \"meter\" ? el.max || 1 : void 0,\n meterLow: tag === \"meter\" ? el.low != null ? +el.low : void 0 : void 0,\n meterHigh: tag === \"meter\" ? el.high != null ? +el.high : void 0 : void 0,\n meterOptimum: tag === \"meter\" ? el.optimum != null ? +el.optimum : void 0 : void 0,\n detailsOpen: tag === \"details\" ? !!el.open : void 0,\n // Detect if author CSS hid the summary's UA disclosure marker (e.g.\n // ::marker { color: transparent }). If so, skip painting our own\n // triangle — the author's custom marker (typically ::before) is the\n // only one that should show. DM-448.\n summaryMarkerSuppressed: tag === \"details\" ? (() => {\n const sum = el.querySelector(\":scope > summary\");\n if (sum == null) return false;\n const mc = window.getComputedStyle(sum, \"::marker\").color;\n if (mc === \"transparent\") return true;\n const am = /^rgba\\(\\s*[0-9.]+\\s*,\\s*[0-9.]+\\s*,\\s*[0-9.]+\\s*,\\s*([0-9.]+)\\s*\\)$/.exec(mc);\n if (am != null && parseFloat(am[1]) === 0) return true;\n return false;\n })() : void 0,\n // Native chevron only when the select keeps UA chrome — appearance:\n // none means the page draws its own arrow via background-image, and\n // we should not stack our default chevron on top. DM-308.\n selectChevron: tag === \"select\" && el.size <= 1 && !el.multiple && cs.appearance !== \"none\" && cs.webkitAppearance !== \"none\",\n selectDisplayText: tag === \"select\" && el.size <= 1 && !el.multiple ? el.selectedOptions && el.selectedOptions.length > 0 ? (el.selectedOptions[0].textContent || \"\").trim() : el.options && el.options.length > 0 ? (el.options[0].textContent || \"\").trim() : \"\" : void 0,\n // Listbox-mode selects (size > 1 or multiple) flatten their option /\n // optgroup children into a captured row list. The renderer walks this\n // list and paints one row per entry inside the select's content rect.\n // Optgroup labels are emitted as italic+bold rows that don't count\n // against selection. DM-282.\n selectListboxOptions: tag === \"select\" && (el.size > 1 || el.multiple) ? (function() {\n const list = [];\n const kids = el.children;\n for (let ki = 0; ki < kids.length; ki++) {\n const c = kids[ki];\n if (c.tagName === \"OPTGROUP\") {\n list.push({ text: c.label || \"\", selected: false, disabled: !!c.disabled, isOptgroupLabel: true });\n const og = c.children;\n for (let gi = 0; gi < og.length; gi++) {\n const o = og[gi];\n if (o.tagName !== \"OPTION\") continue;\n list.push({ text: (o.textContent || \"\").trim(), selected: !!o.selected, disabled: !!o.disabled, isOptgroupChild: true });\n }\n } else if (c.tagName === \"OPTION\") {\n list.push({ text: (c.textContent || \"\").trim(), selected: !!c.selected, disabled: !!c.disabled });\n }\n }\n return list;\n })() : void 0,\n accentColor: tag === \"input\" || tag === \"progress\" || tag === \"meter\" ? normColor(cs.accentColor || \"auto\") : void 0,\n caretColor: tag === \"input\" || tag === \"textarea\" ? normColor(cs.caretColor || \"auto\") : void 0,\n inputValue: tag === \"input\" ? el.value || \"\" : void 0,\n inputMin: tag === \"input\" ? el.min || \"\" : void 0,\n inputMax: tag === \"input\" ? el.max || \"\" : void 0,\n inputStep: tag === \"input\" ? el.step || \"\" : void 0,\n inputMultiple: tag === \"input\" ? !!el.multiple : void 0,\n inputFileName: tag === \"input\" && el.type === \"file\" && el.files && el.files.length > 0 ? el.files[0].name : void 0\n };\n if (tag === \"progress\") {\n const bar = resolvePseudo(el, \"progress-bar\");\n const val = resolvePseudo(el, \"progress-value\");\n out.progressBarBg = bar.matched && bar.backgroundColor !== \"\" ? normColor(bar.backgroundColor) : void 0;\n out.progressBarBgImage = bar.matched && bar.backgroundImage !== \"\" ? bar.backgroundImage : void 0;\n out.progressBarRadius = bar.matched && bar.borderRadius !== \"\" ? bar.borderRadius : void 0;\n out.progressValueBg = val.matched && val.backgroundColor !== \"\" ? normColor(val.backgroundColor) : void 0;\n out.progressValueBgImage = val.matched && val.backgroundImage !== \"\" ? val.backgroundImage : void 0;\n out.progressValueRadius = val.matched && val.borderRadius !== \"\" ? val.borderRadius : void 0;\n }\n if (tag === \"meter\") {\n const bar = resolvePseudo(el, \"meter-bar\");\n const opt = resolvePseudo(el, \"meter-optimum\");\n const sub = resolvePseudo(el, \"meter-suboptimum\");\n const elg = resolvePseudo(el, \"meter-even-less-good\");\n out.meterBarBg = bar.matched && bar.backgroundColor !== \"\" ? normColor(bar.backgroundColor) : void 0;\n out.meterBarBgImage = bar.matched && bar.backgroundImage !== \"\" ? bar.backgroundImage : void 0;\n out.meterBarRadius = bar.matched && bar.borderRadius !== \"\" ? bar.borderRadius : void 0;\n out.meterOptimumBg = opt.matched && opt.backgroundColor !== \"\" ? normColor(opt.backgroundColor) : void 0;\n out.meterOptimumBgImage = opt.matched && opt.backgroundImage !== \"\" ? opt.backgroundImage : void 0;\n out.meterSuboptimumBg = sub.matched && sub.backgroundColor !== \"\" ? normColor(sub.backgroundColor) : void 0;\n out.meterSuboptimumBgImage = sub.matched && sub.backgroundImage !== \"\" ? sub.backgroundImage : void 0;\n out.meterEvenLessGoodBg = elg.matched && elg.backgroundColor !== \"\" ? normColor(elg.backgroundColor) : void 0;\n out.meterEvenLessGoodBgImage = elg.matched && elg.backgroundImage !== \"\" ? elg.backgroundImage : void 0;\n }\n if (tag === \"input\" && el.type === \"color\") {\n const swatch = resolvePseudo(el, \"color-swatch\");\n const wrap = resolvePseudo(el, \"color-swatch-wrapper\");\n out.colorSwatchBg = swatch.matched && swatch.backgroundColor !== \"\" ? normColor(swatch.backgroundColor) : void 0;\n out.colorSwatchBgImage = swatch.matched && swatch.backgroundImage !== \"\" ? swatch.backgroundImage : void 0;\n out.colorSwatchBorder = swatch.matched && swatch.border !== \"\" ? swatch.border : void 0;\n out.colorSwatchRadius = swatch.matched && swatch.borderRadius !== \"\" ? swatch.borderRadius : void 0;\n out.colorSwatchWrapperPadding = wrap.matched && wrap.padding !== \"\" ? wrap.padding : void 0;\n }\n if (tag === \"input\" && el.type === \"number\") {\n const spin = resolvePseudo(el, \"inner-spin-button\");\n out.numberSpinButtonBg = spin.matched && spin.backgroundColor !== \"\" ? normColor(spin.backgroundColor) : void 0;\n out.numberSpinButtonBorder = spin.matched && spin.border !== \"\" ? spin.border : void 0;\n out.numberSpinButtonRadius = spin.matched && spin.borderRadius !== \"\" ? spin.borderRadius : void 0;\n }\n if (tag === \"input\" && el.type === \"search\") {\n const cancel = resolvePseudo(el, \"search-cancel-button\");\n out.searchCancelButtonBg = cancel.matched && cancel.backgroundColor !== \"\" ? normColor(cancel.backgroundColor) : void 0;\n out.searchCancelButtonBorder = cancel.matched && cancel.border !== \"\" ? cancel.border : void 0;\n out.searchCancelButtonRadius = cancel.matched && cancel.borderRadius !== \"\" ? cancel.borderRadius : void 0;\n }\n if (tag === \"input\" && el.type === \"range\") {\n const ts = resolvePseudo(el, \"track\");\n const ms = resolvePseudo(el, \"thumb\");\n const elAppearance = cs.webkitAppearance || cs.appearance;\n const customAppearance = elAppearance === \"none\";\n const styledTrack = ts.matched || customAppearance;\n const styledThumb = ms.matched || customAppearance;\n out.rangeTrackBg = styledTrack && ts.backgroundColor !== \"\" ? normColor(ts.backgroundColor) : styledTrack ? \"rgba(0, 0, 0, 0)\" : void 0;\n out.rangeTrackHeight = styledTrack ? ts.height : void 0;\n out.rangeTrackRadius = styledTrack ? ts.borderRadius : void 0;\n out.rangeTrackBgImage = styledTrack && ts.backgroundImage !== \"\" ? ts.backgroundImage : void 0;\n out.rangeThumbBg = styledThumb && ms.backgroundColor !== \"\" ? normColor(ms.backgroundColor) : styledThumb ? \"rgba(0, 0, 0, 0)\" : void 0;\n out.rangeThumbWidth = styledThumb ? ms.width : void 0;\n out.rangeThumbHeight = styledThumb ? ms.height : void 0;\n out.rangeThumbRadius = styledThumb ? ms.borderRadius : void 0;\n out.rangeThumbBgImage = styledThumb && ms.backgroundImage !== \"\" ? ms.backgroundImage : void 0;\n out.rangeTrackBorder = styledTrack && ts.border !== \"\" ? ts.border : void 0;\n out.rangeThumbBorder = styledThumb && ms.border !== \"\" ? ms.border : void 0;\n out.rangeThumbBoxShadow = styledThumb && ms.boxShadow !== \"\" ? ms.boxShadow : void 0;\n }\n if (tag === \"input\" && el.type === \"file\") {\n const pseudoCs = window.getComputedStyle(el, \"::file-selector-button\");\n out.fileButtonBg = normColor(pseudoCs.backgroundColor);\n out.fileButtonColor = normColor(pseudoCs.color);\n out.fileButtonBorder = pseudoCs.border;\n out.fileButtonBorderRadius = pseudoCs.borderRadius;\n out.fileButtonPadding = pseudoCs.padding;\n out.fileButtonFontWeight = pseudoCs.fontWeight;\n out.fileButtonFontSize = pseudoCs.fontSize;\n out.fileButtonFontFamily = pseudoCs.fontFamily;\n out.fileButtonMarginRight = pseudoCs.marginRight;\n const c = document.createElement(\"canvas\");\n const ctx = c.getContext(\"2d\");\n if (ctx != null) {\n const weight = pseudoCs.fontWeight || \"400\";\n const size = pseudoCs.fontSize || \"13px\";\n const family = pseudoCs.fontFamily || \"sans-serif\";\n ctx.font = weight + \" \" + size + \" \" + family;\n const label = el.multiple ? \"Choose Files\" : \"Choose File\";\n out.fileButtonLabelWidth = ctx.measureText(label).width;\n }\n }\n return out;\n };\n return { captureFormControls };\n};\n\n// src/capture/script/walker/transforms.ts\nvar transformHasRotationOrSkew = (transformStr) => {\n if (!transformStr || transformStr === \"none\") return false;\n const m2 = /^matrix\\(\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)/.exec(transformStr);\n if (m2) {\n const b = parseFloat(m2[2]);\n const c = parseFloat(m2[3]);\n return Math.abs(b) > 1e-6 || Math.abs(c) > 1e-6;\n }\n const m3 = /^matrix3d\\(\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*[-\\d.eE]+\\s*,\\s*[-\\d.eE]+\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)/.exec(transformStr);\n if (m3) {\n const b = parseFloat(m3[2]);\n const c = parseFloat(m3[3]);\n return Math.abs(b) > 1e-6 || Math.abs(c) > 1e-6;\n }\n return false;\n};\nvar createTransformsHandler = () => {\n const wrapWithFrozenTransform = (el, cs, captureInner) => {\n const originalTransform = cs.transform;\n const hasTransform = originalTransform && originalTransform !== \"none\";\n if (!hasTransform) {\n return captureInner(el, cs, null, null);\n }\n if (transformHasRotationOrSkew(originalTransform)) {\n const inline = el.style.transform;\n el.style.transform = \"translate(0)\";\n try {\n return captureInner(el, cs, originalTransform, cs.transformOrigin);\n } finally {\n el.style.transform = inline;\n }\n }\n return captureInner(el, cs, originalTransform, cs.transformOrigin);\n };\n const threadFrozenTransform = (cs, frozenTransform, _frozenTransformOrigin) => ({\n // For elements with rotation/skew, record the ORIGINAL transform so the\n // renderer wraps a `<g transform=...>` around the (un-rotated) captured\n // rect. For pure translate/scale (or no transform), record `'none'` so\n // the renderer skips the wrap and paints the rect at its captured (=live)\n // position directly. frozenTransform is non-null whenever the element\n // originally had a non-none transform; we only stash the rotation/skew\n // string back into styles.transform.\n transform: frozenTransform != null && transformHasRotationOrSkew(frozenTransform) ? frozenTransform : \"none\",\n transformOrigin: cs.transformOrigin,\n // DM-751: extract `matrix3d` translateZ so the paint-order sort can\n // honor 3D Z position when the parent element has\n // `transform-style: preserve-3d` (which sorts children by Z in 3D\n // space, not by z-index per CSS Transforms 2 §6). We can't represent\n // perspective / actual 3D rendering in SVG; this is paint-order only.\n translateZ: (function() {\n const tt = cs.transform;\n if (tt == null || tt === \"none\" || tt === \"\") return void 0;\n const m3 = /^matrix3d\\(([^)]+)\\)/.exec(tt);\n if (m3 == null) return void 0;\n const parts = m3[1].split(\",\").map((s) => parseFloat(s.trim()));\n const tz = parts[14];\n return Number.isFinite(tz) && tz !== 0 ? tz : void 0;\n })(),\n // DM-587: separately flag elements that ORIGINALLY had a non-none\n // transform — even though we discard the value to suppress the wrap,\n // CSS Transforms 2 §4 says any non-none transform creates a stacking\n // context, and `establishesStackingContext` needs to know that for\n // z-index ordering (e.g. a `transform: translate(0)` on a positioned\n // element creates an SC that traps its descendants' z-index resolution).\n // `frozenTransform != null` is true exactly when the live cs.transform\n // was non-none at capture time.\n transformCreatesSc: frozenTransform != null\n });\n return { wrapWithFrozenTransform, threadFrozenTransform };\n};\n\n// src/capture/script/walker/borders-backgrounds.ts\nvar createBordersBackgroundsHandler = ({ normColor, normGradientColors, resolvePlaceholderShownBg, resolveCornerRadius }) => {\n const isUaColorBorder = (tag, el, cs, side) => tag === \"input\" && el.type === \"color\" && normColor(cs[side], cs.color).replace(/\\s+/g, \"\") === \"rgb(0,0,0)\";\n const tintedBorderColor = (tag, el, cs, side) => isUaColorBorder(tag, el, cs, side) ? \"rgb(118,118,118)\" : normColor(cs[side], cs.color);\n const computeFrostedBgFallback = (cs) => {\n const bdf = cs.backdropFilter || cs.webkitBackdropFilter || \"\";\n if (bdf === \"\" || bdf === \"none\") return void 0;\n const bgCol = normColor(cs.backgroundColor, cs.color);\n let a = 1;\n const m = /rgba?\\(\\s*[^,)\\s]+[ ,]+[^,)\\s]+[ ,]+[^,)\\s]+(?:[ ,/]+([^)]+))?\\)/.exec(bgCol);\n if (m != null && m[1] != null) {\n const av = parseFloat(m[1]);\n if (!isNaN(av)) a = av;\n }\n if (a > 0.1) return void 0;\n const bodyBg = normColor(window.getComputedStyle(document.body).backgroundColor);\n let bodyA = 1;\n const bm = /rgba?\\(\\s*[^,)\\s]+[ ,]+[^,)\\s]+[ ,]+[^,)\\s]+(?:[ ,/]+([^)]+))?\\)/.exec(bodyBg);\n if (bm != null && bm[1] != null) {\n const bav = parseFloat(bm[1]);\n if (!isNaN(bav)) bodyA = bav;\n }\n return bodyA <= 0.1 ? \"rgb(255,255,255)\" : bodyBg;\n };\n const computeBackgroundIntrinsic = (cs) => {\n const bgImage = cs.backgroundImage;\n if (bgImage == null || bgImage === \"none\" || bgImage === \"\") return void 0;\n const layers = [];\n let depth = 0, start = 0;\n for (let i = 0; i < bgImage.length; i++) {\n const c = bgImage[i];\n if (c === \"(\") depth++;\n else if (c === \")\") depth--;\n else if (c === \",\" && depth === 0) {\n layers.push(bgImage.slice(start, i));\n start = i + 1;\n }\n }\n layers.push(bgImage.slice(start));\n return layers.map((layer) => {\n let searchLayer = layer;\n const imgSet = /^\\s*(?:-webkit-)?image-set\\(\\s*([\\s\\S]+)\\s*\\)\\s*$/i.exec(layer);\n if (imgSet != null) searchLayer = imgSet[1];\n const u = /\\burl\\(\\s*(?:\"((?:\\\\.|[^\"\\\\])*)\"|'((?:\\\\.|[^'\\\\])*)'|([^)\\s]+))\\s*\\)/.exec(searchLayer);\n if (u == null) return null;\n const raw = u[1] || u[2] || u[3] || \"\";\n if (raw === \"\") return null;\n const url = raw.replace(/\\\\(.)/g, \"$1\");\n const img = new Image();\n img.src = url;\n const w = img.naturalWidth || 0;\n const h = img.naturalHeight || 0;\n return w > 0 && h > 0 ? { w, h } : null;\n });\n };\n const computeBorderImageIntrinsic = (cs, dim) => {\n const m = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.borderImageSource || \"\");\n if (m == null) return void 0;\n const img = new Image();\n img.src = m[1];\n return img[dim] || void 0;\n };\n const cellHiddenNeighbors = (el, tag, cs) => {\n const out = { top: false, right: false, bottom: false, left: false };\n if (tag !== \"td\" && tag !== \"th\" || cs.borderCollapse !== \"collapse\") return out;\n const tr = el.parentElement;\n if (tr == null || tr.tagName !== \"TR\") return out;\n const rowCells = Array.from(tr.children).filter((c) => c.tagName === \"TD\" || c.tagName === \"TH\");\n const colIdx = rowCells.indexOf(el);\n const hiddenSide = (cell, side) => {\n if (cell == null) return false;\n const cs2 = getComputedStyle(cell);\n return cs2[\"border\" + side + \"Style\"] === \"hidden\";\n };\n if (hiddenSide(rowCells[colIdx - 1], \"Right\")) out.left = true;\n if (hiddenSide(rowCells[colIdx + 1], \"Left\")) out.right = true;\n let table = tr.parentElement;\n while (table != null && table.tagName !== \"TABLE\") table = table.parentElement;\n if (table != null) {\n const allRows = Array.from(table.querySelectorAll(\"tr\")).filter((t) => t.closest(\"table\") === table);\n const rowIdx = allRows.indexOf(tr);\n const above = allRows[rowIdx - 1];\n const below = allRows[rowIdx + 1];\n if (above != null) {\n const aboveCells = Array.from(above.children).filter((c) => c.tagName === \"TD\" || c.tagName === \"TH\");\n if (hiddenSide(aboveCells[colIdx], \"Bottom\")) out.top = true;\n }\n if (below != null) {\n const belowCells = Array.from(below.children).filter((c) => c.tagName === \"TD\" || c.tagName === \"TH\");\n if (hiddenSide(belowCells[colIdx], \"Top\")) out.bottom = true;\n }\n }\n return out;\n };\n const captureBordersBackgrounds = (el, cs, tag, rect, isPlaceholderCapture) => ({\n backgroundColor: (function() {\n if (isPlaceholderCapture) {\n const psBg = resolvePlaceholderShownBg(el);\n if (psBg !== \"\") return normColor(psBg);\n }\n return normColor(cs.backgroundColor, cs.color);\n })(),\n borderColor: normColor(cs.borderColor, cs.color),\n borderWidth: cs.borderWidth,\n borderRadius: cs.borderRadius,\n borderTopLeftRadius: resolveCornerRadius(cs.borderTopLeftRadius, rect.width, rect.height),\n borderTopRightRadius: resolveCornerRadius(cs.borderTopRightRadius, rect.width, rect.height),\n borderBottomRightRadius: resolveCornerRadius(cs.borderBottomRightRadius, rect.width, rect.height),\n borderBottomLeftRadius: resolveCornerRadius(cs.borderBottomLeftRadius, rect.width, rect.height),\n borderTopWidth: cs.borderTopWidth,\n borderRightWidth: cs.borderRightWidth,\n borderBottomWidth: cs.borderBottomWidth,\n borderLeftWidth: cs.borderLeftWidth,\n // DM-690: when an adjacent collapsed-table cell declares its matching\n // side as `border-style: hidden`, CSS 2.1 §17.6.2.1 says we MUST treat\n // our side as hidden too (precedence: `hidden > widest > ...`). Override\n // here at capture time so the renderer's existing `style === 'hidden'`\n // skip suppresses the paint on this side. (Cells whose OWN side is\n // already hidden are unaffected — they pass through.)\n ...(function() {\n const hn = cellHiddenNeighbors(el, tag, cs);\n return {\n borderTopStyle: hn.top ? \"hidden\" : cs.borderTopStyle,\n borderRightStyle: hn.right ? \"hidden\" : cs.borderRightStyle,\n borderBottomStyle: hn.bottom ? \"hidden\" : cs.borderBottomStyle,\n borderLeftStyle: hn.left ? \"hidden\" : cs.borderLeftStyle\n };\n })(),\n borderTopColor: tintedBorderColor(tag, el, cs, \"borderTopColor\"),\n borderRightColor: tintedBorderColor(tag, el, cs, \"borderRightColor\"),\n borderBottomColor: tintedBorderColor(tag, el, cs, \"borderBottomColor\"),\n borderLeftColor: tintedBorderColor(tag, el, cs, \"borderLeftColor\"),\n borderCollapse: cs.borderCollapse,\n frostedBgFallback: computeFrostedBgFallback(cs),\n backgroundImage: normGradientColors(cs.backgroundImage, cs.color),\n backgroundSize: cs.backgroundSize,\n backgroundPosition: cs.backgroundPosition,\n backgroundRepeat: cs.backgroundRepeat,\n backgroundClip: cs.backgroundClip,\n backgroundBlendMode: cs.backgroundBlendMode,\n // DM-462: -webkit-text-fill-color is the property that actually makes\n // the headline text transparent in the background-clip:text idiom\n // (cs.color may still report a normal value).\n webkitTextFillColor: cs.webkitTextFillColor || cs.WebkitTextFillColor || void 0,\n // DM-749: Stripe's keynote-speaker headline pattern — a span with\n // `background-image: <gradient>; background-clip: text; -webkit-text-\n // fill-color: transparent` wraps a child div that holds the actual\n // text. The gradient is on the parent but Chrome lets it paint through\n // the child's glyphs because background-clip: text masks the gradient\n // by the union of all descendant text shapes. When the element's own\n // bg-image is none AND its text-fill-color is transparent AND an\n // ancestor has background-clip: text with a gradient, capture that\n // ancestor's gradient so the renderer can use it as the glyph fill.\n inheritedTextFillGradient: (function() {\n const ownTfc = cs.webkitTextFillColor || cs.WebkitTextFillColor || \"\";\n if (!/^(rgba\\(0[^)]*?,\\s*0\\)|transparent)$/i.test(ownTfc.trim())) return void 0;\n let p = el.parentElement;\n let depth = 0;\n while (p != null && depth < 8) {\n const pcs = window.getComputedStyle(p);\n const bc = (pcs.backgroundClip || \"\") + \" \" + (pcs.webkitBackgroundClip || \"\");\n if (/\\btext\\b/i.test(bc) && pcs.backgroundImage && pcs.backgroundImage !== \"none\" && pcs.backgroundImage !== \"\") {\n return pcs.backgroundImage;\n }\n p = p.parentElement;\n depth++;\n }\n return void 0;\n })(),\n // DM-719: `-webkit-text-stroke-width` / `-webkit-text-stroke-color` paint a\n // stroke around each glyph outline. Captured so the renderer can add a\n // `stroke` attribute to the text-path emission.\n webkitTextStrokeWidth: cs.webkitTextStrokeWidth || cs.WebkitTextStrokeWidth || void 0,\n webkitTextStrokeColor: cs.webkitTextStrokeColor || cs.WebkitTextStrokeColor || void 0,\n paintOrder: cs.paintOrder || void 0,\n backgroundOrigin: cs.backgroundOrigin,\n backgroundAttachment: cs.backgroundAttachment,\n backgroundIntrinsic: computeBackgroundIntrinsic(cs),\n borderImageSource: cs.borderImageSource,\n borderImageSlice: cs.borderImageSlice,\n borderImageWidth: cs.borderImageWidth,\n borderImageOutset: cs.borderImageOutset,\n borderImageRepeat: cs.borderImageRepeat,\n borderImageIntrinsicWidth: computeBorderImageIntrinsic(cs, \"naturalWidth\"),\n borderImageIntrinsicHeight: computeBorderImageIntrinsic(cs, \"naturalHeight\"),\n outlineStyle: cs.outlineStyle,\n outlineWidth: cs.outlineWidth,\n outlineColor: normColor(cs.outlineColor),\n outlineOffset: cs.outlineOffset,\n boxShadow: cs.boxShadow,\n // box-decoration-break: 'slice' (default) vs 'clone'. Drives per-fragment\n // paint of wrapped inline elements; see CapturedElement.inlineFragments.\n boxDecorationBreak: cs.boxDecorationBreak || cs.webkitBoxDecorationBreak || \"slice\"\n });\n return { captureBordersBackgrounds };\n};\n\n// src/capture/script/walker/pseudo-content.ts\nvar createPseudoContentHandler = ({ vp, normColor, measureFontMetrics, textNeedsRaster, resolveCounterValue, isCustomCounterStyle }) => {\n const probePseudoTextWidth = (text, pcs) => {\n const span = document.createElement(\"span\");\n span.style.cssText = \"position:absolute;visibility:hidden;pointer-events:none;left:-99999px;top:-99999px;white-space:pre;line-height:normal;margin:0;padding:0;border:0;text-indent:0\";\n span.style.fontFamily = pcs.fontFamily || \"\";\n span.style.fontSize = pcs.fontSize || \"\";\n span.style.fontWeight = pcs.fontWeight || \"\";\n span.style.fontStyle = pcs.fontStyle || \"\";\n span.style.fontStretch = pcs.fontStretch || \"\";\n span.style.fontVariant = pcs.fontVariant || \"\";\n span.style.fontFeatureSettings = pcs.fontFeatureSettings || \"\";\n span.style.fontVariationSettings = pcs.fontVariationSettings || \"\";\n span.style.letterSpacing = pcs.letterSpacing || \"\";\n span.style.wordSpacing = pcs.wordSpacing || \"\";\n span.textContent = text;\n document.body.appendChild(span);\n const w = span.getBoundingClientRect().width;\n document.body.removeChild(span);\n return w;\n };\n const probePseudoStaticBoxRect = (el, pseudo, pcs) => {\n const probe = document.createElement(\"span\");\n probe.style.cssText = \"pointer-events:none;visibility:hidden;box-sizing:content-box\";\n probe.style.display = pcs.display;\n probe.style.width = pcs.width;\n probe.style.height = pcs.height;\n probe.style.paddingTop = pcs.paddingTop;\n probe.style.paddingRight = pcs.paddingRight;\n probe.style.paddingBottom = pcs.paddingBottom;\n probe.style.paddingLeft = pcs.paddingLeft;\n probe.style.borderTopWidth = pcs.borderTopWidth;\n probe.style.borderRightWidth = pcs.borderRightWidth;\n probe.style.borderBottomWidth = pcs.borderBottomWidth;\n probe.style.borderLeftWidth = pcs.borderLeftWidth;\n probe.style.borderStyle = \"solid\";\n probe.style.borderColor = \"transparent\";\n probe.style.marginTop = pcs.marginTop;\n probe.style.marginRight = pcs.marginRight;\n probe.style.marginBottom = pcs.marginBottom;\n probe.style.marginLeft = pcs.marginLeft;\n probe.style.verticalAlign = pcs.verticalAlign;\n probe.style.font = \"\";\n if (pseudo === \"::before\") el.insertBefore(probe, el.firstChild);\n else el.appendChild(probe);\n const r = probe.getBoundingClientRect();\n probe.remove();\n return r;\n };\n const probePseudoAbsoluteBoxRect = (el, pseudo, pcs) => {\n const probe = document.createElement(\"div\");\n probe.style.cssText = \"pointer-events:none;visibility:hidden;box-sizing:content-box;margin:0\";\n probe.style.position = pcs.position;\n probe.style.top = pcs.top;\n probe.style.right = pcs.right;\n probe.style.bottom = pcs.bottom;\n probe.style.left = pcs.left;\n probe.style.width = pcs.width;\n probe.style.height = pcs.height;\n probe.style.paddingTop = pcs.paddingTop;\n probe.style.paddingRight = pcs.paddingRight;\n probe.style.paddingBottom = pcs.paddingBottom;\n probe.style.paddingLeft = pcs.paddingLeft;\n probe.style.borderTopWidth = pcs.borderTopWidth;\n probe.style.borderRightWidth = pcs.borderRightWidth;\n probe.style.borderBottomWidth = pcs.borderBottomWidth;\n probe.style.borderLeftWidth = pcs.borderLeftWidth;\n probe.style.borderStyle = \"solid\";\n probe.style.borderColor = \"transparent\";\n probe.style.marginTop = pcs.marginTop;\n probe.style.marginRight = pcs.marginRight;\n probe.style.marginBottom = pcs.marginBottom;\n probe.style.marginLeft = pcs.marginLeft;\n probe.style.transform = pcs.transform && pcs.transform !== \"none\" ? pcs.transform : \"\";\n probe.style.transformOrigin = pcs.transformOrigin || \"\";\n if (pseudo === \"::before\") el.insertBefore(probe, el.firstChild);\n else el.appendChild(probe);\n const r = probe.getBoundingClientRect();\n probe.remove();\n return r;\n };\n const pickQuoteChar = (forEl, isOpen) => {\n let depth = 0;\n let p = forEl.parentElement;\n while (p != null) {\n if (p.tagName === \"Q\") depth++;\n p = p.parentElement;\n }\n const cs = window.getComputedStyle(forEl).quotes;\n if (cs == null || cs === \"\" || cs === \"none\" || cs === \"auto\") {\n const pairs = [[\"\\u201C\", \"\\u201D\"], [\"\\u2018\", \"\\u2019\"]];\n const pair = pairs[Math.min(depth, pairs.length - 1)];\n return isOpen ? pair[0] : pair[1];\n }\n const tokens = [];\n let i = 0;\n while (i < cs.length) {\n if (cs[i] === '\"') {\n let j = i + 1;\n let s = \"\";\n while (j < cs.length && cs[j] !== '\"') {\n if (cs[j] === \"\\\\\") {\n s += cs[j + 1];\n j += 2;\n } else {\n s += cs[j];\n j++;\n }\n }\n tokens.push(s);\n i = j + 1;\n } else {\n i++;\n }\n }\n if (tokens.length < 2) {\n const pair = [\"\\u201C\", \"\\u201D\"];\n return isOpen ? pair[0] : pair[1];\n }\n const pairIdx = Math.min(depth, Math.floor((tokens.length - 1) / 2));\n return isOpen ? tokens[pairIdx * 2] : tokens[pairIdx * 2 + 1];\n };\n const capturePseudoContent = (el, cs, rect, counterSnapshot) => {\n const pseudoSegments = [];\n const pseudoBoxes = [];\n for (const pseudo of [\"::before\", \"::after\"]) {\n const pcs = window.getComputedStyle(el, pseudo);\n const content = pcs.content;\n if (content == null || content === \"none\" || content === \"normal\" || content === \"\") continue;\n const opacityNum = parseFloat(pcs.opacity);\n if (Number.isFinite(opacityNum) && opacityNum === 0) continue;\n let text = \"\";\n let imageUrl = \"\";\n let i = 0;\n while (i < content.length) {\n const c = content[i];\n if (c === '\"' || c === \"'\") {\n const end = content.indexOf(c, i + 1);\n if (end < 0) break;\n text += content.slice(i + 1, end);\n i = end + 1;\n } else if (content.startsWith(\"attr(\", i)) {\n const end = content.indexOf(\")\", i);\n if (end < 0) break;\n const attrName = content.slice(i + 5, end).trim();\n text += el.getAttribute(attrName) || \"\";\n i = end + 1;\n } else if (content.startsWith(\"url(\", i)) {\n const end = content.indexOf(\")\", i);\n if (end < 0) break;\n let url = content.slice(i + 4, end).trim();\n if (url.startsWith('\"') && url.endsWith('\"') || url.startsWith(\"'\") && url.endsWith(\"'\")) {\n url = url.slice(1, -1);\n }\n imageUrl = url;\n i = end + 1;\n } else if (content.startsWith(\"counter(\", i) || content.startsWith(\"counters(\", i)) {\n const isCounters = content.startsWith(\"counters(\", i);\n const openIdx = i + (isCounters ? \"counters(\".length : \"counter(\".length);\n const closeIdx = content.indexOf(\")\", openIdx);\n if (closeIdx < 0) {\n i++;\n continue;\n }\n const args = content.slice(openIdx, closeIdx).split(\",\").map((s) => {\n const t = s.trim();\n if (t.startsWith('\"') && t.endsWith('\"') || t.startsWith(\"'\") && t.endsWith(\"'\")) {\n return t.slice(1, -1);\n }\n return t;\n });\n const cname = args[0];\n const sep = isCounters ? args[1] ?? \"\" : \"\";\n const styleArg = isCounters ? args[2] : args[1];\n const useCustomStyle = styleArg != null && styleArg !== \"\" && isCustomCounterStyle != null && isCustomCounterStyle(styleArg);\n const format = (v) => {\n if (!useCustomStyle) return String(v);\n const out = resolveCounterValue(styleArg, v);\n return out != null ? out : String(v);\n };\n const snapshot = counterSnapshot.get(el) || [];\n const matches = snapshot.filter((s) => s.name === cname).map((s) => format(s.value));\n if (isCounters) {\n text += matches.length > 0 ? matches.join(sep) : format(0);\n } else {\n text += matches.length > 0 ? matches[matches.length - 1] : format(0);\n }\n i = closeIdx + 1;\n } else if (content.startsWith(\"open-quote\", i)) {\n text += pickQuoteChar(el, true);\n i += \"open-quote\".length;\n } else if (content.startsWith(\"close-quote\", i)) {\n text += pickQuoteChar(el, false);\n i += \"close-quote\".length;\n } else if (content.startsWith(\"no-open-quote\", i)) {\n i += \"no-open-quote\".length;\n } else if (content.startsWith(\"no-close-quote\", i)) {\n i += \"no-close-quote\".length;\n } else {\n i++;\n }\n }\n if (text === \"\" && imageUrl === \"\") {\n const bgRaw = pcs.backgroundColor;\n const hasBg = bgRaw && bgRaw !== \"\" && bgRaw !== \"rgba(0, 0, 0, 0)\" && bgRaw !== \"transparent\";\n const bgImgRaw = pcs.backgroundImage;\n const hasBgImg = bgImgRaw != null && bgImgRaw !== \"\" && bgImgRaw !== \"none\";\n const bwT = parseFloat(pcs.borderTopWidth) || 0;\n const bwR = parseFloat(pcs.borderRightWidth) || 0;\n const bwB = parseFloat(pcs.borderBottomWidth) || 0;\n const bwL = parseFloat(pcs.borderLeftWidth) || 0;\n const hasBorder = bwT > 0 || bwR > 0 || bwB > 0 || bwL > 0;\n const isBlockLike = pcs.display === \"block\" || pcs.display === \"inline-block\" || pcs.display === \"flex\";\n const opacityNum2 = parseFloat(pcs.opacity);\n if (Number.isFinite(opacityNum2) && opacityNum2 === 0) continue;\n if (isBlockLike && (hasBg || hasBgImg || hasBorder)) {\n const hostPadL = parseFloat(cs.paddingLeft) || 0;\n const hostPadT = parseFloat(cs.paddingTop) || 0;\n const hostBorL = parseFloat(cs.borderLeftWidth) || 0;\n const hostBorT = parseFloat(cs.borderTopWidth) || 0;\n const hostBorR = parseFloat(cs.borderRightWidth) || 0;\n const pMarL = parseFloat(pcs.marginLeft) || 0;\n const pPadL = parseFloat(pcs.paddingLeft) || 0;\n const pPadR = parseFloat(pcs.paddingRight) || 0;\n const pPadT = parseFloat(pcs.paddingTop) || 0;\n const pPadB = parseFloat(pcs.paddingBottom) || 0;\n const hostContentW = rect.width - hostBorL - hostBorR - hostPadL - (parseFloat(cs.paddingRight) || 0);\n const pcsW = parseFloat(pcs.width);\n const pcsH = parseFloat(pcs.height);\n const contentW = !isNaN(pcsW) ? pcsW : hostContentW - pMarL - (parseFloat(pcs.marginRight) || 0);\n const contentH = !isNaN(pcsH) ? pcsH : 0;\n const borderBoxW = contentW + pPadL + pPadR + bwL + bwR;\n const borderBoxH = contentH + pPadT + pPadB + bwT + bwB;\n let borderBoxX;\n let borderBoxY;\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pr = probePseudoAbsoluteBoxRect(el, pseudo, pcs);\n borderBoxX = pr.left - vp.x;\n borderBoxY = pr.top - vp.y;\n } else {\n const pMarT = parseFloat(pcs.marginTop) || 0;\n borderBoxX = rect.left - vp.x + hostBorL + hostPadL + pMarL;\n borderBoxY = rect.top - vp.y + hostBorT + hostPadT + pMarT;\n const dispIsInline = pcs.display === \"inline-block\" || pcs.display === \"inline-flex\" || pcs.display === \"inline-grid\" || pcs.display === \"inline-table\";\n if (dispIsInline) {\n const pr = probePseudoStaticBoxRect(el, pseudo, pcs);\n borderBoxY = pr.top - vp.y;\n if (pseudo === \"::after\") {\n borderBoxX = pr.left - vp.x;\n } else {\n const pMarR = parseFloat(pcs.marginRight) || 0;\n borderBoxX = pr.left - vp.x - pMarR - borderBoxW - pMarL;\n }\n }\n }\n let degenerateHostTransform = false;\n if (cs.transform && cs.transform !== \"none\") {\n const m2 = /^matrix\\(\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)\\s*,\\s*([-\\d.eE]+)/.exec(cs.transform);\n if (m2) {\n const a = parseFloat(m2[1]);\n const b = parseFloat(m2[2]);\n const c = parseFloat(m2[3]);\n const d = parseFloat(m2[4]);\n if (Math.abs(a * d - b * c) < 1e-9) degenerateHostTransform = true;\n }\n }\n if (borderBoxW > 0 && borderBoxH > 0 && !degenerateHostTransform) {\n const pcsTransform = pcs.transform && pcs.transform !== \"none\" ? pcs.transform : void 0;\n const pcsTransformOrigin = pcsTransform != null ? pcs.transformOrigin || void 0 : void 0;\n pseudoBoxes.push({\n x: borderBoxX,\n y: borderBoxY,\n width: borderBoxW,\n height: borderBoxH,\n backgroundColor: hasBg ? normColor(bgRaw) : void 0,\n backgroundImage: hasBgImg ? bgImgRaw : void 0,\n borderTopWidth: bwT,\n borderTopColor: bwT > 0 ? normColor(pcs.borderTopColor) : void 0,\n borderTopStyle: pcs.borderTopStyle,\n borderRightWidth: bwR,\n borderRightColor: bwR > 0 ? normColor(pcs.borderRightColor) : void 0,\n borderRightStyle: pcs.borderRightStyle,\n borderBottomWidth: bwB,\n borderBottomColor: bwB > 0 ? normColor(pcs.borderBottomColor) : void 0,\n borderBottomStyle: pcs.borderBottomStyle,\n borderLeftWidth: bwL,\n borderLeftColor: bwL > 0 ? normColor(pcs.borderLeftColor) : void 0,\n borderLeftStyle: pcs.borderLeftStyle,\n borderRadius: parseFloat(pcs.borderRadius) || 0,\n transform: pcsTransform,\n transformOrigin: pcsTransformOrigin\n });\n }\n }\n continue;\n }\n if (imageUrl !== \"\" && text === \"\") {\n const probeImg = new Image();\n probeImg.src = imageUrl;\n const intrinsicW = probeImg.naturalWidth || 0;\n const intrinsicH = probeImg.naturalHeight || 0;\n let layoutW = parseFloat(pcs.width) || 0;\n let layoutH = parseFloat(pcs.height) || 0;\n if (layoutW <= 0) layoutW = intrinsicW || 24;\n if (layoutH <= 0) layoutH = intrinsicH || 24;\n const renderW = intrinsicW > 0 ? intrinsicW : layoutW;\n const renderH = intrinsicH > 0 ? intrinsicH : layoutH;\n const elTop2 = rect.top - vp.y + (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.borderTopWidth) || 0);\n const elLeft2 = rect.left - vp.x + (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.borderLeftWidth) || 0);\n const elFontSizeForImg = parseFloat(pcs.fontSize) || 14;\n const lineHImg = parseFloat(pcs.lineHeight) || elFontSizeForImg * 1.2;\n const yPosImg = elTop2 + (lineHImg - layoutH) / 2;\n pseudoSegments.push({\n isBefore: pseudo === \"::before\",\n imageUrl,\n seg: { text: \"\", x: elLeft2, y: yPosImg, width: layoutW, height: layoutH },\n renderWidth: renderW,\n renderHeight: renderH,\n color: pcs.color,\n boxMarginLeft: parseFloat(pcs.marginLeft) || 0,\n boxMarginRight: parseFloat(pcs.marginRight) || 0,\n boxBorderLeft: parseFloat(pcs.borderLeftWidth) || 0,\n boxBorderRight: parseFloat(pcs.borderRightWidth) || 0,\n boxPaddingLeft: parseFloat(pcs.paddingLeft) || 0,\n boxPaddingRight: parseFloat(pcs.paddingRight) || 0\n });\n continue;\n }\n if (text === \"\") continue;\n let pseudoWidth = probePseudoTextWidth(text, pcs);\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pcsW = parseFloat(pcs.width);\n if (!isNaN(pcsW) && pcsW > 0) pseudoWidth = pcsW;\n }\n const elTop = rect.top - vp.y + (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.borderTopWidth) || 0);\n const elLeft = rect.left - vp.x + (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.borderLeftWidth) || 0);\n const elFontSize = parseFloat(pcs.fontSize) || 14;\n const lineH = parseFloat(pcs.lineHeight) || elFontSize * 1.2;\n const pseudoMetrics = measureFontMetrics(pcs);\n let xPos;\n let yPos;\n let pseudoIsPositioned = false;\n if (pcs.position === \"absolute\" || pcs.position === \"fixed\") {\n const pcsLeft = parseFloat(pcs.left);\n const pcsTop = parseFloat(pcs.top);\n const pcsRight = parseFloat(pcs.right);\n const pcsBottom = parseFloat(pcs.bottom);\n const paddingBoxLeft = rect.left - vp.x + (parseFloat(cs.borderLeftWidth) || 0);\n const paddingBoxTop = rect.top - vp.y + (parseFloat(cs.borderTopWidth) || 0);\n const paddingBoxRight = rect.right - vp.x - (parseFloat(cs.borderRightWidth) || 0);\n const paddingBoxBottom = rect.bottom - vp.y - (parseFloat(cs.borderBottomWidth) || 0);\n const pPadL = parseFloat(pcs.paddingLeft) || 0;\n const pPadR = parseFloat(pcs.paddingRight) || 0;\n const pPadT = parseFloat(pcs.paddingTop) || 0;\n const pPadB = parseFloat(pcs.paddingBottom) || 0;\n const pBorL = parseFloat(pcs.borderLeftWidth) || 0;\n const pBorR = parseFloat(pcs.borderRightWidth) || 0;\n const pBorT = parseFloat(pcs.borderTopWidth) || 0;\n const pBorB = parseFloat(pcs.borderBottomWidth) || 0;\n if (!isNaN(pcsLeft)) xPos = paddingBoxLeft + pcsLeft;\n else if (!isNaN(pcsRight)) xPos = paddingBoxRight - pcsRight - pseudoWidth - pPadL - pPadR - pBorL - pBorR;\n else xPos = paddingBoxLeft;\n if (!isNaN(pcsTop)) yPos = paddingBoxTop + pcsTop;\n else if (!isNaN(pcsBottom)) yPos = paddingBoxBottom - pcsBottom - lineH - pPadT - pPadB - pBorT - pBorB;\n else yPos = paddingBoxTop;\n xPos += pPadL + pBorL;\n yPos += pPadT + pBorT;\n yPos += (lineH - elFontSize) / 2;\n pseudoIsPositioned = true;\n } else {\n yPos = elTop + (lineH - elFontSize) / 2;\n const pcsMarginL = parseFloat(pcs.marginLeft) || 0;\n const pcsBorderL = parseFloat(pcs.borderLeftWidth) || 0;\n const pcsPaddingL = parseFloat(pcs.paddingLeft) || 0;\n if (pseudo === \"::before\") {\n xPos = elLeft + pcsMarginL + pcsBorderL + pcsPaddingL;\n } else {\n xPos = elLeft + rect.width - pseudoWidth - 2 * (parseFloat(cs.paddingRight) || 0);\n }\n }\n const pseudoSeg = {\n text,\n x: xPos,\n y: yPos,\n width: pseudoWidth,\n height: elFontSize,\n // Carry pseudo-specific typography so the renderer can respect\n // per-pseudo color, font-size, font-weight, font-family, font-style\n // (CSS lets pseudos style independently of their parent — Slashdot's\n // \"Most Discussed\" carousel heading is a ::after that's italic+bordered\n // on a non-italic host div).\n color: pcs.color,\n fontSize: elFontSize,\n fontWeight: pcs.fontWeight,\n fontFamily: pcs.fontFamily,\n fontStyle: pcs.fontStyle,\n fontAscent: pseudoMetrics.ascent\n };\n const pseudoBgRaw = pcs.backgroundColor;\n const pseudoBgColor = pseudoBgRaw && pseudoBgRaw !== \"\" && pseudoBgRaw !== \"rgba(0, 0, 0, 0)\" && pseudoBgRaw !== \"transparent\" ? normColor(pseudoBgRaw) : \"\";\n const pseudoBR = parseFloat(pcs.borderRadius) || 0;\n const bwTop = parseFloat(pcs.borderTopWidth) || 0;\n const bwRight = parseFloat(pcs.borderRightWidth) || 0;\n const bwBottom = parseFloat(pcs.borderBottomWidth) || 0;\n const bwLeft = parseFloat(pcs.borderLeftWidth) || 0;\n const bwUniform = bwTop > 0 && bwRight === bwTop && bwBottom === bwTop && bwLeft === bwTop;\n const pseudoBC = bwUniform ? normColor(pcs.borderTopColor) : \"\";\n const colorIsPaintable = (raw) => raw !== \"\" && raw !== \"rgba(0, 0, 0, 0)\" && raw !== \"transparent\";\n const sideBorderTopColor = bwTop > 0 ? normColor(pcs.borderTopColor) : \"\";\n const sideBorderRightColor = bwRight > 0 ? normColor(pcs.borderRightColor) : \"\";\n const sideBorderBottomColor = bwBottom > 0 ? normColor(pcs.borderBottomColor) : \"\";\n const sideBorderLeftColor = bwLeft > 0 ? normColor(pcs.borderLeftColor) : \"\";\n const hasPerSideBorder = !bwUniform && (bwTop > 0 && colorIsPaintable(sideBorderTopColor) || bwRight > 0 && colorIsPaintable(sideBorderRightColor) || bwBottom > 0 && colorIsPaintable(sideBorderBottomColor) || bwLeft > 0 && colorIsPaintable(sideBorderLeftColor));\n const pseudoBgImgRaw = pcs.backgroundImage;\n const hasPseudoBgImg = pseudoBgImgRaw != null && pseudoBgImgRaw !== \"\" && pseudoBgImgRaw !== \"none\";\n const pseudoTransform = pcs.transform && pcs.transform !== \"none\" ? pcs.transform : void 0;\n const pseudoTransformOrigin = pseudoTransform != null ? pcs.transformOrigin || void 0 : void 0;\n let pseudoBoxStyles = null;\n if (pseudoBgColor !== \"\" || hasPseudoBgImg || pseudoBR > 0 || bwUniform && pseudoBC !== \"\" && pseudoBC !== \"rgba(0, 0, 0, 0)\" || hasPerSideBorder || pseudoTransform != null) {\n pseudoBoxStyles = {\n padL: parseFloat(pcs.paddingLeft) || 0,\n padR: parseFloat(pcs.paddingRight) || 0,\n padT: parseFloat(pcs.paddingTop) || 0,\n padB: parseFloat(pcs.paddingBottom) || 0,\n borL: bwLeft,\n borR: bwRight,\n borT: bwTop,\n borB: bwBottom,\n // Inline-box bg paints at line-height, not at font-size — so\n // the box's vertical extent is lineH + padding + border (not\n // fontSize). Capture lineH alongside the metrics; the post-\n // injection block uses it to compute boxH and boxY (centered\n // on the line box).\n lineH,\n fontSize: elFontSize,\n backgroundColor: pseudoBgColor !== \"\" ? pseudoBgColor : void 0,\n backgroundImage: hasPseudoBgImg ? pseudoBgImgRaw : void 0,\n borderRadius: pseudoBR > 0 ? pseudoBR : void 0,\n borderWidth: bwUniform ? bwTop : void 0,\n borderColor: bwUniform && pseudoBC !== \"\" && pseudoBC !== \"rgba(0, 0, 0, 0)\" ? pseudoBC : void 0,\n transform: pseudoTransform,\n transformOrigin: pseudoTransformOrigin,\n // Per-side colors. Renderer reads these when no uniform border\n // is set and emits a `<line>` for each side whose width > 0 and\n // color is paintable. Undefined when the side has no visible\n // border, keeping the captured tree compact in the common case.\n borderTopColor: hasPerSideBorder && bwTop > 0 && colorIsPaintable(sideBorderTopColor) ? sideBorderTopColor : void 0,\n borderRightColor: hasPerSideBorder && bwRight > 0 && colorIsPaintable(sideBorderRightColor) ? sideBorderRightColor : void 0,\n borderBottomColor: hasPerSideBorder && bwBottom > 0 && colorIsPaintable(sideBorderBottomColor) ? sideBorderBottomColor : void 0,\n borderLeftColor: hasPerSideBorder && bwLeft > 0 && colorIsPaintable(sideBorderLeftColor) ? sideBorderLeftColor : void 0\n };\n }\n let allPua = text.length > 0;\n for (let _ci = 0; _ci < text.length; ) {\n const cp = text.codePointAt(_ci);\n const inPua = cp >= 57344 && cp <= 63743 || cp >= 983040 && cp <= 1048573 || cp >= 1048576 && cp <= 1114109;\n if (!inPua) {\n allPua = false;\n break;\n }\n _ci += cp > 65535 ? 2 : 1;\n }\n if (textNeedsRaster(text) || allPua) {\n if (allPua && !textNeedsRaster(text)) {\n pseudoSeg.rasterRect = {\n x: rect.left - vp.x,\n y: rect.top - vp.y,\n width: rect.width,\n height: rect.height\n };\n } else {\n pseudoSeg.rasterRect = {\n x: pseudoSeg.x,\n y: elTop,\n width: pseudoWidth,\n height: lineH\n };\n }\n }\n pseudoSegments.push({\n isBefore: pseudo === \"::before\",\n seg: pseudoSeg,\n color: pcs.color,\n isPositioned: pseudoIsPositioned,\n boxStyles: pseudoBoxStyles\n });\n }\n return { pseudoSegments, pseudoBoxes };\n };\n return { capturePseudoContent };\n};\n\n// src/capture/script/walker/input-value.ts\nvar SKIP_VALUE_TYPES = /* @__PURE__ */ new Set([\n \"range\",\n \"color\",\n \"checkbox\",\n \"radio\",\n \"file\",\n \"image\",\n \"hidden\",\n \"date\",\n \"time\",\n \"datetime-local\",\n \"month\",\n \"week\"\n]);\nvar NOT_APPLIED = { applied: false };\nvar createInputValueHandler = ({ vp, normColor, measureFontMetrics }) => {\n const captureInputValue = (el, cs, tag, rect) => {\n if (tag !== \"input\" && tag !== \"textarea\") return NOT_APPLIED;\n const inputType = tag === \"input\" ? el.type || \"text\" : \"\";\n if (SKIP_VALUE_TYPES.has(inputType)) return NOT_APPLIED;\n let isPlaceholderCapture = false;\n let text = \"\";\n if (!el.value) {\n const placeholder = el.getAttribute && el.getAttribute(\"placeholder\");\n if (placeholder != null && placeholder !== \"\") {\n isPlaceholderCapture = true;\n text = placeholder;\n } else {\n return NOT_APPLIED;\n }\n } else {\n text = inputType === \"password\" ? \"\\u2022\".repeat(el.value.length) : el.value;\n }\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n let textLeft = rect.left - vp.x + bl + pl;\n let textTop = rect.top - vp.y + bt + pt;\n const textHeight = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2;\n const textWidth = rect.width - bl * 2 - pl * 2;\n const display = cs.display;\n const isFlexLike = display === \"flex\" || display === \"inline-flex\" || display === \"grid\" || display === \"inline-grid\";\n const isButtonInput = tag === \"input\" && (inputType === \"submit\" || inputType === \"button\" || inputType === \"reset\");\n if (isFlexLike && cs.alignItems === \"center\" || isButtonInput) {\n const contentH = rect.height - bt - bb - pt - pb;\n if (contentH > textHeight + 0.5) {\n textTop = rect.top - vp.y + bt + pt + (contentH - textHeight) / 2;\n }\n }\n const metrics = measureFontMetrics(cs);\n const fontAscent = metrics.ascent;\n const fontDescent = metrics.descent;\n const fontH = fontAscent + fontDescent;\n if (fontH > textHeight + 0.5) {\n textTop -= (fontH - textHeight) / 2;\n }\n let inputXOffsets;\n if (text.length > 0 && tag === \"input\") {\n const probe = document.createElement(\"span\");\n probe.style.position = \"absolute\";\n probe.style.left = \"-9999px\";\n probe.style.top = \"-9999px\";\n probe.style.visibility = \"hidden\";\n probe.style.whiteSpace = \"pre\";\n probe.style.fontFamily = cs.fontFamily;\n probe.style.fontSize = cs.fontSize;\n probe.style.fontWeight = cs.fontWeight;\n probe.style.fontStyle = cs.fontStyle;\n probe.style.letterSpacing = cs.letterSpacing;\n probe.style.fontKerning = cs.fontKerning;\n probe.style.fontVariationSettings = cs.fontVariationSettings;\n probe.style.fontFeatureSettings = cs.fontFeatureSettings;\n probe.textContent = text;\n document.body.appendChild(probe);\n const probeNode = probe.firstChild;\n if (probeNode != null) {\n const probeBox = probe.getBoundingClientRect();\n const probeOriginX = probeBox.left;\n const xs = [];\n let i = 0;\n while (i < text.length) {\n const code = text.charCodeAt(i);\n const isHigh = code >= 55296 && code <= 56319 && i + 1 < text.length;\n const step = isHigh ? 2 : 1;\n const rng = document.createRange();\n rng.setStart(probeNode, i);\n rng.setEnd(probeNode, i + step);\n const cr = rng.getBoundingClientRect();\n const left = cr.left - probeOriginX + textLeft;\n for (let k = 0; k < step; k++) xs.push(left);\n i += step;\n }\n const contentBoxW = rect.width - bl - br - pl - pr;\n const probeW = probeBox.width;\n const slack = contentBoxW - probeW;\n const align = cs.textAlign;\n const dir = cs.direction;\n let shift = 0;\n if (slack > 0) {\n if (align === \"center\") shift = slack / 2;\n else if (align === \"right\" || align === \"end\" && dir !== \"rtl\" || align === \"start\" && dir === \"rtl\") shift = slack;\n }\n if (shift !== 0) {\n textLeft += shift;\n for (let k = 0; k < xs.length; k++) xs[k] += shift;\n }\n inputXOffsets = xs;\n }\n document.body.removeChild(probe);\n }\n let placeholderColor;\n let placeholderFontStyle;\n let placeholderFontWeight;\n if (isPlaceholderCapture) {\n const phCs = window.getComputedStyle(el, \"::placeholder\");\n placeholderColor = normColor(phCs.color || cs.color);\n placeholderFontStyle = phCs.fontStyle;\n placeholderFontWeight = phCs.fontWeight;\n }\n return {\n applied: true,\n text,\n textLeft,\n textTop,\n textHeight,\n textWidth,\n fontAscent,\n fontDescent,\n inputXOffsets,\n isPlaceholderCapture,\n placeholderColor,\n placeholderFontStyle,\n placeholderFontWeight\n };\n };\n return { captureInputValue };\n};\n\n// src/capture/script/walker/text-segments.ts\nvar computeElementRaster = (el, cs, tag, rect, vp) => {\n const hasTextareaValue = tag === \"textarea\" && el.value;\n const hasNonHorizontalText = cs.writingMode && cs.writingMode !== \"horizontal-tb\" && (el.textContent || \"\").trim() !== \"\";\n const isTextInput = tag === \"input\" && (el.type === \"text\" || el.type === \"search\" || el.type === \"email\" || el.type === \"tel\" || el.type === \"url\" || el.type === \"password\" || el.type === \"number\" || el.type === \"\" || el.type == null);\n const hasInputText = isTextInput && (el.value || el.getAttribute && el.getAttribute(\"placeholder\"));\n if (!hasTextareaValue && !hasNonHorizontalText && !hasInputText) return void 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const bl = parseFloat(cs.borderLeftWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n return {\n x: rect.left - vp.x + bl + pl,\n y: rect.top - vp.y + bt + pt,\n width: Math.max(1, rect.width - bl - br - pl - pr),\n height: Math.max(1, rect.height - bt - bb - pt - pb)\n };\n};\nvar createTextSegmentsHandler = ({ vp, measureFontMetrics, needsRaster }) => {\n const captureTextSegments = (el, cs) => {\n const textSegments = [];\n let text = \"\";\n let minLeft = Infinity;\n let minTop = Infinity;\n let maxRight = -Infinity;\n let maxBottom = -Infinity;\n const flStyle = window.getComputedStyle(el, \"::first-letter\");\n const elFsRaw = parseFloat(cs.fontSize) || 0;\n const flFsRaw = parseFloat(flStyle.fontSize) || 0;\n const firstLetterStyled = flFsRaw > 0 && Math.abs(flFsRaw - elFsRaw) > 0.5;\n let firstCharSeen = false;\n const elTag = el.tagName != null ? el.tagName.toLowerCase() : \"\";\n const _miText = (el.textContent || \"\").trim();\n const mathItalicizeMi = elTag === \"mi\" && [..._miText].length === 1 && /^[a-zA-ZΑ-ΩΆΈΉΊΌΎΏα-ωϐϑϕϖϗϰϱϵ∂∇]$/u.test(_miText);\n const mathItalicChar = (ch) => {\n const code = ch.codePointAt(0);\n if (code == null) return ch;\n if (code >= 65 && code <= 90) return String.fromCodePoint(119860 + (code - 65));\n if (code >= 97 && code <= 122) {\n if (code === 104) return \"\\u210E\";\n return String.fromCodePoint(119886 + (code - 97));\n }\n if (code >= 913 && code <= 937) return String.fromCodePoint(120546 + (code - 913));\n if (code >= 945 && code <= 969) return String.fromCodePoint(120572 + (code - 945));\n switch (code) {\n case 8706:\n return String.fromCodePoint(120597);\n // ∂ → italic partial differential\n case 1013:\n return String.fromCodePoint(120598);\n // ϵ (lunate) → italic epsilon symbol\n case 977:\n return String.fromCodePoint(120599);\n // ϑ (theta sym) → italic theta symbol\n case 1008:\n return String.fromCodePoint(120600);\n // ϰ (kappa sym) → italic kappa symbol\n case 981:\n return String.fromCodePoint(120601);\n // ϕ (phi sym) → italic phi symbol\n case 1009:\n return String.fromCodePoint(120602);\n // ϱ (rho sym) → italic rho symbol\n case 982:\n return String.fromCodePoint(120603);\n // ϖ (pi sym) → italic pi symbol\n case 8711:\n return String.fromCodePoint(120571);\n // ∇ (nabla) → italic nabla (upper-block tail)\n default:\n return ch;\n }\n };\n for (const node of el.childNodes) {\n if (node.nodeType !== Node.TEXT_NODE) continue;\n let raw = node.textContent || \"\";\n const tt = cs.textTransform;\n if (tt === \"uppercase\") raw = raw.toUpperCase();\n else if (tt === \"lowercase\") raw = raw.toLowerCase();\n else if (tt === \"capitalize\") raw = raw.replace(/\\b\\p{L}/gu, (ch) => ch.toUpperCase());\n if (!raw.trim()) continue;\n const rawForText = mathItalicizeMi ? mathItalicChar(raw.trim()) : raw.trim();\n text += rawForText + \" \";\n const lines = [];\n let cur = null;\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n const isHighSurrogate = code >= 55296 && code <= 56319 && i + 1 < raw.length;\n const step = isHighSurrogate ? 2 : 1;\n const r = document.createRange();\n r.setStart(node, i);\n r.setEnd(node, i + step);\n const cr = r.getBoundingClientRect();\n const isWs = step === 1 && /\\s/.test(raw[i]);\n if (cr.width === 0 && (cr.height === 0 || isWs)) {\n i += step - 1;\n continue;\n }\n let ch = raw.slice(i, i + step);\n if (mathItalicizeMi) ch = mathItalicChar(ch);\n const charRec = { ch, left: cr.left, top: cr.top, right: cr.right, bottom: cr.bottom };\n if (cur == null || Math.abs(cr.top - cur.top) > 1) {\n if (cur != null) lines.push(cur);\n cur = { chars: [charRec], top: cr.top, bottom: cr.bottom, left: cr.left, right: cr.right };\n } else {\n cur.chars.push(charRec);\n cur.left = Math.min(cur.left, cr.left);\n cur.right = Math.max(cur.right, cr.right);\n cur.bottom = Math.max(cur.bottom, cr.bottom);\n }\n i += step - 1;\n }\n if (cur != null) lines.push(cur);\n const fragmentedLines = [];\n for (const ln of lines) {\n if (ln.chars.length <= 1) {\n fragmentedLines.push(ln);\n continue;\n }\n let frag = { chars: [ln.chars[0]], top: ln.top, bottom: ln.bottom };\n const fragments = [frag];\n for (let ci = 1; ci < ln.chars.length; ci++) {\n const prev = ln.chars[ci - 1];\n const cc = ln.chars[ci];\n const leftJump = cc.left < prev.left - 80;\n const rightJump = cc.left > prev.right + 80;\n if (leftJump || rightJump) {\n frag = { chars: [cc], top: ln.top, bottom: ln.bottom };\n fragments.push(frag);\n } else {\n frag.chars.push(cc);\n }\n }\n for (const f of fragments) {\n let l = Infinity;\n let r = -Infinity;\n for (const c of f.chars) {\n if (c.left < l) l = c.left;\n if (c.right > r) r = c.right;\n }\n f.left = l;\n f.right = r;\n fragmentedLines.push(f);\n }\n }\n lines.length = 0;\n for (const fl of fragmentedLines) lines.push(fl);\n for (const ln of lines) {\n ln.text = ln.chars.map((c) => c.ch).join(\"\");\n const xo = [];\n for (const c of ln.chars) {\n for (let k = 0; k < c.ch.length; k++) xo.push(c.left);\n }\n ln.xOffsets = xo;\n }\n for (const line of lines) {\n const visualText = line.text.replace(/[\\t\\n\\r]/g, \" \");\n if (visualText.replace(/\\s/g, \"\") === \"\") continue;\n const rasterGlyphs = [];\n let utf16Idx = 0;\n for (let ci = 0; ci < line.chars.length; ci++) {\n const cRec = line.chars[ci];\n const cp = cRec.ch.codePointAt(0);\n const nextCh = ci + 1 < line.chars.length ? line.chars[ci + 1].ch : \"\";\n const nextCp = nextCh ? nextCh.codePointAt(0) : 0;\n const isFirstLetter = firstLetterStyled && !firstCharSeen && /\\S/.test(cRec.ch);\n if (isFirstLetter) firstCharSeen = true;\n if (cp != null && needsRaster(cp, nextCp) || isFirstLetter) {\n let rasterTop = cRec.top - vp.y;\n let rasterHeight = cRec.bottom - cRec.top;\n if (isFirstLetter) {\n const ilRaw = flStyle.initialLetter || flStyle.webkitInitialLetter || \"\";\n const ilN = parseFloat(ilRaw);\n const parentLineHeight = parseFloat(cs.lineHeight);\n if (Number.isFinite(ilN) && ilN > 1 && Number.isFinite(parentLineHeight) && parentLineHeight > 0) {\n const expectedHeight = ilN * parentLineHeight;\n if (expectedHeight > rasterHeight) {\n rasterHeight = expectedHeight;\n }\n }\n }\n rasterGlyphs.push({\n charIndex: utf16Idx,\n rect: {\n x: cRec.left - vp.x,\n y: rasterTop,\n width: cRec.right - cRec.left,\n height: rasterHeight\n },\n // ::first-letter drop caps: suppress the path glyph so\n // only the rasterized big letter paints (DM-439).\n suppressGlyph: isFirstLetter ? true : void 0\n });\n }\n utf16Idx += cRec.ch.length;\n }\n textSegments.push({\n text: visualText,\n x: line.left - vp.x,\n y: line.top - vp.y,\n width: line.right - line.left,\n height: line.bottom - line.top,\n xOffsets: line.xOffsets.map((v) => v - vp.x),\n rasterGlyphs: rasterGlyphs.length > 0 ? rasterGlyphs : void 0\n });\n minLeft = Math.min(minLeft, line.left);\n minTop = Math.min(minTop, line.top);\n maxRight = Math.max(maxRight, line.right);\n maxBottom = Math.max(maxBottom, line.bottom);\n }\n }\n if (textSegments.length > 0) {\n const flLineStyle = window.getComputedStyle(el, \"::first-line\");\n const firstSeg = textSegments[0];\n if (flLineStyle.fontVariant !== \"\" && flLineStyle.fontVariant !== cs.fontVariant) {\n firstSeg.fontVariant = flLineStyle.fontVariant;\n }\n if (flLineStyle.color !== \"\" && flLineStyle.color !== cs.color) {\n firstSeg.color = flLineStyle.color;\n }\n if (flLineStyle.fontWeight !== \"\" && flLineStyle.fontWeight !== cs.fontWeight) {\n firstSeg.fontWeight = flLineStyle.fontWeight;\n }\n if (flLineStyle.fontStyle !== \"\" && flLineStyle.fontStyle !== cs.fontStyle) {\n firstSeg.fontStyle = flLineStyle.fontStyle;\n }\n const flFs = parseFloat(flLineStyle.fontSize);\n const elFs2 = parseFloat(cs.fontSize);\n if (flFs > 0 && Math.abs(flFs - elFs2) > 0.1) {\n firstSeg.fontSize = flFs;\n }\n }\n text = text.trim();\n if (minLeft < Infinity) {\n const metrics = measureFontMetrics(cs);\n return {\n applied: true,\n text,\n textSegments,\n textLeft: minLeft - vp.x,\n textTop: minTop - vp.y,\n textWidth: maxRight - minLeft,\n textHeight: maxBottom - minTop,\n fontAscent: metrics.ascent,\n fontDescent: metrics.descent\n };\n }\n return { applied: true, text, textSegments };\n };\n return { captureTextSegments };\n};\n\n// src/capture/script/walker/pseudo-inject.ts\nvar createPseudoInjectHandler = () => {\n const injectPseudoSegments = (el, pseudoSegments, textSegments, state) => {\n const pseudoImages = [];\n let { text, textLeft, textTop, textWidth, textHeight, fontAscent } = state;\n for (const p of pseudoSegments) {\n if (p.imageUrl) {\n const mL = p.boxMarginLeft || 0;\n const mR = p.boxMarginRight || 0;\n const bL = p.boxBorderLeft || 0;\n const bR = p.boxBorderRight || 0;\n const pL = p.boxPaddingLeft || 0;\n const pR = p.boxPaddingRight || 0;\n if (p.isBefore && textSegments.length > 0) {\n const firstSeg = textSegments[0];\n p.seg.x = firstSeg.x - p.seg.width - pR - bR - mR;\n p.seg.y = firstSeg.y + (firstSeg.height - p.seg.height) / 2;\n } else if (!p.isBefore && textSegments.length > 0) {\n const lastSeg = textSegments[textSegments.length - 1];\n p.seg.x = lastSeg.x + lastSeg.width + mL + bL + pL;\n p.seg.y = lastSeg.y + (lastSeg.height - p.seg.height) / 2;\n }\n pseudoImages.push({\n url: p.imageUrl,\n x: p.seg.x,\n y: p.seg.y,\n width: p.renderWidth,\n height: p.renderHeight\n });\n continue;\n }\n if (p.isPositioned) {\n if (p.isBefore) textSegments.unshift(p.seg);\n else textSegments.push(p.seg);\n } else if (p.isBefore && textSegments.length > 0) {\n const firstSeg = textSegments[0];\n const bs = p.boxStyles || {};\n const mRb = parseFloat(window.getComputedStyle(el, \"::before\").marginRight) || 0;\n p.seg.x = firstSeg.x - p.seg.width - (bs.padR || 0) - (bs.borR || 0) - mRb;\n p.seg.y = firstSeg.y;\n p.seg.height = firstSeg.height;\n textSegments.unshift(p.seg);\n } else if (!p.isBefore && textSegments.length > 0) {\n const lastSeg = textSegments[textSegments.length - 1];\n const bs = p.boxStyles || {};\n const mLa = parseFloat(window.getComputedStyle(el, \"::after\").marginLeft) || 0;\n p.seg.x = lastSeg.x + lastSeg.width + mLa + (bs.borL || 0) + (bs.padL || 0);\n p.seg.y = lastSeg.y;\n p.seg.height = lastSeg.height;\n textSegments.push(p.seg);\n } else {\n textSegments.push(p.seg);\n }\n if (textSegments.length === 1 && textSegments[0] === p.seg) {\n textLeft = p.seg.x;\n textTop = p.seg.y;\n textWidth = p.seg.width;\n textHeight = p.seg.height;\n if (p.seg.fontAscent != null) fontAscent = p.seg.fontAscent;\n }\n if (p.seg.rasterRect != null) {\n const isHostSized = p.seg.rasterRect.width > p.seg.width + 1;\n if (!isHostSized) {\n p.seg.rasterRect.x = p.seg.x;\n p.seg.rasterRect.y = p.seg.y;\n p.seg.rasterRect.height = p.seg.height;\n }\n }\n if (p.boxStyles != null) {\n const bs = p.boxStyles;\n const lineCenter = p.seg.y + bs.fontSize / 2;\n const boxTop = lineCenter - bs.lineH / 2 - bs.padT - bs.borT;\n const bx = p.seg.x - bs.padL - bs.borL;\n const bw = p.seg.width + bs.padL + bs.padR + bs.borL + bs.borR;\n const bh = bs.lineH + bs.padT + bs.padB + bs.borT + bs.borB;\n if (bw > 0 && bh > 0) {\n p.seg.pseudoBox = {\n x: bx,\n y: boxTop,\n width: bw,\n height: bh,\n backgroundColor: bs.backgroundColor,\n // DM-782: gradient/url() bg-image plumbing — renderer threads\n // each comma-separated layer through `buildBackgroundLayerDef`\n // and paints rect(s) behind the glyphs (mirrors the empty-\n // content pseudoBox path in `element-tree-to-svg.ts`).\n backgroundImage: bs.backgroundImage,\n borderRadius: bs.borderRadius,\n borderWidth: bs.borderWidth,\n borderColor: bs.borderColor,\n // Per-side widths + colors for non-uniform borders (e.g. a\n // bare `border-bottom` on a pseudo). Width fields are always\n // emitted so the renderer doesn't have to fall back to zero\n // when a `borderWidth` (uniform) shorthand is absent.\n borL: bs.borL,\n borR: bs.borR,\n borT: bs.borT,\n borB: bs.borB,\n borderTopColor: bs.borderTopColor,\n borderRightColor: bs.borderRightColor,\n borderBottomColor: bs.borderBottomColor,\n borderLeftColor: bs.borderLeftColor,\n // DM-783: pseudo's `transform` + `transformOrigin`. Renderer\n // wraps the box + glyphs in a pre-baked\n // translate-(transform)-translate matrix so the rotation/scale\n // pivots around the box-relative origin instead of (0,0).\n transform: bs.transform,\n transformOrigin: bs.transformOrigin\n };\n }\n }\n text = (p.isBefore ? p.seg.text + \" \" : \" \" + p.seg.text) + text;\n }\n return { pseudoImages, text, textLeft, textTop, textWidth, textHeight, fontAscent };\n };\n return { injectPseudoSegments };\n};\n\n// src/capture/script/index.ts\nreturn ((args) => {\n const sel = args.sel;\n const vp = args.vp;\n const { normColor, normGradientColors } = createColorNorm();\n const { needsRaster, textNeedsRaster } = createEmojiDetect();\n const { measureFontMetrics: _measureFontMetrics, substituteAliasedFamilies: _substituteAliasedFamilies } = createFontMetrics();\n const { resolvePlaceholderShownBg: _resolvePlaceholderShownBg } = createPlaceholderShown();\n const { resolvePseudo: _resolvePseudo, resolveCornerRadius: _resolveCornerRadius } = createPseudoRules();\n const { warn, shortSelector, warnings: _warnings } = createWarnings();\n const _counterStyles = {};\n const { resolveCounterStyle, resolveCounterValue, isCustomCounterStyle } = createCounterStyleResolver({ counterStyles: _counterStyles });\n const { captureListsCounters } = createListsCountersHandler({ normColor, resolveCounterStyle, isCustomCounterStyle });\n const { handleReplacedElement } = createReplacedElementsHandler({ vp });\n const { discoverMasks, discoverClipPaths, maskDefs: _maskDefs, maskRasters: _maskRasters, clipPathDefs: _clipPathDefs } = createMasksClipsHandler({ vp, warn });\n const { captureFormControls } = createFormControlsHandler({ normColor, resolvePseudo: _resolvePseudo });\n const { wrapWithFrozenTransform, threadFrozenTransform } = createTransformsHandler();\n const { captureBordersBackgrounds } = createBordersBackgroundsHandler({\n normColor,\n normGradientColors,\n resolvePlaceholderShownBg: _resolvePlaceholderShownBg,\n resolveCornerRadius: _resolveCornerRadius\n });\n const { capturePseudoContent } = createPseudoContentHandler({\n vp,\n normColor,\n measureFontMetrics: _measureFontMetrics,\n textNeedsRaster,\n resolveCounterValue,\n isCustomCounterStyle\n });\n const { captureInputValue } = createInputValueHandler({ vp, normColor, measureFontMetrics: _measureFontMetrics });\n const { captureTextSegments } = createTextSegmentsHandler({ vp, measureFontMetrics: _measureFontMetrics, needsRaster });\n const { injectPseudoSegments } = createPseudoInjectHandler();\n const capture = (el) => {\n const cs = window.getComputedStyle(el);\n return wrapWithFrozenTransform(el, cs, captureInner);\n };\n const captureInner = (el, cs, frozenTransform, frozenTransformOrigin) => {\n const rect = el.getBoundingClientRect();\n const outsideViewport = rect.right < vp.x || rect.bottom < vp.y || rect.left > vp.x + vp.width || rect.top > vp.y + vp.height;\n if (outsideViewport && !_fixedAncestors.has(el) && !_transformInfluenced.has(el)) return null;\n const _earlyTag = el.tagName.toLowerCase();\n const bordersOnlyCell = (_earlyTag === \"td\" || _earlyTag === \"th\") && (cs.visibility === \"hidden\" || cs.visibility === \"collapse\") && cs.borderCollapse === \"collapse\";\n if (cs.display === \"none\") return null;\n if ((cs.visibility === \"hidden\" || cs.visibility === \"collapse\") && !bordersOnlyCell) return null;\n const _contentVisHidden = cs.contentVisibility === \"hidden\";\n const _clip = cs.clip || \"\";\n if (_clip !== \"auto\" && _clip !== \"\" && _clip !== \"normal\") {\n const _cm = _clip.match(/rect\\(\\s*([^,\\s]+)[ ,]+([^,\\s]+)[ ,]+([^,\\s]+)[ ,]+([^)\\s]+)\\s*\\)/);\n if (_cm != null && parseFloat(_cm[1]) === 0 && parseFloat(_cm[2]) === 0 && parseFloat(_cm[3]) === 0 && parseFloat(_cm[4]) === 0) {\n return null;\n }\n }\n const _cp = cs.clipPath || \"\";\n if (_cp.indexOf(\"inset(\") === 0) {\n const _ipm = _cp.match(/inset\\(\\s*([0-9.]+)\\s*%/);\n if (_ipm != null && parseFloat(_ipm[1]) >= 50) return null;\n }\n if (rect.width <= 1 && rect.height <= 1 && (cs.overflow === \"hidden\" || cs.overflowX === \"hidden\" || cs.overflowY === \"hidden\") && (cs.position === \"absolute\" || cs.position === \"fixed\")) {\n return null;\n }\n const zeroSized = rect.width === 0 || rect.height === 0;\n const _hasAnim = el.dataset != null && el.dataset.domotionAnim != null && el.dataset.domotionAnim !== \"\";\n if (zeroSized && el.children.length === 0 && !_hasAnim) return null;\n const tag = el.tagName.toLowerCase();\n const sel2 = shortSelector(el);\n if (cs.transform && cs.transform.startsWith(\"matrix3d\")) {\n warn(sel2, \"transform-3d\", \"matrix3d/translate3d/rotate3d/perspective downgraded to 2D submatrix; z component + perspective dropped (SK-1135)\");\n }\n if (cs.backdropFilter && cs.backdropFilter !== \"none\") {\n warn(sel2, \"backdrop-filter\", \"captured but not emitted \\u2014 no SVG equivalent\");\n }\n if (cs.position === \"fixed\" || cs.position === \"sticky\") {\n warn(sel2, \"position:\" + cs.position, \"rendered as a static snapshot at t=0; scroll-following behavior is not animated\");\n }\n discoverMasks(el, cs, sel2);\n discoverClipPaths(el, cs, sel2);\n if (cs.borderImageSource && cs.borderImageSource !== \"none\") {\n warn(sel2, \"border-image\", \"9-slice composition pending (SK-466); border-image-source ignored\");\n }\n if (tag === \"iframe\" || tag === \"canvas\" || tag === \"video\" || tag === \"object\" || tag === \"embed\") {\n warn(sel2, \"<\" + tag + \">\", \"element type is not rendered by domotion\");\n }\n if ((cs.overflowX === \"auto\" || cs.overflowX === \"scroll\" || cs.overflowY === \"auto\" || cs.overflowY === \"scroll\") && (el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1)) {\n warn(sel2, \"scrollbar\", \"native scrollbar chrome not emulated yet (SK-468); content is clipped but no scroll indicator\");\n }\n if (cs.textAlign === \"justify\") {\n warn(sel2, \"text-align:justify\", \"path-mode renderer does not space-stretch justified text\");\n }\n let text = \"\";\n let imageSrc = void 0;\n let svgContent = void 0;\n let textTop = 0;\n let textLeft = 0;\n let textHeight = 0;\n let textWidth = 0;\n let fontAscent = 0;\n let fontDescent = 0;\n let inputXOffsets;\n let placeholderColor;\n let placeholderFontStyle;\n let placeholderFontWeight;\n const textSegments = [];\n const _pcResult = _contentVisHidden ? { pseudoSegments: [], pseudoBoxes: [] } : capturePseudoContent(el, cs, rect, _counterSnapshot);\n const pseudoSegments = _pcResult.pseudoSegments;\n const pseudoBoxes = _pcResult.pseudoBoxes;\n const textIsHiddenFallback = tag === \"meter\" || tag === \"progress\" || tag === \"datalist\" || tag === \"option\" || tag === \"optgroup\";\n if (tag !== \"svg\" && tag !== \"img\" && !textIsHiddenFallback && !_contentVisHidden) {\n const _iv = captureInputValue(el, cs, tag, rect);\n var isPlaceholderCapture = false;\n if (_iv.applied) {\n text = _iv.text;\n textLeft = _iv.textLeft;\n textTop = _iv.textTop;\n textHeight = _iv.textHeight;\n textWidth = _iv.textWidth;\n fontAscent = _iv.fontAscent;\n fontDescent = _iv.fontDescent;\n inputXOffsets = _iv.inputXOffsets;\n isPlaceholderCapture = _iv.isPlaceholderCapture;\n placeholderColor = _iv.placeholderColor;\n placeholderFontStyle = _iv.placeholderFontStyle;\n placeholderFontWeight = _iv.placeholderFontWeight;\n } else {\n const _ts = captureTextSegments(el, cs);\n text = _ts.text;\n for (const seg of _ts.textSegments) textSegments.push(seg);\n if (_ts.textLeft != null) {\n textLeft = _ts.textLeft;\n textTop = _ts.textTop;\n textWidth = _ts.textWidth;\n textHeight = _ts.textHeight;\n fontAscent = _ts.fontAscent;\n fontDescent = _ts.fontDescent;\n }\n }\n }\n const _pi = injectPseudoSegments(el, pseudoSegments, textSegments, {\n text,\n textLeft,\n textTop,\n textWidth,\n textHeight,\n fontAscent\n });\n const pseudoImages = _pi.pseudoImages;\n text = _pi.text;\n textLeft = _pi.textLeft;\n textTop = _pi.textTop;\n textWidth = _pi.textWidth;\n textHeight = _pi.textHeight;\n fontAscent = _pi.fontAscent;\n let textImageUri = void 0;\n const textImageScale = 2;\n if (tag === \"img\") {\n imageSrc = el.currentSrc || el.src;\n if (el.naturalWidth > 0 && el.naturalHeight > 0) {\n var imageIntrinsic = { w: el.naturalWidth, h: el.naturalHeight };\n }\n var imageBroken = el.complete && el.naturalWidth === 0;\n var imageAlt = el.alt || \"\";\n } else if (tag === \"input\" && el.type === \"image\") {\n imageSrc = el.src;\n }\n const _listsCounters = captureListsCounters(el, cs, tag);\n if (tag === \"svg\") {\n let _isUnresolvedCssExpr2 = function(v) {\n return v != null && _unresolvedCssExprRe.test(v);\n }, _hasConcreteAttr2 = function(node, attr) {\n return node.hasAttribute(attr) && !_isUnresolvedCssExpr2(node.getAttribute(attr));\n };\n var _isUnresolvedCssExpr = _isUnresolvedCssExpr2, _hasConcreteAttr = _hasConcreteAttr2;\n const svgFill = cs.fill;\n const svgStroke = cs.stroke;\n const svgStrokeWidth = cs.strokeWidth;\n const svgFontFamily = cs.fontFamily;\n const clone = el.cloneNode(true);\n const _unresolvedCssExprRe = /\\b(?:var|calc|env|attr)\\s*\\(/;\n if (svgFill && svgFill !== \"\" && !_hasConcreteAttr2(el, \"fill\")) clone.setAttribute(\"fill\", svgFill);\n if (svgStroke && svgStroke !== \"\" && svgStroke !== \"none\" && !_hasConcreteAttr2(el, \"stroke\")) clone.setAttribute(\"stroke\", svgStroke);\n if (svgStrokeWidth && svgStrokeWidth !== \"\" && !_hasConcreteAttr2(el, \"stroke-width\")) clone.setAttribute(\"stroke-width\", svgStrokeWidth);\n if (svgFontFamily && svgFontFamily !== \"\" && !el.hasAttribute(\"font-family\")) {\n clone.setAttribute(\"font-family\", svgFontFamily);\n }\n const _bakeSvgAttrs = [\"fill\", \"stroke\", \"stroke-width\", \"stroke-dasharray\", \"stroke-linecap\", \"stroke-linejoin\", \"stroke-opacity\", \"fill-opacity\", \"opacity\"];\n const _bakeSvgGeomAttrs = [\"cx\", \"cy\", \"r\", \"rx\", \"ry\", \"x\", \"y\", \"width\", \"height\", \"d\"];\n const _walkBake = (origNode, cloneNode) => {\n if (origNode.nodeType !== 1) return;\n const ns = origNode.namespaceURI;\n if (ns === \"http://www.w3.org/2000/svg\" && origNode !== el) {\n const ocs = window.getComputedStyle(origNode);\n const _usesCurrentColor = (camel) => {\n const baseVal = ocs[camel];\n if (baseVal !== ocs.color) return false;\n const savedColor = origNode.style.color;\n origNode.style.color = \"rgb(1, 2, 3)\";\n const probeCs = window.getComputedStyle(origNode);\n const matches = probeCs[camel] === probeCs.color;\n origNode.style.color = savedColor;\n return matches;\n };\n for (const attr of _bakeSvgAttrs) {\n const camel = attr.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n const val = ocs[camel];\n if (val != null && val !== \"\" && !_hasConcreteAttr2(origNode, attr)) {\n const preserveCurrent = (attr === \"fill\" || attr === \"stroke\") && _usesCurrentColor(camel);\n cloneNode.setAttribute(attr, preserveCurrent ? \"currentColor\" : val);\n }\n }\n for (const gattr of _bakeSvgGeomAttrs) {\n if (_hasConcreteAttr2(origNode, gattr)) continue;\n let gval = ocs.getPropertyValue(gattr);\n if (gval == null) continue;\n gval = gval.trim();\n if (gval === \"\" || gval === \"auto\" || gval === \"none\" || gval === \"normal\") continue;\n if (gattr === \"d\") {\n const m = /^path\\(\\s*(?:\"([^\"]*)\"|'([^']*)')\\s*\\)$/.exec(gval);\n if (m) gval = m[1] != null ? m[1] : m[2];\n else continue;\n } else if (/^-?\\d+(?:\\.\\d+)?px$/.test(gval)) {\n gval = gval.slice(0, -2);\n }\n cloneNode.setAttribute(gattr, gval);\n }\n if (origNode.tagName && origNode.tagName.toLowerCase() === \"mask\") {\n const mt = ocs.maskType || ocs.getPropertyValue(\"mask-type\");\n if (mt === \"alpha\" || mt === \"luminance\") {\n if (!origNode.hasAttribute(\"mask-type\") || origNode.getAttribute(\"mask-type\") !== mt) {\n cloneNode.setAttribute(\"mask-type\", mt);\n }\n }\n }\n var transformVal = ocs.transform;\n var hasStaticTransformAttr = origNode.hasAttribute(\"transform\") && !_isUnresolvedCssExpr2(origNode.getAttribute(\"transform\"));\n if (!hasStaticTransformAttr && transformVal != null && transformVal !== \"\" && transformVal !== \"none\") {\n var transformOriginVal = ocs.transformOrigin || \"0 0\";\n var originParts = transformOriginVal.trim().split(/\\s+/);\n var ox = parseFloat(originParts[0] || \"0\") || 0;\n var oy = parseFloat(originParts[1] || \"0\") || 0;\n var transformBoxVal = ocs.transformBox || \"fill-box\";\n try {\n if (typeof origNode.getBBox === \"function\" && transformBoxVal !== \"view-box\") {\n var bbox = origNode.getBBox();\n ox += bbox.x;\n oy += bbox.y;\n if (transformBoxVal === \"stroke-box\") {\n var swPx = parseFloat(ocs.strokeWidth || \"0\") || 0;\n ox -= swPx / 2;\n oy -= swPx / 2;\n }\n }\n } catch (e) {\n }\n var composed;\n if (ox === 0 && oy === 0) {\n composed = transformVal;\n } else {\n composed = \"translate(\" + ox + \",\" + oy + \") \" + transformVal + \" translate(\" + -ox + \",\" + -oy + \")\";\n }\n cloneNode.setAttribute(\"transform\", composed);\n }\n }\n const oChildren = origNode.children;\n const cChildren = cloneNode.children;\n const n = Math.min(oChildren.length, cChildren.length);\n for (let i = 0; i < n; i++) _walkBake(oChildren[i], cChildren[i]);\n };\n _walkBake(el, clone);\n const _svgNS = \"http://www.w3.org/2000/svg\";\n const _xlinkNS = \"http://www.w3.org/1999/xlink\";\n const _resolveUseRefs = (root2, depth) => {\n if (depth > 5) return;\n var uses = root2.querySelectorAll ? root2.querySelectorAll(\"use\") : [];\n for (var ui = 0; ui < uses.length; ui++) {\n var useEl = uses[ui];\n var href = useEl.getAttribute(\"href\");\n if (href == null || href === \"\") href = useEl.getAttributeNS(_xlinkNS, \"href\") || \"\";\n if (href.charAt(0) !== \"#\") continue;\n var targetId = href.slice(1);\n var target = document.getElementById(targetId);\n if (target == null) continue;\n if (target.namespaceURI !== _svgNS) continue;\n if (typeof target.getAnimations === \"function\") {\n try {\n var anims = target.getAnimations({ subtree: true });\n if (anims != null && anims.length > 0) {\n warn(sel2, \"inline-svg\", '<use href=\"#' + targetId + '\"> resolved to a CSS-animated subtree; the inlined SVG carries the t=0 computed paint state (no animation in the output)');\n }\n } catch (e) {\n }\n }\n var ux = parseFloat(useEl.getAttribute(\"x\") || \"0\") || 0;\n var uy = parseFloat(useEl.getAttribute(\"y\") || \"0\") || 0;\n var uw = useEl.getAttribute(\"width\");\n var uh = useEl.getAttribute(\"height\");\n var targetTag = target.tagName.toLowerCase();\n var replacement;\n if (targetTag === \"symbol\") {\n var vb = target.getAttribute(\"viewBox\") || \"\";\n var par = target.getAttribute(\"preserveAspectRatio\") || \"\";\n var innerSvg = document.createElementNS(_svgNS, \"svg\");\n if (ux !== 0) innerSvg.setAttribute(\"x\", String(ux));\n if (uy !== 0) innerSvg.setAttribute(\"y\", String(uy));\n if (uw != null) innerSvg.setAttribute(\"width\", uw);\n if (uh != null) innerSvg.setAttribute(\"height\", uh);\n if (vb !== \"\") innerSvg.setAttribute(\"viewBox\", vb);\n if (par !== \"\") innerSvg.setAttribute(\"preserveAspectRatio\", par);\n for (var ci = 0; ci < target.children.length; ci++) {\n var clonedChild = target.children[ci].cloneNode(true);\n innerSvg.appendChild(clonedChild);\n _walkBake(target.children[ci], clonedChild);\n }\n var useTransformAttrSym = useEl.getAttribute(\"transform\") || \"\";\n if (useTransformAttrSym !== \"\") {\n replacement = document.createElementNS(_svgNS, \"g\");\n replacement.setAttribute(\"transform\", useTransformAttrSym);\n replacement.appendChild(innerSvg);\n } else {\n replacement = innerSvg;\n }\n } else {\n replacement = document.createElementNS(_svgNS, \"g\");\n var useTransformAttr = useEl.getAttribute(\"transform\") || \"\";\n var translatePart = ux !== 0 || uy !== 0 ? \"translate(\" + ux + \",\" + uy + \")\" : \"\";\n var composedTransform = (useTransformAttr + \" \" + translatePart).trim();\n if (composedTransform !== \"\") {\n replacement.setAttribute(\"transform\", composedTransform);\n }\n var clonedTarget = target.cloneNode(true);\n if (clonedTarget.removeAttribute) clonedTarget.removeAttribute(\"id\");\n replacement.appendChild(clonedTarget);\n _walkBake(target, clonedTarget);\n if (clonedTarget.tagName && clonedTarget.tagName.toLowerCase() === \"svg\" && clonedTarget.removeAttribute) {\n if (!_hasConcreteAttr2(target, \"width\") && /^0(?:\\.0+)?$/.test(clonedTarget.getAttribute(\"width\") || \"\")) {\n clonedTarget.removeAttribute(\"width\");\n }\n if (!_hasConcreteAttr2(target, \"height\") && /^0(?:\\.0+)?$/.test(clonedTarget.getAttribute(\"height\") || \"\")) {\n clonedTarget.removeAttribute(\"height\");\n }\n }\n }\n var _useAttrs = [\"fill\", \"stroke\", \"stroke-width\", \"opacity\", \"class\", \"style\"];\n for (var ai = 0; ai < _useAttrs.length; ai++) {\n var av = useEl.getAttribute(_useAttrs[ai]);\n if (av != null && av !== \"\") replacement.setAttribute(_useAttrs[ai], av);\n }\n useEl.parentNode.replaceChild(replacement, useEl);\n _resolveUseRefs(replacement, depth + 1);\n }\n };\n _resolveUseRefs(clone, 0);\n var _hostColor = cs.color;\n var _substCurrentColor = (node) => {\n if (node.nodeType !== 1) return;\n var fa = node.getAttribute && node.getAttribute(\"fill\");\n if (fa != null && /^currentcolor$/i.test(fa)) node.setAttribute(\"fill\", _hostColor);\n var sa = node.getAttribute && node.getAttribute(\"stroke\");\n if (sa != null && /^currentcolor$/i.test(sa)) node.setAttribute(\"stroke\", _hostColor);\n for (var ci = 0; ci < node.children.length; ci++) _substCurrentColor(node.children[ci]);\n };\n _substCurrentColor(clone);\n svgContent = clone.outerHTML;\n }\n const children = [];\n if (_contentVisHidden) {\n } else\n for (const child of el.children) {\n if (tag === \"details\" && !el.open && child.tagName.toLowerCase() !== \"summary\") continue;\n if (tag === \"select\" && (child.tagName.toLowerCase() === \"option\" || child.tagName.toLowerCase() === \"optgroup\")) continue;\n const c = capture(child);\n if (c) children.push(c);\n }\n const _animId = el.dataset != null ? el.dataset.domotionAnim : void 0;\n let fieldsetLegendNotch;\n let fsX = rect.left - vp.x;\n let fsY = rect.top - vp.y;\n let fsW = rect.width;\n let fsH = rect.height;\n if (tag === \"fieldset\") {\n for (let i = 0; i < el.children.length; i++) {\n const ch = el.children[i];\n if (ch.tagName.toLowerCase() !== \"legend\") continue;\n const lr = ch.getBoundingClientRect();\n if (lr.height > 0 && lr.width > 0 && Math.abs(lr.top - rect.top) < 2) {\n const inset = lr.height / 2;\n fsY = rect.top - vp.y + inset;\n fsH = rect.height - inset;\n fieldsetLegendNotch = { x: lr.left - vp.x, y: lr.top - vp.y, w: lr.width, h: lr.height };\n }\n break;\n }\n }\n const _captured = {\n tag,\n text,\n x: fsX,\n y: fsY,\n width: fsW,\n height: fsH,\n fieldsetLegendNotch,\n animId: _animId,\n styles: {\n // Border + background + outline + box-shadow fields — see\n // walker/borders-backgrounds.ts. Includes the\n // backgroundColor placeholder-shown fallback (DM-283), %-resolved\n // corner radii (SK-1093), per-side color-input border tint\n // workaround (DM-434), frosted-bg fallback (DM-476), per-layer\n // background-image intrinsic dims (DM-308), and border-image\n // intrinsic dims.\n ...captureBordersBackgrounds(el, cs, tag, rect, isPlaceholderCapture),\n overflowX: cs.overflowX,\n overflowY: cs.overflowY,\n // DM-761: `overflow-clip-margin` extends the overflow clip outward\n // from a reference box (content / padding / border) by a length.\n // Only meaningful for `overflow: clip`; `hidden` ignores it. Captured\n // as the resolved string (\"20px\" / \"content-box 12px\") so the renderer\n // can parse the reference-box keyword + length together.\n overflowClipMargin: cs.overflowClipMargin || void 0,\n scrollbarGutter: cs.scrollbarGutter || \"auto\",\n scrollWidth: el.scrollWidth,\n scrollHeight: el.scrollHeight,\n clientWidth: el.clientWidth,\n clientHeight: el.clientHeight,\n scrollTop: el.scrollTop,\n scrollLeft: el.scrollLeft,\n objectFit: cs.objectFit,\n objectPosition: cs.objectPosition,\n filter: cs.filter,\n backdropFilter: cs.backdropFilter || cs.webkitBackdropFilter || \"\",\n mixBlendMode: cs.mixBlendMode,\n clipPath: cs.clipPath,\n mask: cs.mask || cs.webkitMask || \"\",\n maskImage: cs.maskImage || cs.webkitMaskImage || \"\",\n maskMode: cs.maskMode || \"match-source\",\n maskSize: cs.maskSize || cs.webkitMaskSize || \"auto\",\n maskPosition: cs.maskPosition || cs.webkitMaskPosition || \"0% 0%\",\n maskRepeat: cs.maskRepeat || cs.webkitMaskRepeat || \"repeat\",\n maskComposite: cs.maskComposite || cs.webkitMaskComposite || \"add\",\n maskClip: cs.maskClip || cs.webkitMaskClip || \"border-box\",\n // DM-758: `mask-border-source` / legacy `-webkit-mask-box-image`. Chrome\n // exposes only the legacy webkit name; modern `maskBorderSource`\n // returns undefined. Capture source + slice / width / outset so the\n // renderer can decide whether to route through the simplified\n // full-element mask path (only safe when width / outset both `0`).\n maskBorderSource: cs.webkitMaskBoxImageSource && cs.webkitMaskBoxImageSource !== \"none\" ? cs.webkitMaskBoxImageSource : void 0,\n maskBorderSlice: cs.webkitMaskBoxImageSlice || void 0,\n maskBorderWidth: cs.webkitMaskBoxImageWidth || void 0,\n maskBorderOutset: cs.webkitMaskBoxImageOutset || void 0,\n // DM-793: legacy `-webkit-mask-box-image-repeat` keyword (stretch /\n // repeat / round / space) per axis. Mirrors `border-image-repeat`.\n maskBorderRepeat: cs.webkitMaskBoxImageRepeat || void 0,\n // DM-793: intrinsic dimensions of the mask-border-source raster /\n // SVG asset. Same probe pattern as `borderImageIntrinsic*` — a\n // detached `<img>` resolves the URL against the document base and\n // reports `naturalWidth` / `naturalHeight` for raster sources and\n // the `<svg width/height>` attributes (or viewBox-derived size) for\n // SVG sources. Captured at capture time so the renderer can compute\n // 9-slice source rects without re-fetching the asset.\n maskBorderIntrinsicWidth: (function() {\n var _m = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.webkitMaskBoxImageSource || \"\");\n if (_m == null) return void 0;\n var _img = new Image();\n _img.src = _m[1];\n return _img.naturalWidth || void 0;\n })(),\n maskBorderIntrinsicHeight: (function() {\n var _m = /^url\\((?:\"|')?([^\"')]+)/.exec(cs.webkitMaskBoxImageSource || \"\");\n if (_m == null) return void 0;\n var _img = new Image();\n _img.src = _m[1];\n return _img.naturalHeight || void 0;\n })(),\n listStyleType: cs.listStyleType,\n listStyleImage: cs.listStyleImage,\n display: cs.display,\n listStylePosition: cs.listStylePosition,\n paddingTop: cs.paddingTop,\n paddingRight: cs.paddingRight,\n paddingBottom: cs.paddingBottom,\n paddingLeft: cs.paddingLeft,\n zIndex: cs.zIndex,\n position: cs.position,\n float: cs.float,\n order: cs.order,\n flexDirection: cs.flexDirection,\n emptyCellsHidden: (tag === \"td\" || tag === \"th\") && cs.emptyCells === \"hide\" && (el.textContent || \"\").trim() === \"\" && el.children.length === 0,\n // Form-control fields — input / progress / meter / select / details\n // + ::-webkit-* pseudos for slider track/thumb, color swatch, number\n // spin button, search cancel, file-selector button. See\n // walker/form-controls.ts. Input value-capture-as-text and color-\n // input border tinting deliberately stay inline (entangled with\n // text-shaping and border-color emission respectively).\n ...captureFormControls(el, cs, tag),\n textShadow: cs.textShadow,\n ...threadFrozenTransform(cs, frozenTransform, frozenTransformOrigin),\n // CSS Transforms 2 §4: `transform-style` != `flat` (i.e. `preserve-3d`)\n // creates a stacking context. Captured so the renderer's SC detection\n // sees it; otherwise z-index:-1 descendants hoist past their intended\n // SC and end up behind the wrong background (DM-589).\n transformStyle: cs.transformStyle,\n willChange: cs.willChange,\n contain: cs.contain,\n isolation: cs.isolation,\n writingMode: cs.writingMode,\n textOrientation: cs.textOrientation,\n // CSS resize: 'none' / 'both' / 'vertical' / 'horizontal' / 'block' /\n // 'inline'. When non-none on a <textarea> Chrome paints a small\n // diagonal-line resize handle in the bottom-right corner. (DM-339)\n resize: cs.resize,\n textOverflow: cs.textOverflow,\n whiteSpace: cs.whiteSpace,\n color: normColor(cs.color),\n // DM-587: live-rect capture records text bboxes at scaled (live)\n // viewport coords, but `cs.fontSize` and `canvas.measureText` are in\n // CSS px (unscaled). Multiply by the cumulative ancestor scale so\n // the renderer's text-Y math (baseline = top + ascent) lands the\n // baseline inside the scaled bbox — without this, glyphs inside e.g.\n // a `transform: scale(0.7)` container overflow their captured cell\n // and escape per-label `overflow: hidden` clip-paths. _cumulativeScale\n // is pre-computed in the pre-pass above. Defaults to 1 for elements\n // outside any scaled ancestor (the common case).\n fontSize: (function() {\n var _fs = parseFloat(cs.fontSize);\n if (!isFinite(_fs)) return cs.fontSize;\n var _s = _scaleMag(el);\n if (_s === 1) return cs.fontSize;\n return (_fs * _s).toFixed(4) + \"px\";\n })(),\n fontFamily: cs.fontFamily,\n fontWeight: cs.fontWeight,\n fontStyle: cs.fontStyle,\n opacity: cs.opacity,\n lineHeight: cs.lineHeight,\n letterSpacing: cs.letterSpacing,\n fontKerning: cs.fontKerning,\n fontStretch: cs.fontStretch,\n fontVariationSettings: cs.fontVariationSettings,\n fontFeatureSettings: cs.fontFeatureSettings,\n // CSS font-variant-caps. 'small-caps' / 'all-small-caps' route to\n // the OpenType smcp feature; renderer applies synthesized small-caps\n // when the active font lacks smcp (Helvetica, Times, etc.). DM-361.\n fontVariantCaps: cs.fontVariantCaps,\n direction: cs.direction,\n // Computed BCP-47 language tag from el.lang or nearest ancestor\n // [lang], falling back to document.documentElement.lang. Used by the\n // path renderer to route CJK Han fallback to the right PingFang\n // regional variant. (DM-394)\n lang: (function() {\n var n = el;\n while (n != null && n.nodeType === 1) {\n if (n.lang) return n.lang;\n n = n.parentElement;\n }\n return document.documentElement.lang || \"\";\n })(),\n textDecorationLine: cs.textDecorationLine,\n textDecorationColor: cs.textDecorationColor,\n textDecorationStyle: cs.textDecorationStyle,\n textDecorationThickness: cs.textDecorationThickness,\n textUnderlineOffset: cs.textUnderlineOffset,\n textDecorationSkipInk: cs.textDecorationSkipInk\n },\n children,\n imageSrc,\n imageIntrinsic,\n imageBroken,\n imageAlt,\n svgContent,\n pseudoImages,\n pseudoBoxes: pseudoBoxes.length > 0 ? pseudoBoxes : void 0,\n // SK-1115: ::marker pseudo styles plus list-marker intrinsic dims and\n // list-item index — see walker/lists-counters.ts.\n ..._listsCounters,\n textSegments: textSegments.length > 0 ? textSegments : void 0,\n textTop,\n textLeft,\n textHeight,\n textWidth,\n // DM-587: fontAscent + fontDescent come from `canvas.measureText` using\n // the unscaled `cs.fontSize`, so scale them to match the also-scaled\n // captured fontSize. Otherwise the renderer's baseline math reads\n // unscaled ascent values, and glyphs sit too far below their captured\n // bbox top inside a `transform: scale(<1)` container.\n fontAscent: fontAscent != null ? fontAscent * _scaleMag(el) : fontAscent,\n fontDescent: fontDescent != null ? fontDescent * _scaleMag(el) : fontDescent,\n inputXOffsets,\n textImageUri,\n textImageScale,\n // Placeholder metadata (SK-1097 / SK-1100 / SK-1099): captured in\n // walker/input-value.ts when the host is a placeholder-shown input\n // or textarea. Undefined elsewhere.\n isPlaceholderText: isPlaceholderCapture || void 0,\n placeholderColor,\n placeholderFontStyle,\n placeholderFontWeight,\n // SK-1108 / SK-1128: textarea soft-wrap + writing-mode != horizontal-tb\n // content-box raster rect — see walker/text-segments.ts.\n elementRaster: computeElementRaster(el, cs, tag, rect, vp),\n // DM-680: per-axis cumulative ancestor scale, exposed ONLY when\n // anisotropic (sx ≠ sy within a small epsilon). The geometric mean is\n // already folded into fontSize / fontAscent / fontDescent above, so\n // the renderer's text-emission path only needs to apply a per-axis\n // correction transform when the two axes diverge. Emitting these on\n // every transformed element would add noise to the captured tree.\n ...(function() {\n const _s = _scaleXY(el);\n const _sx = _s[0], _sy = _s[1];\n if (Math.abs(_sx - _sy) > 1e-4) return { cumScaleX: _sx, cumScaleY: _sy };\n return {};\n })()\n };\n {\n var _bgC = _captured.styles.backgroundColor;\n var _hasBg = _bgC != null && _bgC !== \"\" && _bgC !== \"transparent\" && _bgC !== \"rgba(0, 0, 0, 0)\";\n var _hasBgImage = _captured.styles.backgroundImage != null && _captured.styles.backgroundImage !== \"\" && _captured.styles.backgroundImage !== \"none\";\n var _btw = parseFloat(_captured.styles.borderTopWidth || \"0\") || 0;\n var _brw = parseFloat(_captured.styles.borderRightWidth || \"0\") || 0;\n var _bbw = parseFloat(_captured.styles.borderBottomWidth || \"0\") || 0;\n var _blw = parseFloat(_captured.styles.borderLeftWidth || \"0\") || 0;\n var _hasBorder = _btw > 0 || _brw > 0 || _bbw > 0 || _blw > 0;\n var _hasPaint = _hasBg || _hasBgImage || _hasBorder;\n var _isInline = cs.display === \"inline\";\n var _isBlockLevel = !_isInline && (cs.display === \"block\" || cs.display === \"list-item\" || cs.display === \"flex\" || cs.display === \"grid\" || cs.display === \"flow-root\" || cs.display === \"inline-block\" || cs.display === \"inline-flex\" || cs.display === \"inline-grid\");\n var _inMultiColumn = false;\n if (_isBlockLevel && _hasPaint) {\n var _a = el.parentElement;\n while (_a != null) {\n var _ac = window.getComputedStyle(_a);\n var _cc = parseInt(_ac.columnCount, 10);\n var _cw = _ac.columnWidth;\n if (Number.isFinite(_cc) && _cc > 1 || _cw != null && _cw !== \"auto\" && _cw !== \"\" && _cw !== \"normal\") {\n _inMultiColumn = true;\n break;\n }\n if (_a === document.body) break;\n _a = _a.parentElement;\n }\n }\n if (_hasPaint && (_isInline || _inMultiColumn)) {\n var _cr = el.getClientRects();\n if (_cr != null && _cr.length > 1) {\n var _frags = [];\n for (var _ci = 0; _ci < _cr.length; _ci++) {\n var _f = _cr[_ci];\n if (_f.width <= 0 || _f.height <= 0) continue;\n _frags.push({\n x: _f.left - vp.x,\n y: _f.top - vp.y,\n width: _f.width,\n height: _f.height\n });\n }\n if (_frags.length > 1) {\n _captured.inlineFragments = _frags;\n _captured.fragmentAxis = _isInline ? \"inline\" : \"block\";\n }\n }\n }\n }\n if (bordersOnlyCell) {\n _captured.text = \"\";\n _captured.children = [];\n _captured.styles.backgroundColor = \"rgba(0, 0, 0, 0)\";\n _captured.styles.backgroundImage = void 0;\n _captured.textSegments = void 0;\n _captured.imageSrc = void 0;\n _captured.svgContent = void 0;\n _captured.pseudoImages = void 0;\n _captured.elementRaster = void 0;\n }\n handleReplacedElement(el, cs, tag, rect, _captured, bordersOnlyCell);\n return _captured;\n };\n const root = document.querySelector(sel);\n if (!root) return { tree: [], warnings: [] };\n const _fixedAncestors = /* @__PURE__ */ new Set();\n const _allEls = root.getElementsByTagName(\"*\");\n for (let _i = 0; _i < _allEls.length; _i++) {\n const _el = _allEls[_i];\n const _pos = getComputedStyle(_el).position;\n if (_pos !== \"fixed\" && _pos !== \"sticky\") continue;\n const _r = _el.getBoundingClientRect();\n const _outside = _r.right < vp.x || _r.bottom < vp.y || _r.left > vp.x + vp.width || _r.top > vp.y + vp.height;\n if (_outside) continue;\n let _cur = _el.parentElement;\n while (_cur != null && _cur !== root.parentElement) {\n if (_fixedAncestors.has(_cur)) break;\n _fixedAncestors.add(_cur);\n _cur = _cur.parentElement;\n }\n }\n const _transformInfluenced = /* @__PURE__ */ new Set();\n for (let _ti = 0; _ti < _allEls.length; _ti++) {\n const _tel = _allEls[_ti];\n const _tt = getComputedStyle(_tel).transform;\n if (_tt === \"none\" || _tt === \"\") continue;\n _transformInfluenced.add(_tel);\n const _tdescs = _tel.getElementsByTagName(\"*\");\n for (let _tj = 0; _tj < _tdescs.length; _tj++) {\n _transformInfluenced.add(_tdescs[_tj]);\n }\n }\n const _cumulativeScale = /* @__PURE__ */ new Map();\n const _computeOwnScale = (_tt) => {\n if (_tt == null || _tt === \"none\" || _tt === \"\") return [1, 1];\n const _m2 = /^matrix\\(\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)\\s*,\\s*([-\\d.eE+]+)/.exec(_tt);\n let _sa = 1, _sd = 1;\n if (_m2 != null) {\n _sa = parseFloat(_m2[1]);\n _sd = parseFloat(_m2[4]);\n } else {\n const _m3 = /^matrix3d\\(([^)]+)\\)/.exec(_tt);\n if (_m3 != null) {\n const _parts = _m3[1].split(\",\");\n _sa = parseFloat(_parts[0]);\n _sd = parseFloat(_parts[5]);\n }\n }\n if (!isFinite(_sa) || !isFinite(_sd)) return [1, 1];\n const _sx = Math.abs(_sa) > 0 ? Math.abs(_sa) : 1;\n const _sy = Math.abs(_sd) > 0 ? Math.abs(_sd) : 1;\n return [_sx, _sy];\n };\n for (let _si = 0; _si < _allEls.length; _si++) {\n const _el = _allEls[_si];\n let _cumX = 1, _cumY = 1;\n const _pe = _el.parentElement;\n if (_pe != null && _cumulativeScale.has(_pe)) {\n const _p = _cumulativeScale.get(_pe);\n _cumX = _p[0];\n _cumY = _p[1];\n }\n const _ownCs = getComputedStyle(_el);\n const _ownT = _ownCs.transform;\n if (_ownT != null && _ownT !== \"none\" && _ownT !== \"\") {\n const _own = _computeOwnScale(_ownT);\n _cumX *= _own[0];\n _cumY *= _own[1];\n }\n const _ownZ = parseFloat(_ownCs.zoom);\n if (Number.isFinite(_ownZ) && _ownZ > 0 && _ownZ !== 1) {\n _cumX *= _ownZ;\n _cumY *= _ownZ;\n }\n if (_cumX !== 1 || _cumY !== 1) _cumulativeScale.set(_el, [_cumX, _cumY]);\n }\n const _scaleXY = (el) => _cumulativeScale.get(el) || [1, 1];\n const _scaleMag = (el) => {\n const s = _scaleXY(el);\n return Math.sqrt(s[0] * s[1]);\n };\n const _counterSnapshot = /* @__PURE__ */ new WeakMap();\n function _parseCounterDecl(declStr, defaultValue) {\n if (!declStr || declStr === \"none\") return [];\n const tokens = declStr.split(/\\s+/);\n const out = [];\n let i = 0;\n while (i < tokens.length) {\n const name = tokens[i++];\n if (!name) continue;\n let value = defaultValue;\n if (i < tokens.length && /^-?\\d+$/.test(tokens[i])) {\n value = parseInt(tokens[i++], 10);\n }\n out.push({ name, value });\n }\n return out;\n }\n const _activeScopes = [];\n function _findInnermost(name) {\n for (let i = _activeScopes.length - 1; i >= 0; i--) {\n if (_activeScopes[i].name === name) return _activeScopes[i];\n }\n return null;\n }\n function _counterPreWalk(el) {\n const cs = window.getComputedStyle(el);\n const owned = [];\n _parseCounterDecl(cs.counterReset, 0).forEach(({ name, value }) => {\n const scope = { name, value, owner: el };\n _activeScopes.push(scope);\n owned.push(scope);\n });\n _parseCounterDecl(cs.counterIncrement, 1).forEach(({ name, value }) => {\n const s = _findInnermost(name);\n if (s) s.value += value;\n else {\n const ns = { name, value, owner: el };\n _activeScopes.push(ns);\n owned.push(ns);\n }\n });\n _parseCounterDecl(cs.counterSet, 0).forEach(({ name, value }) => {\n const s = _findInnermost(name);\n if (s) s.value = value;\n else {\n const ns = { name, value, owner: el };\n _activeScopes.push(ns);\n owned.push(ns);\n }\n });\n _counterSnapshot.set(el, _activeScopes.map((s) => ({ name: s.name, value: s.value })));\n for (const child of el.children) _counterPreWalk(child);\n while (_activeScopes.length > 0 && owned.length > 0 && _activeScopes[_activeScopes.length - 1] === owned[owned.length - 1]) {\n _activeScopes.pop();\n owned.pop();\n }\n }\n _counterPreWalk(root);\n function _parseStringList(s) {\n const out = [];\n let i = 0;\n while (i < s.length) {\n while (i < s.length && /\\s/.test(s[i])) i++;\n if (i >= s.length) break;\n const q = s[i];\n if (q !== '\"' && q !== \"'\") {\n let j2 = i;\n while (j2 < s.length && !/\\s/.test(s[j2])) j2++;\n out.push(s.slice(i, j2));\n i = j2;\n continue;\n }\n let j = i + 1;\n let val = \"\";\n while (j < s.length && s[j] !== q) {\n if (s[j] === \"\\\\\" && j + 1 < s.length) {\n const hex = /^\\\\([0-9a-fA-F]{1,6})\\s?/.exec(s.slice(j));\n if (hex != null) {\n val += String.fromCodePoint(parseInt(hex[1], 16));\n j += hex[0].length;\n continue;\n }\n val += s[j + 1];\n j += 2;\n } else {\n val += s[j];\n j++;\n }\n }\n out.push(val);\n i = j + 1;\n }\n return out;\n }\n function _parseAdditiveSymbols(s) {\n const out = [];\n for (const tok of s.split(\",\")) {\n const m = /(-?\\d+)\\s+(.+)/.exec(tok.trim());\n if (m == null) continue;\n const weight = parseInt(m[1], 10);\n const sym = _parseStringList(m[2])[0] ?? \"\";\n out.push({ weight, sym });\n }\n out.sort((a, b) => b.weight - a.weight);\n return out;\n }\n function _walkRulesForCounterStyles(rules) {\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (rule.type === 11 || window.CSSCounterStyleRule != null && rule instanceof window.CSSCounterStyleRule) {\n const name = rule.name;\n if (!name) continue;\n let extendsName;\n let sys = rule.system || \"symbolic\";\n const extMatch = /^extends\\s+(\\S+)/.exec(sys);\n if (extMatch) {\n extendsName = extMatch[1];\n sys = \"extends\";\n } else {\n const sysMatch = /^(cyclic|numeric|alphabetic|symbolic|fixed|additive)\\b/.exec(sys);\n sys = sysMatch ? sysMatch[1] : \"symbolic\";\n }\n const symbols = rule.symbols ? _parseStringList(rule.symbols) : [];\n const additiveSymbols = rule.additiveSymbols ? _parseAdditiveSymbols(rule.additiveSymbols) : [];\n const prefix = rule.prefix ? _parseStringList(rule.prefix)[0] ?? \"\" : \"\";\n const suffix = rule.suffix ? _parseStringList(rule.suffix)[0] ?? \". \" : \". \";\n const negativeRaw = rule.negative;\n let negPrefix = \"-\";\n let negSuffix = \"\";\n if (negativeRaw) {\n const nlist = _parseStringList(negativeRaw);\n negPrefix = nlist[0] ?? \"-\";\n if (nlist.length > 1) negSuffix = nlist[1];\n }\n let padLen = 0;\n let padSym = \"\";\n if (rule.pad) {\n const pm = /^\\s*(\\d+)\\s+(.+)$/.exec(rule.pad);\n if (pm != null) {\n padLen = parseInt(pm[1], 10);\n padSym = _parseStringList(pm[2])[0] ?? \"\";\n }\n }\n let rangeLo = -Infinity;\n let rangeHi = Infinity;\n if (rule.range && rule.range !== \"auto\") {\n const rm = /(-?\\d+|infinite)\\s+(-?\\d+|infinite)/.exec(rule.range);\n if (rm != null) {\n rangeLo = rm[1] === \"infinite\" ? -Infinity : parseInt(rm[1], 10);\n rangeHi = rm[2] === \"infinite\" ? Infinity : parseInt(rm[2], 10);\n }\n }\n const fallback = rule.fallback || \"decimal\";\n _counterStyles[name] = { system: sys, symbols, additiveSymbols, prefix, suffix, negPrefix, negSuffix, padLen, padSym, rangeLo, rangeHi, fallback, extendsName };\n } else if (rule.cssRules) {\n _walkRulesForCounterStyles(rule.cssRules);\n }\n }\n }\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n _walkRulesForCounterStyles(sheet.cssRules);\n } catch (e) {\n }\n }\n const result = [];\n const rootCs = window.getComputedStyle(root);\n const rootHasBorder = (parseFloat(rootCs.borderTopWidth) || 0) > 0 || (parseFloat(rootCs.borderRightWidth) || 0) > 0 || (parseFloat(rootCs.borderBottomWidth) || 0) > 0 || (parseFloat(rootCs.borderLeftWidth) || 0) > 0;\n const rootBg = rootCs.backgroundColor;\n const rootHasBg = rootBg != null && rootBg !== \"rgba(0, 0, 0, 0)\" && rootBg !== \"transparent\";\n let rootHasDirectText = false;\n for (const node of root.childNodes) {\n if (node.nodeType === Node.TEXT_NODE && (node.textContent || \"\").trim() !== \"\") {\n rootHasDirectText = true;\n break;\n }\n }\n if (rootHasBorder || rootHasBg || rootHasDirectText) {\n const c = capture(root);\n if (c) result.push(c);\n } else {\n for (const child of root.children) {\n const c = capture(child);\n if (c) result.push(c);\n }\n }\n if (_maskDefs.size > 0 && result.length > 0) {\n result[0].maskDefs = Array.from(_maskDefs.values());\n }\n if (_clipPathDefs.size > 0 && result.length > 0) {\n result[0].clipPathDefs = Array.from(_clipPathDefs.values());\n }\n if (_maskRasters.size > 0 && result.length > 0) {\n var rasterArr = [];\n for (var entry of _maskRasters.values()) {\n if (entry != null) rasterArr.push(entry);\n }\n if (rasterArr.length > 0) result[0].maskRasters = rasterArr;\n }\n if (result.length > 0) {\n try {\n var _isDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n result[0].styles.rootColorScheme = _isDark ? \"dark\" : \"light\";\n result[0].styles.rootBgComputed = window.getComputedStyle(document.documentElement).backgroundColor;\n } catch (_e) {\n }\n }\n return { tree: result, warnings: _warnings };\n});\n})()\n";