"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var injectedScriptSource_exports = {};
__export(injectedScriptSource_exports, {
  source: () => source
});
module.exports = __toCommonJS(injectedScriptSource_exports);
const source = '\nvar __commonJS = obj => {\n  let required = false;\n  let result;\n  return function __require() {\n    if (!required) {\n      required = true;\n      let fn;\n      for (const name in obj) { fn = obj[name]; break; }\n      const module = { exports: {} };\n      fn(module.exports, module);\n      result = module.exports;\n    }\n    return result;\n  }\n};\nvar __export = (target, all) => {for (var name in all) target[name] = all[name];};\nvar __toESM = mod => ({ ...mod, \'default\': mod });\nvar __toCommonJS = mod => ({ ...mod, __esModule: true });\n\n\n// packages/injected/src/injectedScript.ts\nvar injectedScript_exports = {};\n__export(injectedScript_exports, {\n  InjectedScript: () => InjectedScript\n});\nmodule.exports = __toCommonJS(injectedScript_exports);\n\n// packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts\nfunction ariaNodesEqual(a, b) {\n  if (a.role !== b.role || a.name !== b.name)\n    return false;\n  if (!ariaPropsEqual(a, b) || hasPointerCursor(a) !== hasPointerCursor(b))\n    return false;\n  const aKeys = Object.keys(a.props);\n  const bKeys = Object.keys(b.props);\n  return aKeys.length === bKeys.length && aKeys.every((k) => a.props[k] === b.props[k]);\n}\nfunction hasPointerCursor(ariaNode) {\n  return ariaNode.box.cursor === "pointer";\n}\nfunction ariaPropsEqual(a, b) {\n  return a.active === b.active && a.checked === b.checked && a.disabled === b.disabled && a.expanded === b.expanded && a.selected === b.selected && a.level === b.level && a.pressed === b.pressed;\n}\nfunction parseAriaSnapshot(yaml, text, options = {}) {\n  var _a;\n  const lineCounter = new yaml.LineCounter();\n  const parseOptions = {\n    keepSourceTokens: true,\n    lineCounter,\n    ...options\n  };\n  const yamlDoc = yaml.parseDocument(text, parseOptions);\n  const errors = [];\n  const convertRange = (range) => {\n    return [lineCounter.linePos(range[0]), lineCounter.linePos(range[1])];\n  };\n  const addError = (error) => {\n    errors.push({\n      message: error.message,\n      range: [lineCounter.linePos(error.pos[0]), lineCounter.linePos(error.pos[1])]\n    });\n  };\n  const convertSeq = (container, seq) => {\n    for (const item of seq.items) {\n      const itemIsString = item instanceof yaml.Scalar && typeof item.value === "string";\n      if (itemIsString) {\n        const childNode = KeyParser.parse(item, parseOptions, errors);\n        if (childNode) {\n          container.children = container.children || [];\n          container.children.push(childNode);\n        }\n        continue;\n      }\n      const itemIsMap = item instanceof yaml.YAMLMap;\n      if (itemIsMap) {\n        convertMap(container, item);\n        continue;\n      }\n      errors.push({\n        message: "Sequence items should be strings or maps",\n        range: convertRange(item.range || seq.range)\n      });\n    }\n  };\n  const convertMap = (container, map) => {\n    var _a2;\n    for (const entry of map.items) {\n      container.children = container.children || [];\n      const keyIsString = entry.key instanceof yaml.Scalar && typeof entry.key.value === "string";\n      if (!keyIsString) {\n        errors.push({\n          message: "Only string keys are supported",\n          range: convertRange(entry.key.range || map.range)\n        });\n        continue;\n      }\n      const key = entry.key;\n      const value = entry.value;\n      if (key.value === "text") {\n        const valueIsString = value instanceof yaml.Scalar && typeof value.value === "string";\n        if (!valueIsString) {\n          errors.push({\n            message: "Text value should be a string",\n            range: convertRange(entry.value.range || map.range)\n          });\n          continue;\n        }\n        container.children.push({\n          kind: "text",\n          text: textValue(value.value)\n        });\n        continue;\n      }\n      if (key.value === "/children") {\n        const valueIsString = value instanceof yaml.Scalar && typeof value.value === "string";\n        if (!valueIsString || value.value !== "contain" && value.value !== "equal" && value.value !== "deep-equal") {\n          errors.push({\n            message: \'Strict value should be "contain", "equal" or "deep-equal"\',\n            range: convertRange(entry.value.range || map.range)\n          });\n          continue;\n        }\n        container.containerMode = value.value;\n        continue;\n      }\n      if (key.value.startsWith("/")) {\n        const valueIsString = value instanceof yaml.Scalar && typeof value.value === "string";\n        if (!valueIsString) {\n          errors.push({\n            message: "Property value should be a string",\n            range: convertRange(entry.value.range || map.range)\n          });\n          continue;\n        }\n        container.props = (_a2 = container.props) != null ? _a2 : {};\n        container.props[key.value.slice(1)] = textValue(value.value);\n        continue;\n      }\n      const childNode = KeyParser.parse(key, parseOptions, errors);\n      if (!childNode)\n        continue;\n      const valueIsScalar = value instanceof yaml.Scalar;\n      if (valueIsScalar) {\n        const type = typeof value.value;\n        if (type !== "string" && type !== "number" && type !== "boolean") {\n          errors.push({\n            message: "Node value should be a string or a sequence",\n            range: convertRange(entry.value.range || map.range)\n          });\n          continue;\n        }\n        container.children.push({\n          ...childNode,\n          children: [{\n            kind: "text",\n            text: textValue(String(value.value))\n          }]\n        });\n        continue;\n      }\n      const valueIsSequence = value instanceof yaml.YAMLSeq;\n      if (valueIsSequence) {\n        container.children.push(childNode);\n        convertSeq(childNode, value);\n        continue;\n      }\n      errors.push({\n        message: "Map values should be strings or sequences",\n        range: convertRange(entry.value.range || map.range)\n      });\n    }\n  };\n  const fragment = { kind: "role", role: "fragment" };\n  yamlDoc.errors.forEach(addError);\n  if (errors.length)\n    return { errors, fragment };\n  if (!(yamlDoc.contents instanceof yaml.YAMLSeq)) {\n    errors.push({\n      message: \'Aria snapshot must be a YAML sequence, elements starting with " -"\',\n      range: yamlDoc.contents ? convertRange(yamlDoc.contents.range) : [{ line: 0, col: 0 }, { line: 0, col: 0 }]\n    });\n  }\n  if (errors.length)\n    return { errors, fragment };\n  convertSeq(fragment, yamlDoc.contents);\n  if (errors.length)\n    return { errors, fragment: emptyFragment };\n  if (((_a = fragment.children) == null ? void 0 : _a.length) === 1 && (!fragment.containerMode || fragment.containerMode === "contain"))\n    return { fragment: fragment.children[0], errors: [] };\n  return { fragment, errors: [] };\n}\nvar emptyFragment = { kind: "role", role: "fragment" };\nfunction normalizeWhitespace(text) {\n  return text.replace(/[\\u200b\\u00ad]/g, "").replace(/[\\r\\n\\s\\t]+/g, " ").trim();\n}\nfunction textValue(value) {\n  return {\n    raw: value,\n    normalized: normalizeWhitespace(value)\n  };\n}\nvar KeyParser = class _KeyParser {\n  static parse(text, options, errors) {\n    try {\n      return new _KeyParser(text.value)._parse();\n    } catch (e) {\n      if (e instanceof ParserError) {\n        const message = options.prettyErrors === false ? e.message : e.message + ":\\n\\n" + text.value + "\\n" + " ".repeat(e.pos) + "^\\n";\n        errors.push({\n          message,\n          range: [options.lineCounter.linePos(text.range[0]), options.lineCounter.linePos(text.range[0] + e.pos)]\n        });\n        return null;\n      }\n      throw e;\n    }\n  }\n  constructor(input) {\n    this._input = input;\n    this._pos = 0;\n    this._length = input.length;\n  }\n  _peek() {\n    return this._input[this._pos] || "";\n  }\n  _next() {\n    if (this._pos < this._length)\n      return this._input[this._pos++];\n    return null;\n  }\n  _eof() {\n    return this._pos >= this._length;\n  }\n  _isWhitespace() {\n    return !this._eof() && /\\s/.test(this._peek());\n  }\n  _skipWhitespace() {\n    while (this._isWhitespace())\n      this._pos++;\n  }\n  _readIdentifier(type) {\n    if (this._eof())\n      this._throwError(`Unexpected end of input when expecting ${type}`);\n    const start = this._pos;\n    while (!this._eof() && /[a-zA-Z]/.test(this._peek()))\n      this._pos++;\n    return this._input.slice(start, this._pos);\n  }\n  _readString() {\n    let result = "";\n    let escaped = false;\n    while (!this._eof()) {\n      const ch = this._next();\n      if (escaped) {\n        result += ch;\n        escaped = false;\n      } else if (ch === "\\\\") {\n        escaped = true;\n      } else if (ch === \'"\') {\n        return result;\n      } else {\n        result += ch;\n      }\n    }\n    this._throwError("Unterminated string");\n  }\n  _throwError(message, offset = 0) {\n    throw new ParserError(message, offset || this._pos);\n  }\n  _readRegex() {\n    let result = "";\n    let escaped = false;\n    let insideClass = false;\n    while (!this._eof()) {\n      const ch = this._next();\n      if (escaped) {\n        result += ch;\n        escaped = false;\n      } else if (ch === "\\\\") {\n        escaped = true;\n        result += ch;\n      } else if (ch === "/" && !insideClass) {\n        return { pattern: result };\n      } else if (ch === "[") {\n        insideClass = true;\n        result += ch;\n      } else if (ch === "]" && insideClass) {\n        result += ch;\n        insideClass = false;\n      } else {\n        result += ch;\n      }\n    }\n    this._throwError("Unterminated regex");\n  }\n  _readStringOrRegex() {\n    const ch = this._peek();\n    if (ch === \'"\') {\n      this._next();\n      return normalizeWhitespace(this._readString());\n    }\n    if (ch === "/") {\n      this._next();\n      return this._readRegex();\n    }\n    return null;\n  }\n  _readAttributes(result) {\n    let errorPos = this._pos;\n    while (true) {\n      this._skipWhitespace();\n      if (this._peek() === "[") {\n        this._next();\n        this._skipWhitespace();\n        errorPos = this._pos;\n        const flagName = this._readIdentifier("attribute");\n        this._skipWhitespace();\n        let flagValue = "";\n        if (this._peek() === "=") {\n          this._next();\n          this._skipWhitespace();\n          errorPos = this._pos;\n          while (this._peek() !== "]" && !this._isWhitespace() && !this._eof())\n            flagValue += this._next();\n        }\n        this._skipWhitespace();\n        if (this._peek() !== "]")\n          this._throwError("Expected ]");\n        this._next();\n        this._applyAttribute(result, flagName, flagValue || "true", errorPos);\n      } else {\n        break;\n      }\n    }\n  }\n  _parse() {\n    this._skipWhitespace();\n    const role = this._readIdentifier("role");\n    this._skipWhitespace();\n    const name = this._readStringOrRegex() || "";\n    const result = { kind: "role", role, name };\n    this._readAttributes(result);\n    this._skipWhitespace();\n    if (!this._eof())\n      this._throwError("Unexpected input");\n    return result;\n  }\n  _applyAttribute(node, key, value, errorPos) {\n    if (key === "checked") {\n      this._assert(value === "true" || value === "false" || value === "mixed", \'Value of "checked" attribute must be a boolean or "mixed"\', errorPos);\n      node.checked = value === "true" ? true : value === "false" ? false : "mixed";\n      return;\n    }\n    if (key === "disabled") {\n      this._assert(value === "true" || value === "false", \'Value of "disabled" attribute must be a boolean\', errorPos);\n      node.disabled = value === "true";\n      return;\n    }\n    if (key === "expanded") {\n      this._assert(value === "true" || value === "false", \'Value of "expanded" attribute must be a boolean\', errorPos);\n      node.expanded = value === "true";\n      return;\n    }\n    if (key === "active") {\n      this._assert(value === "true" || value === "false", \'Value of "active" attribute must be a boolean\', errorPos);\n      node.active = value === "true";\n      return;\n    }\n    if (key === "level") {\n      this._assert(!isNaN(Number(value)), \'Value of "level" attribute must be a number\', errorPos);\n      node.level = Number(value);\n      return;\n    }\n    if (key === "pressed") {\n      this._assert(value === "true" || value === "false" || value === "mixed", \'Value of "pressed" attribute must be a boolean or "mixed"\', errorPos);\n      node.pressed = value === "true" ? true : value === "false" ? false : "mixed";\n      return;\n    }\n    if (key === "selected") {\n      this._assert(value === "true" || value === "false", \'Value of "selected" attribute must be a boolean\', errorPos);\n      node.selected = value === "true";\n      return;\n    }\n    this._assert(false, `Unsupported attribute [${key}]`, errorPos);\n  }\n  _assert(value, message, valuePos) {\n    if (!value)\n      this._throwError(message || "Assertion error", valuePos);\n  }\n};\nvar ParserError = class extends Error {\n  constructor(message, pos) {\n    super(message);\n    this.pos = pos;\n  }\n};\nfunction findNewNode(from, to) {\n  var _a, _b;\n  function fillMap(root, map, position) {\n    let size = 1;\n    let childPosition = position + size;\n    for (const child of root.children || []) {\n      if (typeof child === "string") {\n        size++;\n        childPosition++;\n      } else {\n        size += fillMap(child, map, childPosition);\n        childPosition += size;\n      }\n    }\n    if (!["none", "presentation", "fragment", "iframe", "generic"].includes(root.role) && root.name) {\n      let byRole = map.get(root.role);\n      if (!byRole) {\n        byRole = /* @__PURE__ */ new Map();\n        map.set(root.role, byRole);\n      }\n      const existing = byRole.get(root.name);\n      const sizeAndPosition = size * 100 - position;\n      if (!existing || existing.sizeAndPosition < sizeAndPosition)\n        byRole.set(root.name, { node: root, sizeAndPosition });\n    }\n    return size;\n  }\n  const fromMap = /* @__PURE__ */ new Map();\n  if (from)\n    fillMap(from, fromMap, 0);\n  const toMap = /* @__PURE__ */ new Map();\n  fillMap(to, toMap, 0);\n  const result = [];\n  for (const [role, byRole] of toMap) {\n    for (const [name, byName] of byRole) {\n      const inFrom = (_a = fromMap.get(role)) == null ? void 0 : _a.get(name);\n      if (!inFrom)\n        result.push(byName);\n    }\n  }\n  result.sort((a, b) => b.sizeAndPosition - a.sizeAndPosition);\n  return (_b = result[0]) == null ? void 0 : _b.node;\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts\nvar between = function(num, first, last) {\n  return num >= first && num <= last;\n};\nfunction digit(code) {\n  return between(code, 48, 57);\n}\nfunction hexdigit(code) {\n  return digit(code) || between(code, 65, 70) || between(code, 97, 102);\n}\nfunction uppercaseletter(code) {\n  return between(code, 65, 90);\n}\nfunction lowercaseletter(code) {\n  return between(code, 97, 122);\n}\nfunction letter(code) {\n  return uppercaseletter(code) || lowercaseletter(code);\n}\nfunction nonascii(code) {\n  return code >= 128;\n}\nfunction namestartchar(code) {\n  return letter(code) || nonascii(code) || code === 95;\n}\nfunction namechar(code) {\n  return namestartchar(code) || digit(code) || code === 45;\n}\nfunction nonprintable(code) {\n  return between(code, 0, 8) || code === 11 || between(code, 14, 31) || code === 127;\n}\nfunction newline(code) {\n  return code === 10;\n}\nfunction whitespace(code) {\n  return newline(code) || code === 9 || code === 32;\n}\nvar maximumallowedcodepoint = 1114111;\nvar InvalidCharacterError = class extends Error {\n  constructor(message) {\n    super(message);\n    this.name = "InvalidCharacterError";\n  }\n};\nfunction preprocess(str) {\n  const codepoints = [];\n  for (let i = 0; i < str.length; i++) {\n    let code = str.charCodeAt(i);\n    if (code === 13 && str.charCodeAt(i + 1) === 10) {\n      code = 10;\n      i++;\n    }\n    if (code === 13 || code === 12)\n      code = 10;\n    if (code === 0)\n      code = 65533;\n    if (between(code, 55296, 56319) && between(str.charCodeAt(i + 1), 56320, 57343)) {\n      const lead = code - 55296;\n      const trail = str.charCodeAt(i + 1) - 56320;\n      code = Math.pow(2, 16) + lead * Math.pow(2, 10) + trail;\n      i++;\n    }\n    codepoints.push(code);\n  }\n  return codepoints;\n}\nfunction stringFromCode(code) {\n  if (code <= 65535)\n    return String.fromCharCode(code);\n  code -= Math.pow(2, 16);\n  const lead = Math.floor(code / Math.pow(2, 10)) + 55296;\n  const trail = code % Math.pow(2, 10) + 56320;\n  return String.fromCharCode(lead) + String.fromCharCode(trail);\n}\nfunction tokenize(str1) {\n  const str = preprocess(str1);\n  let i = -1;\n  const tokens = [];\n  let code;\n  let line = 0;\n  let column = 0;\n  let lastLineLength = 0;\n  const incrLineno = function() {\n    line += 1;\n    lastLineLength = column;\n    column = 0;\n  };\n  const locStart = { line, column };\n  const codepoint = function(i2) {\n    if (i2 >= str.length)\n      return -1;\n    return str[i2];\n  };\n  const next = function(num) {\n    if (num === void 0)\n      num = 1;\n    if (num > 3)\n      throw "Spec Error: no more than three codepoints of lookahead.";\n    return codepoint(i + num);\n  };\n  const consume = function(num) {\n    if (num === void 0)\n      num = 1;\n    i += num;\n    code = codepoint(i);\n    if (newline(code))\n      incrLineno();\n    else\n      column += num;\n    return true;\n  };\n  const reconsume = function() {\n    i -= 1;\n    if (newline(code)) {\n      line -= 1;\n      column = lastLineLength;\n    } else {\n      column -= 1;\n    }\n    locStart.line = line;\n    locStart.column = column;\n    return true;\n  };\n  const eof = function(codepoint2) {\n    if (codepoint2 === void 0)\n      codepoint2 = code;\n    return codepoint2 === -1;\n  };\n  const donothing = function() {\n  };\n  const parseerror = function() {\n  };\n  const consumeAToken = function() {\n    consumeComments();\n    consume();\n    if (whitespace(code)) {\n      while (whitespace(next()))\n        consume();\n      return new WhitespaceToken();\n    } else if (code === 34) {\n      return consumeAStringToken();\n    } else if (code === 35) {\n      if (namechar(next()) || areAValidEscape(next(1), next(2))) {\n        const token = new HashToken("");\n        if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n          token.type = "id";\n        token.value = consumeAName();\n        return token;\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 36) {\n      if (next() === 61) {\n        consume();\n        return new SuffixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 39) {\n      return consumeAStringToken();\n    } else if (code === 40) {\n      return new OpenParenToken();\n    } else if (code === 41) {\n      return new CloseParenToken();\n    } else if (code === 42) {\n      if (next() === 61) {\n        consume();\n        return new SubstringMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 43) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 44) {\n      return new CommaToken();\n    } else if (code === 45) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else if (next(1) === 45 && next(2) === 62) {\n        consume(2);\n        return new CDCToken();\n      } else if (startsWithAnIdentifier()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 46) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 58) {\n      return new ColonToken();\n    } else if (code === 59) {\n      return new SemicolonToken();\n    } else if (code === 60) {\n      if (next(1) === 33 && next(2) === 45 && next(3) === 45) {\n        consume(3);\n        return new CDOToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 64) {\n      if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n        return new AtKeywordToken(consumeAName());\n      else\n        return new DelimToken(code);\n    } else if (code === 91) {\n      return new OpenSquareToken();\n    } else if (code === 92) {\n      if (startsWithAValidEscape()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        parseerror();\n        return new DelimToken(code);\n      }\n    } else if (code === 93) {\n      return new CloseSquareToken();\n    } else if (code === 94) {\n      if (next() === 61) {\n        consume();\n        return new PrefixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 123) {\n      return new OpenCurlyToken();\n    } else if (code === 124) {\n      if (next() === 61) {\n        consume();\n        return new DashMatchToken();\n      } else if (next() === 124) {\n        consume();\n        return new ColumnToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 125) {\n      return new CloseCurlyToken();\n    } else if (code === 126) {\n      if (next() === 61) {\n        consume();\n        return new IncludeMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (digit(code)) {\n      reconsume();\n      return consumeANumericToken();\n    } else if (namestartchar(code)) {\n      reconsume();\n      return consumeAnIdentlikeToken();\n    } else if (eof()) {\n      return new EOFToken();\n    } else {\n      return new DelimToken(code);\n    }\n  };\n  const consumeComments = function() {\n    while (next(1) === 47 && next(2) === 42) {\n      consume(2);\n      while (true) {\n        consume();\n        if (code === 42 && next() === 47) {\n          consume();\n          break;\n        } else if (eof()) {\n          parseerror();\n          return;\n        }\n      }\n    }\n  };\n  const consumeANumericToken = function() {\n    const num = consumeANumber();\n    if (wouldStartAnIdentifier(next(1), next(2), next(3))) {\n      const token = new DimensionToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      token.unit = consumeAName();\n      return token;\n    } else if (next() === 37) {\n      consume();\n      const token = new PercentageToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      return token;\n    } else {\n      const token = new NumberToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      return token;\n    }\n  };\n  const consumeAnIdentlikeToken = function() {\n    const str2 = consumeAName();\n    if (str2.toLowerCase() === "url" && next() === 40) {\n      consume();\n      while (whitespace(next(1)) && whitespace(next(2)))\n        consume();\n      if (next() === 34 || next() === 39)\n        return new FunctionToken(str2);\n      else if (whitespace(next()) && (next(2) === 34 || next(2) === 39))\n        return new FunctionToken(str2);\n      else\n        return consumeAURLToken();\n    } else if (next() === 40) {\n      consume();\n      return new FunctionToken(str2);\n    } else {\n      return new IdentToken(str2);\n    }\n  };\n  const consumeAStringToken = function(endingCodePoint) {\n    if (endingCodePoint === void 0)\n      endingCodePoint = code;\n    let string = "";\n    while (consume()) {\n      if (code === endingCodePoint || eof()) {\n        return new StringToken(string);\n      } else if (newline(code)) {\n        parseerror();\n        reconsume();\n        return new BadStringToken();\n      } else if (code === 92) {\n        if (eof(next()))\n          donothing();\n        else if (newline(next()))\n          consume();\n        else\n          string += stringFromCode(consumeEscape());\n      } else {\n        string += stringFromCode(code);\n      }\n    }\n    throw new Error("Internal error");\n  };\n  const consumeAURLToken = function() {\n    const token = new URLToken("");\n    while (whitespace(next()))\n      consume();\n    if (eof(next()))\n      return token;\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return token;\n      } else if (whitespace(code)) {\n        while (whitespace(next()))\n          consume();\n        if (next() === 41 || eof(next())) {\n          consume();\n          return token;\n        } else {\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else if (code === 34 || code === 39 || code === 40 || nonprintable(code)) {\n        parseerror();\n        consumeTheRemnantsOfABadURL();\n        return new BadURLToken();\n      } else if (code === 92) {\n        if (startsWithAValidEscape()) {\n          token.value += stringFromCode(consumeEscape());\n        } else {\n          parseerror();\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else {\n        token.value += stringFromCode(code);\n      }\n    }\n    throw new Error("Internal error");\n  };\n  const consumeEscape = function() {\n    consume();\n    if (hexdigit(code)) {\n      const digits = [code];\n      for (let total = 0; total < 5; total++) {\n        if (hexdigit(next())) {\n          consume();\n          digits.push(code);\n        } else {\n          break;\n        }\n      }\n      if (whitespace(next()))\n        consume();\n      let value = parseInt(digits.map(function(x) {\n        return String.fromCharCode(x);\n      }).join(""), 16);\n      if (value > maximumallowedcodepoint)\n        value = 65533;\n      return value;\n    } else if (eof()) {\n      return 65533;\n    } else {\n      return code;\n    }\n  };\n  const areAValidEscape = function(c1, c2) {\n    if (c1 !== 92)\n      return false;\n    if (newline(c2))\n      return false;\n    return true;\n  };\n  const startsWithAValidEscape = function() {\n    return areAValidEscape(code, next());\n  };\n  const wouldStartAnIdentifier = function(c1, c2, c3) {\n    if (c1 === 45)\n      return namestartchar(c2) || c2 === 45 || areAValidEscape(c2, c3);\n    else if (namestartchar(c1))\n      return true;\n    else if (c1 === 92)\n      return areAValidEscape(c1, c2);\n    else\n      return false;\n  };\n  const startsWithAnIdentifier = function() {\n    return wouldStartAnIdentifier(code, next(1), next(2));\n  };\n  const wouldStartANumber = function(c1, c2, c3) {\n    if (c1 === 43 || c1 === 45) {\n      if (digit(c2))\n        return true;\n      if (c2 === 46 && digit(c3))\n        return true;\n      return false;\n    } else if (c1 === 46) {\n      if (digit(c2))\n        return true;\n      return false;\n    } else if (digit(c1)) {\n      return true;\n    } else {\n      return false;\n    }\n  };\n  const startsWithANumber = function() {\n    return wouldStartANumber(code, next(1), next(2));\n  };\n  const consumeAName = function() {\n    let result = "";\n    while (consume()) {\n      if (namechar(code)) {\n        result += stringFromCode(code);\n      } else if (startsWithAValidEscape()) {\n        result += stringFromCode(consumeEscape());\n      } else {\n        reconsume();\n        return result;\n      }\n    }\n    throw new Error("Internal parse error");\n  };\n  const consumeANumber = function() {\n    let repr = "";\n    let type = "integer";\n    if (next() === 43 || next() === 45) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    while (digit(next())) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    if (next(1) === 46 && digit(next(2))) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = "number";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const c1 = next(1), c2 = next(2), c3 = next(3);\n    if ((c1 === 69 || c1 === 101) && digit(c2)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = "number";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    } else if ((c1 === 69 || c1 === 101) && (c2 === 43 || c2 === 45) && digit(c3)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = "number";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const value = convertAStringToANumber(repr);\n    return { type, value, repr };\n  };\n  const convertAStringToANumber = function(string) {\n    return +string;\n  };\n  const consumeTheRemnantsOfABadURL = function() {\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return;\n      } else if (startsWithAValidEscape()) {\n        consumeEscape();\n        donothing();\n      } else {\n        donothing();\n      }\n    }\n  };\n  let iterationCount = 0;\n  while (!eof(next())) {\n    tokens.push(consumeAToken());\n    iterationCount++;\n    if (iterationCount > str.length * 2)\n      throw new Error("I\'m infinite-looping!");\n  }\n  return tokens;\n}\nvar CSSParserToken = class {\n  constructor() {\n    this.tokenType = "";\n  }\n  toJSON() {\n    return { token: this.tokenType };\n  }\n  toString() {\n    return this.tokenType;\n  }\n  toSource() {\n    return "" + this;\n  }\n};\nvar BadStringToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "BADSTRING";\n  }\n};\nvar BadURLToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "BADURL";\n  }\n};\nvar WhitespaceToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "WHITESPACE";\n  }\n  toString() {\n    return "WS";\n  }\n  toSource() {\n    return " ";\n  }\n};\nvar CDOToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "CDO";\n  }\n  toSource() {\n    return "<!--";\n  }\n};\nvar CDCToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "CDC";\n  }\n  toSource() {\n    return "-->";\n  }\n};\nvar ColonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = ":";\n  }\n};\nvar SemicolonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = ";";\n  }\n};\nvar CommaToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = ",";\n  }\n};\nvar GroupingToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = "";\n    this.mirror = "";\n  }\n};\nvar OpenCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = "{";\n    this.value = "{";\n    this.mirror = "}";\n  }\n};\nvar CloseCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = "}";\n    this.value = "}";\n    this.mirror = "{";\n  }\n};\nvar OpenSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = "[";\n    this.value = "[";\n    this.mirror = "]";\n  }\n};\nvar CloseSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = "]";\n    this.value = "]";\n    this.mirror = "[";\n  }\n};\nvar OpenParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = "(";\n    this.value = "(";\n    this.mirror = ")";\n  }\n};\nvar CloseParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = ")";\n    this.value = ")";\n    this.mirror = "(";\n  }\n};\nvar IncludeMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "~=";\n  }\n};\nvar DashMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "|=";\n  }\n};\nvar PrefixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "^=";\n  }\n};\nvar SuffixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "$=";\n  }\n};\nvar SubstringMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "*=";\n  }\n};\nvar ColumnToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "||";\n  }\n};\nvar EOFToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = "EOF";\n  }\n  toSource() {\n    return "";\n  }\n};\nvar DelimToken = class extends CSSParserToken {\n  constructor(code) {\n    super();\n    this.tokenType = "DELIM";\n    this.value = "";\n    this.value = stringFromCode(code);\n  }\n  toString() {\n    return "DELIM(" + this.value + ")";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n  toSource() {\n    if (this.value === "\\\\")\n      return "\\\\\\n";\n    else\n      return this.value;\n  }\n};\nvar StringValuedToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = "";\n  }\n  ASCIIMatch(str) {\n    return this.value.toLowerCase() === str.toLowerCase();\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n};\nvar IdentToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "IDENT";\n    this.value = val;\n  }\n  toString() {\n    return "IDENT(" + this.value + ")";\n  }\n  toSource() {\n    return escapeIdent(this.value);\n  }\n};\nvar FunctionToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "FUNCTION";\n    this.value = val;\n    this.mirror = ")";\n  }\n  toString() {\n    return "FUNCTION(" + this.value + ")";\n  }\n  toSource() {\n    return escapeIdent(this.value) + "(";\n  }\n};\nvar AtKeywordToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "AT-KEYWORD";\n    this.value = val;\n  }\n  toString() {\n    return "AT(" + this.value + ")";\n  }\n  toSource() {\n    return "@" + escapeIdent(this.value);\n  }\n};\nvar HashToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "HASH";\n    this.value = val;\n    this.type = "unrestricted";\n  }\n  toString() {\n    return "HASH(" + this.value + ")";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    return json;\n  }\n  toSource() {\n    if (this.type === "id")\n      return "#" + escapeIdent(this.value);\n    else\n      return "#" + escapeHash(this.value);\n  }\n};\nvar StringToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "STRING";\n    this.value = val;\n  }\n  toString() {\n    return \'"\' + escapeString(this.value) + \'"\';\n  }\n};\nvar URLToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = "URL";\n    this.value = val;\n  }\n  toString() {\n    return "URL(" + this.value + ")";\n  }\n  toSource() {\n    return \'url("\' + escapeString(this.value) + \'")\';\n  }\n};\nvar NumberToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = "NUMBER";\n    this.type = "integer";\n    this.repr = "";\n  }\n  toString() {\n    if (this.type === "integer")\n      return "INT(" + this.value + ")";\n    return "NUMBER(" + this.value + ")";\n  }\n  toJSON() {\n    const json = super.toJSON();\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr;\n  }\n};\nvar PercentageToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = "PERCENTAGE";\n    this.repr = "";\n  }\n  toString() {\n    return "PERCENTAGE(" + this.value + ")";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr + "%";\n  }\n};\nvar DimensionToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = "DIMENSION";\n    this.type = "integer";\n    this.repr = "";\n    this.unit = "";\n  }\n  toString() {\n    return "DIM(" + this.value + "," + this.unit + ")";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    json.unit = this.unit;\n    return json;\n  }\n  toSource() {\n    const source = this.repr;\n    let unit = escapeIdent(this.unit);\n    if (unit[0].toLowerCase() === "e" && (unit[1] === "-" || between(unit.charCodeAt(1), 48, 57))) {\n      unit = "\\\\65 " + unit.slice(1, unit.length);\n    }\n    return source + unit;\n  }\n};\nfunction escapeIdent(string) {\n  string = "" + string;\n  let result = "";\n  const firstcode = string.charCodeAt(0);\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError("Invalid character: the input contains U+0000.");\n    if (between(code, 1, 31) || code === 127 || i === 0 && between(code, 48, 57) || i === 1 && between(code, 48, 57) && firstcode === 45)\n      result += "\\\\" + code.toString(16) + " ";\n    else if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += "\\\\" + string[i];\n  }\n  return result;\n}\nfunction escapeHash(string) {\n  string = "" + string;\n  let result = "";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError("Invalid character: the input contains U+0000.");\n    if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += "\\\\" + code.toString(16) + " ";\n  }\n  return result;\n}\nfunction escapeString(string) {\n  string = "" + string;\n  let result = "";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError("Invalid character: the input contains U+0000.");\n    if (between(code, 1, 31) || code === 127)\n      result += "\\\\" + code.toString(16) + " ";\n    else if (code === 34 || code === 92)\n      result += "\\\\" + string[i];\n    else\n      result += string[i];\n  }\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssParser.ts\nvar InvalidSelectorError = class extends Error {\n};\nfunction parseCSS(selector, customNames) {\n  let tokens;\n  try {\n    tokens = tokenize(selector);\n    if (!(tokens[tokens.length - 1] instanceof EOFToken))\n      tokens.push(new EOFToken());\n  } catch (e) {\n    const newMessage = e.message + ` while parsing css selector "${selector}". Did you mean to CSS.escape it?`;\n    const index = (e.stack || "").indexOf(e.message);\n    if (index !== -1)\n      e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);\n    e.message = newMessage;\n    throw e;\n  }\n  const unsupportedToken = tokens.find((token) => {\n    return token instanceof AtKeywordToken || token instanceof BadStringToken || token instanceof BadURLToken || token instanceof ColumnToken || token instanceof CDOToken || token instanceof CDCToken || token instanceof SemicolonToken || // TODO: Consider using these for something, e.g. to escape complex strings.\n    // For example :xpath{ (//div/bar[@attr="foo"])[2]/baz }\n    // Or this way :xpath( {complex-xpath-goes-here("hello")} )\n    token instanceof OpenCurlyToken || token instanceof CloseCurlyToken || // TODO: Consider treating these as strings?\n    token instanceof URLToken || token instanceof PercentageToken;\n  });\n  if (unsupportedToken)\n    throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`);\n  let pos = 0;\n  const names = /* @__PURE__ */ new Set();\n  function unexpected() {\n    return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`);\n  }\n  function skipWhitespace() {\n    while (tokens[pos] instanceof WhitespaceToken)\n      pos++;\n  }\n  function isIdent(p = pos) {\n    return tokens[p] instanceof IdentToken;\n  }\n  function isString(p = pos) {\n    return tokens[p] instanceof StringToken;\n  }\n  function isNumber(p = pos) {\n    return tokens[p] instanceof NumberToken;\n  }\n  function isComma(p = pos) {\n    return tokens[p] instanceof CommaToken;\n  }\n  function isOpenParen(p = pos) {\n    return tokens[p] instanceof OpenParenToken;\n  }\n  function isCloseParen(p = pos) {\n    return tokens[p] instanceof CloseParenToken;\n  }\n  function isFunction(p = pos) {\n    return tokens[p] instanceof FunctionToken;\n  }\n  function isStar(p = pos) {\n    return tokens[p] instanceof DelimToken && tokens[p].value === "*";\n  }\n  function isEOF(p = pos) {\n    return tokens[p] instanceof EOFToken;\n  }\n  function isClauseCombinator(p = pos) {\n    return tokens[p] instanceof DelimToken && [">", "+", "~"].includes(tokens[p].value);\n  }\n  function isSelectorClauseEnd(p = pos) {\n    return isComma(p) || isCloseParen(p) || isEOF(p) || isClauseCombinator(p) || tokens[p] instanceof WhitespaceToken;\n  }\n  function consumeFunctionArguments() {\n    const result2 = [consumeArgument()];\n    while (true) {\n      skipWhitespace();\n      if (!isComma())\n        break;\n      pos++;\n      result2.push(consumeArgument());\n    }\n    return result2;\n  }\n  function consumeArgument() {\n    skipWhitespace();\n    if (isNumber())\n      return tokens[pos++].value;\n    if (isString())\n      return tokens[pos++].value;\n    return consumeComplexSelector();\n  }\n  function consumeComplexSelector() {\n    const result2 = { simples: [] };\n    skipWhitespace();\n    if (isClauseCombinator()) {\n      result2.simples.push({ selector: { functions: [{ name: "scope", args: [] }] }, combinator: "" });\n    } else {\n      result2.simples.push({ selector: consumeSimpleSelector(), combinator: "" });\n    }\n    while (true) {\n      skipWhitespace();\n      if (isClauseCombinator()) {\n        result2.simples[result2.simples.length - 1].combinator = tokens[pos++].value;\n        skipWhitespace();\n      } else if (isSelectorClauseEnd()) {\n        break;\n      }\n      result2.simples.push({ combinator: "", selector: consumeSimpleSelector() });\n    }\n    return result2;\n  }\n  function consumeSimpleSelector() {\n    let rawCSSString = "";\n    const functions = [];\n    while (!isSelectorClauseEnd()) {\n      if (isIdent() || isStar()) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof HashToken) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof DelimToken && tokens[pos].value === ".") {\n        pos++;\n        if (isIdent())\n          rawCSSString += "." + tokens[pos++].toSource();\n        else\n          throw unexpected();\n      } else if (tokens[pos] instanceof ColonToken) {\n        pos++;\n        if (isIdent()) {\n          if (!customNames.has(tokens[pos].value.toLowerCase())) {\n            rawCSSString += ":" + tokens[pos++].toSource();\n          } else {\n            const name = tokens[pos++].value.toLowerCase();\n            functions.push({ name, args: [] });\n            names.add(name);\n          }\n        } else if (isFunction()) {\n          const name = tokens[pos++].value.toLowerCase();\n          if (!customNames.has(name)) {\n            rawCSSString += `:${name}(${consumeBuiltinFunctionArguments()})`;\n          } else {\n            functions.push({ name, args: consumeFunctionArguments() });\n            names.add(name);\n          }\n          skipWhitespace();\n          if (!isCloseParen())\n            throw unexpected();\n          pos++;\n        } else {\n          throw unexpected();\n        }\n      } else if (tokens[pos] instanceof OpenSquareToken) {\n        rawCSSString += "[";\n        pos++;\n        while (!(tokens[pos] instanceof CloseSquareToken) && !isEOF())\n          rawCSSString += tokens[pos++].toSource();\n        if (!(tokens[pos] instanceof CloseSquareToken))\n          throw unexpected();\n        rawCSSString += "]";\n        pos++;\n      } else {\n        throw unexpected();\n      }\n    }\n    if (!rawCSSString && !functions.length)\n      throw unexpected();\n    return { css: rawCSSString || void 0, functions };\n  }\n  function consumeBuiltinFunctionArguments() {\n    let s = "";\n    let balance = 1;\n    while (!isEOF()) {\n      if (isOpenParen() || isFunction())\n        balance++;\n      if (isCloseParen())\n        balance--;\n      if (!balance)\n        break;\n      s += tokens[pos++].toSource();\n    }\n    return s;\n  }\n  const result = consumeFunctionArguments();\n  if (!isEOF())\n    throw unexpected();\n  if (result.some((arg) => typeof arg !== "object" || !("simples" in arg)))\n    throw new InvalidSelectorError(`Error while parsing css selector "${selector}". Did you mean to CSS.escape it?`);\n  return { selector: result, names: Array.from(names) };\n}\n\n// packages/playwright-core/src/utils/isomorphic/selectorParser.ts\nvar kNestedSelectorNames = /* @__PURE__ */ new Set(["internal:has", "internal:has-not", "internal:and", "internal:or", "internal:chain", "left-of", "right-of", "above", "below", "near"]);\nvar kNestedSelectorNamesWithDistance = /* @__PURE__ */ new Set(["left-of", "right-of", "above", "below", "near"]);\nvar customCSSNames = /* @__PURE__ */ new Set(["not", "is", "where", "has", "scope", "light", "visible", "text", "text-matches", "text-is", "has-text", "above", "below", "right-of", "left-of", "near", "nth-match"]);\nfunction parseSelector(selector) {\n  const parsedStrings = parseSelectorString(selector);\n  const parts = [];\n  for (const part of parsedStrings.parts) {\n    if (part.name === "css" || part.name === "css:light") {\n      if (part.name === "css:light")\n        part.body = ":light(" + part.body + ")";\n      const parsedCSS = parseCSS(part.body, customCSSNames);\n      parts.push({\n        name: "css",\n        body: parsedCSS.selector,\n        source: part.body\n      });\n      continue;\n    }\n    if (kNestedSelectorNames.has(part.name)) {\n      let innerSelector;\n      let distance;\n      try {\n        const unescaped = JSON.parse("[" + part.body + "]");\n        if (!Array.isArray(unescaped) || unescaped.length < 1 || unescaped.length > 2 || typeof unescaped[0] !== "string")\n          throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n        innerSelector = unescaped[0];\n        if (unescaped.length === 2) {\n          if (typeof unescaped[1] !== "number" || !kNestedSelectorNamesWithDistance.has(part.name))\n            throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n          distance = unescaped[1];\n        }\n      } catch (e) {\n        throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n      }\n      const nested = { name: part.name, source: part.body, body: { parsed: parseSelector(innerSelector), distance } };\n      const lastFrame = [...nested.body.parsed.parts].reverse().find((part2) => part2.name === "internal:control" && part2.body === "enter-frame");\n      const lastFrameIndex = lastFrame ? nested.body.parsed.parts.indexOf(lastFrame) : -1;\n      if (lastFrameIndex !== -1 && selectorPartsEqual(nested.body.parsed.parts.slice(0, lastFrameIndex + 1), parts.slice(0, lastFrameIndex + 1)))\n        nested.body.parsed.parts.splice(0, lastFrameIndex + 1);\n      parts.push(nested);\n      continue;\n    }\n    parts.push({ ...part, source: part.body });\n  }\n  if (kNestedSelectorNames.has(parts[0].name))\n    throw new InvalidSelectorError(`"${parts[0].name}" selector cannot be first`);\n  return {\n    capture: parsedStrings.capture,\n    parts\n  };\n}\nfunction selectorPartsEqual(list1, list2) {\n  return stringifySelector({ parts: list1 }) === stringifySelector({ parts: list2 });\n}\nfunction stringifySelector(selector, forceEngineName) {\n  if (typeof selector === "string")\n    return selector;\n  return selector.parts.map((p, i) => {\n    let includeEngine = true;\n    if (!forceEngineName && i !== selector.capture) {\n      if (p.name === "css")\n        includeEngine = false;\n      else if (p.name === "xpath" && p.source.startsWith("//") || p.source.startsWith(".."))\n        includeEngine = false;\n    }\n    const prefix = includeEngine ? p.name + "=" : "";\n    return `${i === selector.capture ? "*" : ""}${prefix}${p.source}`;\n  }).join(" >> ");\n}\nfunction visitAllSelectorParts(selector, visitor) {\n  const visit = (selector2, nested) => {\n    for (const part of selector2.parts) {\n      visitor(part, nested);\n      if (kNestedSelectorNames.has(part.name))\n        visit(part.body.parsed, true);\n    }\n  };\n  visit(selector, false);\n}\nfunction parseSelectorString(selector) {\n  let index = 0;\n  let quote;\n  let start = 0;\n  const result = { parts: [] };\n  const append = () => {\n    const part = selector.substring(start, index).trim();\n    const eqIndex = part.indexOf("=");\n    let name;\n    let body;\n    if (eqIndex !== -1 && part.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9-+:*]+$/)) {\n      name = part.substring(0, eqIndex).trim();\n      body = part.substring(eqIndex + 1);\n    } else if (part.length > 1 && part[0] === \'"\' && part[part.length - 1] === \'"\') {\n      name = "text";\n      body = part;\n    } else if (part.length > 1 && part[0] === "\'" && part[part.length - 1] === "\'") {\n      name = "text";\n      body = part;\n    } else if (/^\\(*\\/\\//.test(part) || part.startsWith("..")) {\n      name = "xpath";\n      body = part;\n    } else {\n      name = "css";\n      body = part;\n    }\n    let capture = false;\n    if (name[0] === "*") {\n      capture = true;\n      name = name.substring(1);\n    }\n    result.parts.push({ name, body });\n    if (capture) {\n      if (result.capture !== void 0)\n        throw new InvalidSelectorError(`Only one of the selectors can capture using * modifier`);\n      result.capture = result.parts.length - 1;\n    }\n  };\n  if (!selector.includes(">>")) {\n    index = selector.length;\n    append();\n    return result;\n  }\n  const shouldIgnoreTextSelectorQuote = () => {\n    const prefix = selector.substring(start, index);\n    const match = prefix.match(/^\\s*text\\s*=(.*)$/);\n    return !!match && !!match[1];\n  };\n  while (index < selector.length) {\n    const c = selector[index];\n    if (c === "\\\\" && index + 1 < selector.length) {\n      index += 2;\n    } else if (c === quote) {\n      quote = void 0;\n      index++;\n    } else if (!quote && (c === \'"\' || c === "\'" || c === "`") && !shouldIgnoreTextSelectorQuote()) {\n      quote = c;\n      index++;\n    } else if (!quote && c === ">" && selector[index + 1] === ">") {\n      append();\n      index += 2;\n      start = index;\n    } else {\n      index++;\n    }\n  }\n  append();\n  return result;\n}\nfunction parseAttributeSelector(selector, allowUnquotedStrings) {\n  let wp = 0;\n  let EOL = selector.length === 0;\n  const next = () => selector[wp] || "";\n  const eat1 = () => {\n    const result2 = next();\n    ++wp;\n    EOL = wp >= selector.length;\n    return result2;\n  };\n  const syntaxError = (stage) => {\n    if (EOL)\n      throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \\`${selector}\\``);\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - unexpected symbol "${next()}" at position ${wp}` + (stage ? " during " + stage : ""));\n  };\n  function skipSpaces() {\n    while (!EOL && /\\s/.test(next()))\n      eat1();\n  }\n  function isCSSNameChar(char) {\n    return char >= "\\x80" || char >= "0" && char <= "9" || char >= "A" && char <= "Z" || char >= "a" && char <= "z" || char >= "0" && char <= "9" || char === "_" || char === "-";\n  }\n  function readIdentifier() {\n    let result2 = "";\n    skipSpaces();\n    while (!EOL && isCSSNameChar(next()))\n      result2 += eat1();\n    return result2;\n  }\n  function readQuotedString(quote) {\n    let result2 = eat1();\n    if (result2 !== quote)\n      syntaxError("parsing quoted string");\n    while (!EOL && next() !== quote) {\n      if (next() === "\\\\")\n        eat1();\n      result2 += eat1();\n    }\n    if (next() !== quote)\n      syntaxError("parsing quoted string");\n    result2 += eat1();\n    return result2;\n  }\n  function readRegularExpression() {\n    if (eat1() !== "/")\n      syntaxError("parsing regular expression");\n    let source = "";\n    let inClass = false;\n    while (!EOL) {\n      if (next() === "\\\\") {\n        source += eat1();\n        if (EOL)\n          syntaxError("parsing regular expression");\n      } else if (inClass && next() === "]") {\n        inClass = false;\n      } else if (!inClass && next() === "[") {\n        inClass = true;\n      } else if (!inClass && next() === "/") {\n        break;\n      }\n      source += eat1();\n    }\n    if (eat1() !== "/")\n      syntaxError("parsing regular expression");\n    let flags = "";\n    while (!EOL && next().match(/[dgimsuy]/))\n      flags += eat1();\n    try {\n      return new RegExp(source, flags);\n    } catch (e) {\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\`: ${e.message}`);\n    }\n  }\n  function readAttributeToken() {\n    let token = "";\n    skipSpaces();\n    if (next() === `\'` || next() === `"`)\n      token = readQuotedString(next()).slice(1, -1);\n    else\n      token = readIdentifier();\n    if (!token)\n      syntaxError("parsing property path");\n    return token;\n  }\n  function readOperator() {\n    skipSpaces();\n    let op = "";\n    if (!EOL)\n      op += eat1();\n    if (!EOL && op !== "=")\n      op += eat1();\n    if (!["=", "*=", "^=", "$=", "|=", "~="].includes(op))\n      syntaxError("parsing operator");\n    return op;\n  }\n  function readAttribute() {\n    eat1();\n    const jsonPath = [];\n    jsonPath.push(readAttributeToken());\n    skipSpaces();\n    while (next() === ".") {\n      eat1();\n      jsonPath.push(readAttributeToken());\n      skipSpaces();\n    }\n    if (next() === "]") {\n      eat1();\n      return { name: jsonPath.join("."), jsonPath, op: "<truthy>", value: null, caseSensitive: false };\n    }\n    const operator = readOperator();\n    let value = void 0;\n    let caseSensitive = true;\n    skipSpaces();\n    if (next() === "/") {\n      if (operator !== "=")\n        throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with regular expression`);\n      value = readRegularExpression();\n    } else if (next() === `\'` || next() === `"`) {\n      value = readQuotedString(next()).slice(1, -1);\n      skipSpaces();\n      if (next() === "i" || next() === "I") {\n        caseSensitive = false;\n        eat1();\n      } else if (next() === "s" || next() === "S") {\n        caseSensitive = true;\n        eat1();\n      }\n    } else {\n      value = "";\n      while (!EOL && (isCSSNameChar(next()) || next() === "+" || next() === "."))\n        value += eat1();\n      if (value === "true") {\n        value = true;\n      } else if (value === "false") {\n        value = false;\n      } else {\n        if (!allowUnquotedStrings) {\n          value = +value;\n          if (Number.isNaN(value))\n            syntaxError("parsing attribute value");\n        }\n      }\n    }\n    skipSpaces();\n    if (next() !== "]")\n      syntaxError("parsing attribute value");\n    eat1();\n    if (operator !== "=" && typeof value !== "string")\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);\n    return { name: jsonPath.join("."), jsonPath, op: operator, value, caseSensitive };\n  }\n  const result = {\n    name: "",\n    attributes: []\n  };\n  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === "[") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/stringUtils.ts\nfunction escapeWithQuotes(text, char = "\'") {\n  const stringified = JSON.stringify(text);\n  const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\\\"/g, \'"\');\n  if (char === "\'")\n    return char + escapedText.replace(/[\']/g, "\\\\\'") + char;\n  if (char === \'"\')\n    return char + escapedText.replace(/["]/g, \'\\\\"\') + char;\n  if (char === "`")\n    return char + escapedText.replace(/[`]/g, "\\\\`") + char;\n  throw new Error("Invalid escape char");\n}\nfunction toTitleCase(name) {\n  return name.charAt(0).toUpperCase() + name.substring(1);\n}\nfunction toSnakeCase(name) {\n  return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toLowerCase();\n}\nfunction quoteCSSAttributeValue(text) {\n  return `"${text.replace(/["\\\\]/g, (char) => "\\\\" + char)}"`;\n}\nvar normalizedWhitespaceCache;\nfunction cacheNormalizedWhitespaces() {\n  normalizedWhitespaceCache = /* @__PURE__ */ new Map();\n}\nfunction normalizeWhiteSpace(text) {\n  let result = normalizedWhitespaceCache == null ? void 0 : normalizedWhitespaceCache.get(text);\n  if (result === void 0) {\n    result = text.replace(/[\\u200b\\u00ad]/g, "").trim().replace(/\\s+/g, " ");\n    normalizedWhitespaceCache == null ? void 0 : normalizedWhitespaceCache.set(text, result);\n  }\n  return result;\n}\nfunction normalizeEscapedRegexQuotes(source) {\n  return source.replace(/(^|[^\\\\])(\\\\\\\\)*\\\\([\'"`])/g, "$1$2$3");\n}\nfunction escapeRegexForSelector(re) {\n  if (re.unicode || re.unicodeSets)\n    return String(re);\n  return String(re).replace(/(^|[^\\\\])(\\\\\\\\)*(["\'`])/g, "$1$2\\\\$3").replace(/>>/g, "\\\\>\\\\>");\n}\nfunction escapeForTextSelector(text, exact) {\n  if (typeof text !== "string")\n    return escapeRegexForSelector(text);\n  return `${JSON.stringify(text)}${exact ? "s" : "i"}`;\n}\nfunction escapeForAttributeSelector(value, exact) {\n  if (typeof value !== "string")\n    return escapeRegexForSelector(value);\n  return `"${value.replace(/\\\\/g, "\\\\\\\\").replace(/["]/g, \'\\\\"\')}"${exact ? "s" : "i"}`;\n}\nfunction trimString(input, cap, suffix = "") {\n  if (input.length <= cap)\n    return input;\n  const chars = [...input];\n  if (chars.length > cap)\n    return chars.slice(0, cap - suffix.length).join("") + suffix;\n  return chars.join("");\n}\nfunction trimStringWithEllipsis(input, cap) {\n  return trimString(input, cap, "\\u2026");\n}\nfunction escapeRegExp(s) {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&");\n}\nfunction longestCommonSubstring(s1, s2) {\n  const n = s1.length;\n  const m = s2.length;\n  let maxLen = 0;\n  let endingIndex = 0;\n  const dp = Array(n + 1).fill(null).map(() => Array(m + 1).fill(0));\n  for (let i = 1; i <= n; i++) {\n    for (let j = 1; j <= m; j++) {\n      if (s1[i - 1] === s2[j - 1]) {\n        dp[i][j] = dp[i - 1][j - 1] + 1;\n        if (dp[i][j] > maxLen) {\n          maxLen = dp[i][j];\n          endingIndex = i;\n        }\n      }\n    }\n  }\n  return s1.slice(endingIndex - maxLen, endingIndex);\n}\nvar ansiRegex = new RegExp("([\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:[a-zA-Z\\\\d]*(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)|(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~])))", "g");\n\n// packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts\nfunction asLocator(lang, selector, isFrameLocator = false) {\n  return asLocators(lang, selector, isFrameLocator, 1)[0];\n}\nfunction asLocators(lang, selector, isFrameLocator = false, maxOutputSize = 20, preferredQuote) {\n  try {\n    return innerAsLocators(new generators[lang](preferredQuote), parseSelector(selector), isFrameLocator, maxOutputSize);\n  } catch (e) {\n    return [selector];\n  }\n}\nfunction innerAsLocators(factory, parsed, isFrameLocator = false, maxOutputSize = 20) {\n  const parts = [...parsed.parts];\n  const tokens = [];\n  let nextBase = isFrameLocator ? "frame-locator" : "page";\n  for (let index = 0; index < parts.length; index++) {\n    const part = parts[index];\n    const base = nextBase;\n    nextBase = "locator";\n    if (part.name === "internal:describe")\n      continue;\n    if (part.name === "nth") {\n      if (part.body === "0")\n        tokens.push([factory.generateLocator(base, "first", ""), factory.generateLocator(base, "nth", "0")]);\n      else if (part.body === "-1")\n        tokens.push([factory.generateLocator(base, "last", ""), factory.generateLocator(base, "nth", "-1")]);\n      else\n        tokens.push([factory.generateLocator(base, "nth", part.body)]);\n      continue;\n    }\n    if (part.name === "visible") {\n      tokens.push([factory.generateLocator(base, "visible", part.body), factory.generateLocator(base, "default", `visible=${part.body}`)]);\n      continue;\n    }\n    if (part.name === "internal:text") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push([factory.generateLocator(base, "text", text, { exact })]);\n      continue;\n    }\n    if (part.name === "internal:has-text") {\n      const { exact, text } = detectExact(part.body);\n      if (!exact) {\n        tokens.push([factory.generateLocator(base, "has-text", text, { exact })]);\n        continue;\n      }\n    }\n    if (part.name === "internal:has-not-text") {\n      const { exact, text } = detectExact(part.body);\n      if (!exact) {\n        tokens.push([factory.generateLocator(base, "has-not-text", text, { exact })]);\n        continue;\n      }\n    }\n    if (part.name === "internal:has") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, "has", inner)));\n      continue;\n    }\n    if (part.name === "internal:has-not") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, "hasNot", inner)));\n      continue;\n    }\n    if (part.name === "internal:and") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, "and", inner)));\n      continue;\n    }\n    if (part.name === "internal:or") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, "or", inner)));\n      continue;\n    }\n    if (part.name === "internal:chain") {\n      const inners = innerAsLocators(factory, part.body.parsed, false, maxOutputSize);\n      tokens.push(inners.map((inner) => factory.generateLocator(base, "chain", inner)));\n      continue;\n    }\n    if (part.name === "internal:label") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push([factory.generateLocator(base, "label", text, { exact })]);\n      continue;\n    }\n    if (part.name === "internal:role") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const options = { attrs: [] };\n      for (const attr of attrSelector.attributes) {\n        if (attr.name === "name") {\n          options.exact = attr.caseSensitive;\n          options.name = attr.value;\n        } else {\n          if (attr.name === "level" && typeof attr.value === "string")\n            attr.value = +attr.value;\n          options.attrs.push({ name: attr.name === "include-hidden" ? "includeHidden" : attr.name, value: attr.value });\n        }\n      }\n      tokens.push([factory.generateLocator(base, "role", attrSelector.name, options)]);\n      continue;\n    }\n    if (part.name === "internal:testid") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { value } = attrSelector.attributes[0];\n      tokens.push([factory.generateLocator(base, "test-id", value)]);\n      continue;\n    }\n    if (part.name === "internal:attr") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { name, value, caseSensitive } = attrSelector.attributes[0];\n      const text = value;\n      const exact = !!caseSensitive;\n      if (name === "placeholder") {\n        tokens.push([factory.generateLocator(base, "placeholder", text, { exact })]);\n        continue;\n      }\n      if (name === "alt") {\n        tokens.push([factory.generateLocator(base, "alt", text, { exact })]);\n        continue;\n      }\n      if (name === "title") {\n        tokens.push([factory.generateLocator(base, "title", text, { exact })]);\n        continue;\n      }\n    }\n    if (part.name === "internal:control" && part.body === "enter-frame") {\n      const lastTokens = tokens[tokens.length - 1];\n      const lastPart = parts[index - 1];\n      const transformed = lastTokens.map((token) => factory.chainLocators([token, factory.generateLocator(base, "frame", "")]));\n      if (["xpath", "css"].includes(lastPart.name)) {\n        transformed.push(\n          factory.generateLocator(base, "frame-locator", stringifySelector({ parts: [lastPart] })),\n          factory.generateLocator(base, "frame-locator", stringifySelector({ parts: [lastPart] }, true))\n        );\n      }\n      lastTokens.splice(0, lastTokens.length, ...transformed);\n      nextBase = "frame-locator";\n      continue;\n    }\n    const nextPart = parts[index + 1];\n    const selectorPart = stringifySelector({ parts: [part] });\n    const locatorPart = factory.generateLocator(base, "default", selectorPart);\n    if (nextPart && ["internal:has-text", "internal:has-not-text"].includes(nextPart.name)) {\n      const { exact, text } = detectExact(nextPart.body);\n      if (!exact) {\n        const nextLocatorPart = factory.generateLocator("locator", nextPart.name === "internal:has-text" ? "has-text" : "has-not-text", text, { exact });\n        const options = {};\n        if (nextPart.name === "internal:has-text")\n          options.hasText = text;\n        else\n          options.hasNotText = text;\n        const combinedPart = factory.generateLocator(base, "default", selectorPart, options);\n        tokens.push([factory.chainLocators([locatorPart, nextLocatorPart]), combinedPart]);\n        index++;\n        continue;\n      }\n    }\n    let locatorPartWithEngine;\n    if (["xpath", "css"].includes(part.name)) {\n      const selectorPart2 = stringifySelector(\n        { parts: [part] },\n        /* forceEngineName */\n        true\n      );\n      locatorPartWithEngine = factory.generateLocator(base, "default", selectorPart2);\n    }\n    tokens.push([locatorPart, locatorPartWithEngine].filter(Boolean));\n  }\n  return combineTokens(factory, tokens, maxOutputSize);\n}\nfunction combineTokens(factory, tokens, maxOutputSize) {\n  const currentTokens = tokens.map(() => "");\n  const result = [];\n  const visit = (index) => {\n    if (index === tokens.length) {\n      result.push(factory.chainLocators(currentTokens));\n      return result.length < maxOutputSize;\n    }\n    for (const taken of tokens[index]) {\n      currentTokens[index] = taken;\n      if (!visit(index + 1))\n        return false;\n    }\n    return true;\n  };\n  visit(0);\n  return result;\n}\nfunction detectExact(text) {\n  let exact = false;\n  const match = text.match(/^\\/(.*)\\/([igm]*)$/);\n  if (match)\n    return { text: new RegExp(match[1], match[2]) };\n  if (text.endsWith(\'"\')) {\n    text = JSON.parse(text);\n    exact = true;\n  } else if (text.endsWith(\'"s\')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = true;\n  } else if (text.endsWith(\'"i\')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = false;\n  }\n  return { exact, text };\n}\nvar JavaScriptLocatorFactory = class {\n  constructor(preferredQuote) {\n    this.preferredQuote = preferredQuote;\n  }\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case "default":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, { hasText: ${this.toHasText(options.hasText)} })`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, { hasNotText: ${this.toHasText(options.hasNotText)} })`;\n        return `locator(${this.quote(body)})`;\n      case "frame-locator":\n        return `frameLocator(${this.quote(body)})`;\n      case "frame":\n        return `contentFrame()`;\n      case "nth":\n        return `nth(${body})`;\n      case "first":\n        return `first()`;\n      case "last":\n        return `last()`;\n      case "visible":\n        return `filter({ visible: ${body === "true" ? "true" : "false"} })`;\n      case "role":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name: ${this.regexToSourceString(options.name)}`);\n        } else if (typeof options.name === "string") {\n          attrs.push(`name: ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact: true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${name}: ${typeof value === "string" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, { ${attrs.join(", ")} }` : "";\n        return `getByRole(${this.quote(body)}${attrString})`;\n      case "has-text":\n        return `filter({ hasText: ${this.toHasText(body)} })`;\n      case "has-not-text":\n        return `filter({ hasNotText: ${this.toHasText(body)} })`;\n      case "has":\n        return `filter({ has: ${body} })`;\n      case "hasNot":\n        return `filter({ hasNot: ${body} })`;\n      case "and":\n        return `and(${body})`;\n      case "or":\n        return `or(${body})`;\n      case "chain":\n        return `locator(${body})`;\n      case "test-id":\n        return `getByTestId(${this.toTestIdValue(body)})`;\n      case "text":\n        return this.toCallWithExact("getByText", body, !!options.exact);\n      case "alt":\n        return this.toCallWithExact("getByAltText", body, !!options.exact);\n      case "placeholder":\n        return this.toCallWithExact("getByPlaceholder", body, !!options.exact);\n      case "label":\n        return this.toCallWithExact("getByLabel", body, !!options.exact);\n      case "title":\n        return this.toCallWithExact("getByTitle", body, !!options.exact);\n      default:\n        throw new Error("Unknown selector kind " + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(".");\n  }\n  regexToSourceString(re) {\n    return normalizeEscapedRegexQuotes(String(re));\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToSourceString(body)})`;\n    return exact ? `${method}(${this.quote(body)}, { exact: true })` : `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToSourceString(body);\n    return this.quote(body);\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToSourceString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    var _a;\n    return escapeWithQuotes(text, (_a = this.preferredQuote) != null ? _a : "\'");\n  }\n};\nvar PythonLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case "default":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, has_text=${this.toHasText(options.hasText)})`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, has_not_text=${this.toHasText(options.hasNotText)})`;\n        return `locator(${this.quote(body)})`;\n      case "frame-locator":\n        return `frame_locator(${this.quote(body)})`;\n      case "frame":\n        return `content_frame`;\n      case "nth":\n        return `nth(${body})`;\n      case "first":\n        return `first`;\n      case "last":\n        return `last`;\n      case "visible":\n        return `filter(visible=${body === "true" ? "True" : "False"})`;\n      case "role":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name=${this.regexToString(options.name)}`);\n        } else if (typeof options.name === "string") {\n          attrs.push(`name=${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact=True`);\n        }\n        for (const { name, value } of options.attrs) {\n          let valueString = typeof value === "string" ? this.quote(value) : value;\n          if (typeof value === "boolean")\n            valueString = value ? "True" : "False";\n          attrs.push(`${toSnakeCase(name)}=${valueString}`);\n        }\n        const attrString = attrs.length ? `, ${attrs.join(", ")}` : "";\n        return `get_by_role(${this.quote(body)}${attrString})`;\n      case "has-text":\n        return `filter(has_text=${this.toHasText(body)})`;\n      case "has-not-text":\n        return `filter(has_not_text=${this.toHasText(body)})`;\n      case "has":\n        return `filter(has=${body})`;\n      case "hasNot":\n        return `filter(has_not=${body})`;\n      case "and":\n        return `and_(${body})`;\n      case "or":\n        return `or_(${body})`;\n      case "chain":\n        return `locator(${body})`;\n      case "test-id":\n        return `get_by_test_id(${this.toTestIdValue(body)})`;\n      case "text":\n        return this.toCallWithExact("get_by_text", body, !!options.exact);\n      case "alt":\n        return this.toCallWithExact("get_by_alt_text", body, !!options.exact);\n      case "placeholder":\n        return this.toCallWithExact("get_by_placeholder", body, !!options.exact);\n      case "label":\n        return this.toCallWithExact("get_by_label", body, !!options.exact);\n      case "title":\n        return this.toCallWithExact("get_by_title", body, !!options.exact);\n      default:\n        throw new Error("Unknown selector kind " + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(".");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes("i") ? ", re.IGNORECASE" : "";\n    return `re.compile(r"${normalizeEscapedRegexQuotes(body.source).replace(/\\\\\\//, "/").replace(/"/g, \'\\\\"\')}"${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, exact=True)`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return `${this.quote(body)}`;\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, \'"\');\n  }\n};\nvar JavaLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    let clazz;\n    switch (base) {\n      case "page":\n        clazz = "Page";\n        break;\n      case "frame-locator":\n        clazz = "FrameLocator";\n        break;\n      case "locator":\n        clazz = "Locator";\n        break;\n    }\n    switch (kind) {\n      case "default":\n        if (options.hasText !== void 0)\n          return `locator(${this.quote(body)}, new ${clazz}.LocatorOptions().setHasText(${this.toHasText(options.hasText)}))`;\n        if (options.hasNotText !== void 0)\n          return `locator(${this.quote(body)}, new ${clazz}.LocatorOptions().setHasNotText(${this.toHasText(options.hasNotText)}))`;\n        return `locator(${this.quote(body)})`;\n      case "frame-locator":\n        return `frameLocator(${this.quote(body)})`;\n      case "frame":\n        return `contentFrame()`;\n      case "nth":\n        return `nth(${body})`;\n      case "first":\n        return `first()`;\n      case "last":\n        return `last()`;\n      case "visible":\n        return `filter(new ${clazz}.FilterOptions().setVisible(${body === "true" ? "true" : "false"}))`;\n      case "role":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`.setName(${this.regexToString(options.name)})`);\n        } else if (typeof options.name === "string") {\n          attrs.push(`.setName(${this.quote(options.name)})`);\n          if (options.exact)\n            attrs.push(`.setExact(true)`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`.set${toTitleCase(name)}(${typeof value === "string" ? this.quote(value) : value})`);\n        const attrString = attrs.length ? `, new ${clazz}.GetByRoleOptions()${attrs.join("")}` : "";\n        return `getByRole(AriaRole.${toSnakeCase(body).toUpperCase()}${attrString})`;\n      case "has-text":\n        return `filter(new ${clazz}.FilterOptions().setHasText(${this.toHasText(body)}))`;\n      case "has-not-text":\n        return `filter(new ${clazz}.FilterOptions().setHasNotText(${this.toHasText(body)}))`;\n      case "has":\n        return `filter(new ${clazz}.FilterOptions().setHas(${body}))`;\n      case "hasNot":\n        return `filter(new ${clazz}.FilterOptions().setHasNot(${body}))`;\n      case "and":\n        return `and(${body})`;\n      case "or":\n        return `or(${body})`;\n      case "chain":\n        return `locator(${body})`;\n      case "test-id":\n        return `getByTestId(${this.toTestIdValue(body)})`;\n      case "text":\n        return this.toCallWithExact(clazz, "getByText", body, !!options.exact);\n      case "alt":\n        return this.toCallWithExact(clazz, "getByAltText", body, !!options.exact);\n      case "placeholder":\n        return this.toCallWithExact(clazz, "getByPlaceholder", body, !!options.exact);\n      case "label":\n        return this.toCallWithExact(clazz, "getByLabel", body, !!options.exact);\n      case "title":\n        return this.toCallWithExact(clazz, "getByTitle", body, !!options.exact);\n      default:\n        throw new Error("Unknown selector kind " + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(".");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes("i") ? ", Pattern.CASE_INSENSITIVE" : "";\n    return `Pattern.compile(${this.quote(normalizeEscapedRegexQuotes(body.source))}${suffix})`;\n  }\n  toCallWithExact(clazz, method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new ${clazz}.${toTitleCase(method)}Options().setExact(true))`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return this.quote(body);\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, \'"\');\n  }\n};\nvar CSharpLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case "default":\n        if (options.hasText !== void 0)\n          return `Locator(${this.quote(body)}, new() { ${this.toHasText(options.hasText)} })`;\n        if (options.hasNotText !== void 0)\n          return `Locator(${this.quote(body)}, new() { ${this.toHasNotText(options.hasNotText)} })`;\n        return `Locator(${this.quote(body)})`;\n      case "frame-locator":\n        return `FrameLocator(${this.quote(body)})`;\n      case "frame":\n        return `ContentFrame`;\n      case "nth":\n        return `Nth(${body})`;\n      case "first":\n        return `First`;\n      case "last":\n        return `Last`;\n      case "visible":\n        return `Filter(new() { Visible = ${body === "true" ? "true" : "false"} })`;\n      case "role":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`NameRegex = ${this.regexToString(options.name)}`);\n        } else if (typeof options.name === "string") {\n          attrs.push(`Name = ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`Exact = true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${toTitleCase(name)} = ${typeof value === "string" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, new() { ${attrs.join(", ")} }` : "";\n        return `GetByRole(AriaRole.${toTitleCase(body)}${attrString})`;\n      case "has-text":\n        return `Filter(new() { ${this.toHasText(body)} })`;\n      case "has-not-text":\n        return `Filter(new() { ${this.toHasNotText(body)} })`;\n      case "has":\n        return `Filter(new() { Has = ${body} })`;\n      case "hasNot":\n        return `Filter(new() { HasNot = ${body} })`;\n      case "and":\n        return `And(${body})`;\n      case "or":\n        return `Or(${body})`;\n      case "chain":\n        return `Locator(${body})`;\n      case "test-id":\n        return `GetByTestId(${this.toTestIdValue(body)})`;\n      case "text":\n        return this.toCallWithExact("GetByText", body, !!options.exact);\n      case "alt":\n        return this.toCallWithExact("GetByAltText", body, !!options.exact);\n      case "placeholder":\n        return this.toCallWithExact("GetByPlaceholder", body, !!options.exact);\n      case "label":\n        return this.toCallWithExact("GetByLabel", body, !!options.exact);\n      case "title":\n        return this.toCallWithExact("GetByTitle", body, !!options.exact);\n      default:\n        throw new Error("Unknown selector kind " + kind);\n    }\n  }\n  chainLocators(locators) {\n    return locators.join(".");\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes("i") ? ", RegexOptions.IgnoreCase" : "";\n    return `new Regex(${this.quote(normalizeEscapedRegexQuotes(body.source))}${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new() { Exact = true })`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return `HasTextRegex = ${this.regexToString(body)}`;\n    return `HasText = ${this.quote(body)}`;\n  }\n  toTestIdValue(value) {\n    if (isRegExp(value))\n      return this.regexToString(value);\n    return this.quote(value);\n  }\n  toHasNotText(body) {\n    if (isRegExp(body))\n      return `HasNotTextRegex = ${this.regexToString(body)}`;\n    return `HasNotText = ${this.quote(body)}`;\n  }\n  quote(text) {\n    return escapeWithQuotes(text, \'"\');\n  }\n};\nvar JsonlLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    return JSON.stringify({\n      kind,\n      body,\n      options\n    });\n  }\n  chainLocators(locators) {\n    const objects = locators.map((l) => JSON.parse(l));\n    for (let i = 0; i < objects.length - 1; ++i)\n      objects[i].next = objects[i + 1];\n    return JSON.stringify(objects[0]);\n  }\n};\nvar generators = {\n  javascript: JavaScriptLocatorFactory,\n  python: PythonLocatorFactory,\n  java: JavaLocatorFactory,\n  csharp: CSharpLocatorFactory,\n  jsonl: JsonlLocatorFactory\n};\nfunction isRegExp(obj) {\n  return obj instanceof RegExp;\n}\n\n// packages/playwright-core/src/utils/isomorphic/yaml.ts\nfunction yamlEscapeKeyIfNeeded(str) {\n  if (!yamlStringNeedsQuotes(str))\n    return str;\n  return `\'` + str.replace(/\'/g, `\'\'`) + `\'`;\n}\nfunction yamlEscapeValueIfNeeded(str) {\n  if (!yamlStringNeedsQuotes(str))\n    return str;\n  return \'"\' + str.replace(/[\\\\"\\x00-\\x1f\\x7f-\\x9f]/g, (c) => {\n    switch (c) {\n      case "\\\\":\n        return "\\\\\\\\";\n      case \'"\':\n        return \'\\\\"\';\n      case "\\b":\n        return "\\\\b";\n      case "\\f":\n        return "\\\\f";\n      case "\\n":\n        return "\\\\n";\n      case "\\r":\n        return "\\\\r";\n      case "	":\n        return "\\\\t";\n      default:\n        const code = c.charCodeAt(0);\n        return "\\\\x" + code.toString(16).padStart(2, "0");\n    }\n  }) + \'"\';\n}\nfunction yamlStringNeedsQuotes(str) {\n  if (str.length === 0)\n    return true;\n  if (/^\\s|\\s$/.test(str))\n    return true;\n  if (/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/.test(str))\n    return true;\n  if (/^-/.test(str))\n    return true;\n  if (/[\\n:](\\s|$)/.test(str))\n    return true;\n  if (/\\s#/.test(str))\n    return true;\n  if (/[\\n\\r]/.test(str))\n    return true;\n  if (/^[&*\\],?!>|@"\'#%]/.test(str))\n    return true;\n  if (/[{}`]/.test(str))\n    return true;\n  if (/^\\[/.test(str))\n    return true;\n  if (!isNaN(Number(str)) || ["y", "n", "yes", "no", "true", "false", "on", "off", "null"].includes(str.toLowerCase()))\n    return true;\n  return false;\n}\n\n// packages/injected/src/domUtils.ts\nvar globalOptions = {};\nfunction setGlobalOptions(options) {\n  globalOptions = options;\n}\nfunction isInsideScope(scope, element) {\n  while (element) {\n    if (scope.contains(element))\n      return true;\n    element = enclosingShadowHost(element);\n  }\n  return false;\n}\nfunction parentElementOrShadowHost(element) {\n  if (element.parentElement)\n    return element.parentElement;\n  if (!element.parentNode)\n    return;\n  if (element.parentNode.nodeType === 11 && element.parentNode.host)\n    return element.parentNode.host;\n}\nfunction enclosingShadowRootOrDocument(element) {\n  let node = element;\n  while (node.parentNode)\n    node = node.parentNode;\n  if (node.nodeType === 11 || node.nodeType === 9)\n    return node;\n}\nfunction enclosingShadowHost(element) {\n  while (element.parentElement)\n    element = element.parentElement;\n  return parentElementOrShadowHost(element);\n}\nfunction closestCrossShadow(element, css, scope) {\n  while (element) {\n    const closest = element.closest(css);\n    if (scope && closest !== scope && (closest == null ? void 0 : closest.contains(scope)))\n      return;\n    if (closest)\n      return closest;\n    element = enclosingShadowHost(element);\n  }\n}\nfunction getElementComputedStyle(element, pseudo) {\n  const cache = pseudo === "::before" ? cacheStyleBefore : pseudo === "::after" ? cacheStyleAfter : cacheStyle;\n  if (cache && cache.has(element))\n    return cache.get(element);\n  const style = element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;\n  cache == null ? void 0 : cache.set(element, style);\n  return style;\n}\nfunction isElementStyleVisibilityVisible(element, style) {\n  style = style != null ? style : getElementComputedStyle(element);\n  if (!style)\n    return true;\n  if (Element.prototype.checkVisibility && globalOptions.browserNameForWorkarounds !== "webkit") {\n    if (!element.checkVisibility())\n      return false;\n  } else {\n    const detailsOrSummary = element.closest("details,summary");\n    if (detailsOrSummary !== element && (detailsOrSummary == null ? void 0 : detailsOrSummary.nodeName) === "DETAILS" && !detailsOrSummary.open)\n      return false;\n  }\n  if (style.visibility !== "visible")\n    return false;\n  return true;\n}\nfunction computeBox(element) {\n  const style = getElementComputedStyle(element);\n  if (!style)\n    return { visible: true, inline: false };\n  const cursor = style.cursor;\n  if (style.display === "contents") {\n    for (let child = element.firstChild; child; child = child.nextSibling) {\n      if (child.nodeType === 1 && isElementVisible(child))\n        return { visible: true, inline: false, cursor };\n      if (child.nodeType === 3 && isVisibleTextNode(child))\n        return { visible: true, inline: true, cursor };\n    }\n    return { visible: false, inline: false, cursor };\n  }\n  if (!isElementStyleVisibilityVisible(element, style))\n    return { cursor, visible: false, inline: false };\n  const rect = element.getBoundingClientRect();\n  return { cursor, visible: rect.width > 0 && rect.height > 0, inline: style.display === "inline" };\n}\nfunction isElementVisible(element) {\n  return computeBox(element).visible;\n}\nfunction isVisibleTextNode(node) {\n  const range = node.ownerDocument.createRange();\n  range.selectNode(node);\n  const rect = range.getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\nfunction elementSafeTagName(element) {\n  const tagName = element.tagName;\n  if (typeof tagName === "string")\n    return tagName.toUpperCase();\n  if (element instanceof HTMLFormElement)\n    return "FORM";\n  return element.tagName.toUpperCase();\n}\nvar cacheStyle;\nvar cacheStyleBefore;\nvar cacheStyleAfter;\nvar cachesCounter = 0;\nfunction beginDOMCaches() {\n  ++cachesCounter;\n  cacheStyle != null ? cacheStyle : cacheStyle = /* @__PURE__ */ new Map();\n  cacheStyleBefore != null ? cacheStyleBefore : cacheStyleBefore = /* @__PURE__ */ new Map();\n  cacheStyleAfter != null ? cacheStyleAfter : cacheStyleAfter = /* @__PURE__ */ new Map();\n}\nfunction endDOMCaches() {\n  if (!--cachesCounter) {\n    cacheStyle = void 0;\n    cacheStyleBefore = void 0;\n    cacheStyleAfter = void 0;\n  }\n}\n\n// packages/injected/src/roleUtils.ts\nfunction hasExplicitAccessibleName(e) {\n  return e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby");\n}\nvar kAncestorPreventingLandmark = "article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]";\nvar kGlobalAriaAttributes = [\n  ["aria-atomic", void 0],\n  ["aria-busy", void 0],\n  ["aria-controls", void 0],\n  ["aria-current", void 0],\n  ["aria-describedby", void 0],\n  ["aria-details", void 0],\n  // Global use deprecated in ARIA 1.2\n  // [\'aria-disabled\', undefined],\n  ["aria-dropeffect", void 0],\n  // Global use deprecated in ARIA 1.2\n  // [\'aria-errormessage\', undefined],\n  ["aria-flowto", void 0],\n  ["aria-grabbed", void 0],\n  // Global use deprecated in ARIA 1.2\n  // [\'aria-haspopup\', undefined],\n  ["aria-hidden", void 0],\n  // Global use deprecated in ARIA 1.2\n  // [\'aria-invalid\', undefined],\n  ["aria-keyshortcuts", void 0],\n  ["aria-label", ["caption", "code", "deletion", "emphasis", "generic", "insertion", "paragraph", "presentation", "strong", "subscript", "superscript"]],\n  ["aria-labelledby", ["caption", "code", "deletion", "emphasis", "generic", "insertion", "paragraph", "presentation", "strong", "subscript", "superscript"]],\n  ["aria-live", void 0],\n  ["aria-owns", void 0],\n  ["aria-relevant", void 0],\n  ["aria-roledescription", ["generic"]]\n];\nfunction hasGlobalAriaAttribute(element, forRole) {\n  return kGlobalAriaAttributes.some(([attr, prohibited]) => {\n    return !(prohibited == null ? void 0 : prohibited.includes(forRole || "")) && element.hasAttribute(attr);\n  });\n}\nfunction hasTabIndex(element) {\n  return !Number.isNaN(Number(String(element.getAttribute("tabindex"))));\n}\nfunction isFocusable(element) {\n  return !isNativelyDisabled(element) && (isNativelyFocusable(element) || hasTabIndex(element));\n}\nfunction isNativelyFocusable(element) {\n  const tagName = elementSafeTagName(element);\n  if (["BUTTON", "DETAILS", "SELECT", "TEXTAREA"].includes(tagName))\n    return true;\n  if (tagName === "A" || tagName === "AREA")\n    return element.hasAttribute("href");\n  if (tagName === "INPUT")\n    return !element.hidden;\n  return false;\n}\nvar kImplicitRoleByTagName = {\n  "A": (e) => {\n    return e.hasAttribute("href") ? "link" : null;\n  },\n  "AREA": (e) => {\n    return e.hasAttribute("href") ? "link" : null;\n  },\n  "ARTICLE": () => "article",\n  "ASIDE": () => "complementary",\n  "BLOCKQUOTE": () => "blockquote",\n  "BUTTON": () => "button",\n  "CAPTION": () => "caption",\n  "CODE": () => "code",\n  "DATALIST": () => "listbox",\n  "DD": () => "definition",\n  "DEL": () => "deletion",\n  "DETAILS": () => "group",\n  "DFN": () => "term",\n  "DIALOG": () => "dialog",\n  "DT": () => "term",\n  "EM": () => "emphasis",\n  "FIELDSET": () => "group",\n  "FIGURE": () => "figure",\n  "FOOTER": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "contentinfo",\n  "FORM": (e) => hasExplicitAccessibleName(e) ? "form" : null,\n  "H1": () => "heading",\n  "H2": () => "heading",\n  "H3": () => "heading",\n  "H4": () => "heading",\n  "H5": () => "heading",\n  "H6": () => "heading",\n  "HEADER": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "banner",\n  "HR": () => "separator",\n  "HTML": () => "document",\n  "IMG": (e) => e.getAttribute("alt") === "" && !e.getAttribute("title") && !hasGlobalAriaAttribute(e) && !hasTabIndex(e) ? "presentation" : "img",\n  "INPUT": (e) => {\n    const type = e.type.toLowerCase();\n    if (type === "search")\n      return e.hasAttribute("list") ? "combobox" : "searchbox";\n    if (["email", "tel", "text", "url", ""].includes(type)) {\n      const list = getIdRefs(e, e.getAttribute("list"))[0];\n      return list && elementSafeTagName(list) === "DATALIST" ? "combobox" : "textbox";\n    }\n    if (type === "hidden")\n      return null;\n    if (type === "file")\n      return "button";\n    return inputTypeToRole[type] || "textbox";\n  },\n  "INS": () => "insertion",\n  "LI": () => "listitem",\n  "MAIN": () => "main",\n  "MARK": () => "mark",\n  "MATH": () => "math",\n  "MENU": () => "list",\n  "METER": () => "meter",\n  "NAV": () => "navigation",\n  "OL": () => "list",\n  "OPTGROUP": () => "group",\n  "OPTION": () => "option",\n  "OUTPUT": () => "status",\n  "P": () => "paragraph",\n  "PROGRESS": () => "progressbar",\n  "SEARCH": () => "search",\n  "SECTION": (e) => hasExplicitAccessibleName(e) ? "region" : null,\n  "SELECT": (e) => e.hasAttribute("multiple") || e.size > 1 ? "listbox" : "combobox",\n  "STRONG": () => "strong",\n  "SUB": () => "subscript",\n  "SUP": () => "superscript",\n  // For <svg> we default to Chrome behavior:\n  // - Chrome reports \'img\'.\n  // - Firefox reports \'diagram\' that is not in official ARIA spec yet.\n  // - Safari reports \'no role\', but still computes accessible name.\n  "SVG": () => "img",\n  "TABLE": () => "table",\n  "TBODY": () => "rowgroup",\n  "TD": (e) => {\n    const table = closestCrossShadow(e, "table");\n    const role = table ? getExplicitAriaRole(table) : "";\n    return role === "grid" || role === "treegrid" ? "gridcell" : "cell";\n  },\n  "TEXTAREA": () => "textbox",\n  "TFOOT": () => "rowgroup",\n  "TH": (e) => {\n    const scope = e.getAttribute("scope");\n    if (scope === "col" || scope === "colgroup")\n      return "columnheader";\n    if (scope === "row" || scope === "rowgroup")\n      return "rowheader";\n    const nextSibling = e.nextElementSibling;\n    const prevSibling = e.previousElementSibling;\n    const row = !!e.parentElement && elementSafeTagName(e.parentElement) === "TR" ? e.parentElement : void 0;\n    if (!nextSibling && !prevSibling) {\n      if (row) {\n        const table = closestCrossShadow(row, "table");\n        if (table && table.rows.length <= 1)\n          return null;\n      }\n      return "columnheader";\n    }\n    if (isHeaderCell(nextSibling) && isHeaderCell(prevSibling))\n      return "columnheader";\n    if (isNonEmptyDataCell(nextSibling) || isNonEmptyDataCell(prevSibling))\n      return "rowheader";\n    return "columnheader";\n  },\n  "THEAD": () => "rowgroup",\n  "TIME": () => "time",\n  "TR": () => "row",\n  "UL": () => "list"\n};\nfunction isHeaderCell(element) {\n  return !!element && elementSafeTagName(element) === "TH";\n}\nfunction isNonEmptyDataCell(element) {\n  var _a;\n  if (!element || elementSafeTagName(element) !== "TD")\n    return false;\n  return !!(((_a = element.textContent) == null ? void 0 : _a.trim()) || element.children.length > 0);\n}\nvar kPresentationInheritanceParents = {\n  "DD": ["DL", "DIV"],\n  "DIV": ["DL"],\n  "DT": ["DL", "DIV"],\n  "LI": ["OL", "UL"],\n  "TBODY": ["TABLE"],\n  "TD": ["TR"],\n  "TFOOT": ["TABLE"],\n  "TH": ["TR"],\n  "THEAD": ["TABLE"],\n  "TR": ["THEAD", "TBODY", "TFOOT", "TABLE"]\n};\nfunction getImplicitAriaRole(element) {\n  var _a;\n  const implicitRole = ((_a = kImplicitRoleByTagName[elementSafeTagName(element)]) == null ? void 0 : _a.call(kImplicitRoleByTagName, element)) || "";\n  if (!implicitRole)\n    return null;\n  let ancestor = element;\n  while (ancestor) {\n    const parent = parentElementOrShadowHost(ancestor);\n    const parents = kPresentationInheritanceParents[elementSafeTagName(ancestor)];\n    if (!parents || !parent || !parents.includes(elementSafeTagName(parent)))\n      break;\n    const parentExplicitRole = getExplicitAriaRole(parent);\n    if ((parentExplicitRole === "none" || parentExplicitRole === "presentation") && !hasPresentationConflictResolution(parent, parentExplicitRole))\n      return parentExplicitRole;\n    ancestor = parent;\n  }\n  return implicitRole;\n}\nvar validRoles = [\n  "alert",\n  "alertdialog",\n  "application",\n  "article",\n  "banner",\n  "blockquote",\n  "button",\n  "caption",\n  "cell",\n  "checkbox",\n  "code",\n  "columnheader",\n  "combobox",\n  "complementary",\n  "contentinfo",\n  "definition",\n  "deletion",\n  "dialog",\n  "directory",\n  "document",\n  "emphasis",\n  "feed",\n  "figure",\n  "form",\n  "generic",\n  "grid",\n  "gridcell",\n  "group",\n  "heading",\n  "img",\n  "insertion",\n  "link",\n  "list",\n  "listbox",\n  "listitem",\n  "log",\n  "main",\n  "mark",\n  "marquee",\n  "math",\n  "meter",\n  "menu",\n  "menubar",\n  "menuitem",\n  "menuitemcheckbox",\n  "menuitemradio",\n  "navigation",\n  "none",\n  "note",\n  "option",\n  "paragraph",\n  "presentation",\n  "progressbar",\n  "radio",\n  "radiogroup",\n  "region",\n  "row",\n  "rowgroup",\n  "rowheader",\n  "scrollbar",\n  "search",\n  "searchbox",\n  "separator",\n  "slider",\n  "spinbutton",\n  "status",\n  "strong",\n  "subscript",\n  "superscript",\n  "switch",\n  "tab",\n  "table",\n  "tablist",\n  "tabpanel",\n  "term",\n  "textbox",\n  "time",\n  "timer",\n  "toolbar",\n  "tooltip",\n  "tree",\n  "treegrid",\n  "treeitem"\n];\nfunction getExplicitAriaRole(element) {\n  const roles = (element.getAttribute("role") || "").split(" ").map((role) => role.trim());\n  return roles.find((role) => validRoles.includes(role)) || null;\n}\nfunction hasPresentationConflictResolution(element, role) {\n  return hasGlobalAriaAttribute(element, role) || isFocusable(element);\n}\nfunction getAriaRole(element) {\n  const explicitRole = getExplicitAriaRole(element);\n  if (!explicitRole)\n    return getImplicitAriaRole(element);\n  if (explicitRole === "none" || explicitRole === "presentation") {\n    const implicitRole = getImplicitAriaRole(element);\n    if (hasPresentationConflictResolution(element, implicitRole))\n      return implicitRole;\n  }\n  return explicitRole;\n}\nfunction getAriaBoolean(attr) {\n  return attr === null ? void 0 : attr.toLowerCase() === "true";\n}\nfunction isElementIgnoredForAria(element) {\n  return ["STYLE", "SCRIPT", "NOSCRIPT", "TEMPLATE"].includes(elementSafeTagName(element));\n}\nfunction isElementHiddenForAria(element) {\n  if (isElementIgnoredForAria(element))\n    return true;\n  const style = getElementComputedStyle(element);\n  const isSlot = element.nodeName === "SLOT";\n  if ((style == null ? void 0 : style.display) === "contents" && !isSlot) {\n    for (let child = element.firstChild; child; child = child.nextSibling) {\n      if (child.nodeType === 1 && !isElementHiddenForAria(child))\n        return false;\n      if (child.nodeType === 3 && isVisibleTextNode(child))\n        return false;\n    }\n    return true;\n  }\n  const isOptionInsideSelect = element.nodeName === "OPTION" && !!element.closest("select");\n  if (!isOptionInsideSelect && !isSlot && !isElementStyleVisibilityVisible(element, style))\n    return true;\n  return belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element);\n}\nfunction belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element) {\n  let hidden = cacheIsHidden == null ? void 0 : cacheIsHidden.get(element);\n  if (hidden === void 0) {\n    hidden = false;\n    if (element.parentElement && element.parentElement.shadowRoot && !element.assignedSlot)\n      hidden = true;\n    if (!hidden) {\n      const style = getElementComputedStyle(element);\n      hidden = !style || style.display === "none" || getAriaBoolean(element.getAttribute("aria-hidden")) === true;\n    }\n    if (!hidden) {\n      const parent = parentElementOrShadowHost(element);\n      if (parent)\n        hidden = belongsToDisplayNoneOrAriaHiddenOrNonSlotted(parent);\n    }\n    cacheIsHidden == null ? void 0 : cacheIsHidden.set(element, hidden);\n  }\n  return hidden;\n}\nfunction getIdRefs(element, ref) {\n  if (!ref)\n    return [];\n  const root = enclosingShadowRootOrDocument(element);\n  if (!root)\n    return [];\n  try {\n    const ids = ref.split(" ").filter((id) => !!id);\n    const result = [];\n    for (const id of ids) {\n      const firstElement = root.querySelector("#" + CSS.escape(id));\n      if (firstElement && !result.includes(firstElement))\n        result.push(firstElement);\n    }\n    return result;\n  } catch (e) {\n    return [];\n  }\n}\nfunction trimFlatString(s) {\n  return s.trim();\n}\nfunction asFlatString(s) {\n  return s.split("\\xA0").map((chunk) => chunk.replace(/\\r\\n/g, "\\n").replace(/[\\u200b\\u00ad]/g, "").replace(/\\s\\s*/g, " ")).join("\\xA0").trim();\n}\nfunction queryInAriaOwned(element, selector) {\n  const result = [...element.querySelectorAll(selector)];\n  for (const owned of getIdRefs(element, element.getAttribute("aria-owns"))) {\n    if (owned.matches(selector))\n      result.push(owned);\n    result.push(...owned.querySelectorAll(selector));\n  }\n  return result;\n}\nfunction getCSSContent(element, pseudo) {\n  const cache = pseudo === "::before" ? cachePseudoContentBefore : pseudo === "::after" ? cachePseudoContentAfter : cachePseudoContent;\n  if (cache == null ? void 0 : cache.has(element))\n    return cache == null ? void 0 : cache.get(element);\n  const style = getElementComputedStyle(element, pseudo);\n  let content;\n  if (style) {\n    const contentValue = style.content;\n    if (contentValue && contentValue !== "none" && contentValue !== "normal") {\n      if (style.display !== "none" && style.visibility !== "hidden") {\n        content = parseCSSContentPropertyAsString(element, contentValue, !!pseudo);\n      }\n    }\n  }\n  if (pseudo && content !== void 0) {\n    const display = (style == null ? void 0 : style.display) || "inline";\n    if (display !== "inline")\n      content = " " + content + " ";\n  }\n  if (cache)\n    cache.set(element, content);\n  return content;\n}\nfunction parseCSSContentPropertyAsString(element, content, isPseudo) {\n  if (!content || content === "none" || content === "normal") {\n    return;\n  }\n  try {\n    let tokens = tokenize(content).filter((token) => !(token instanceof WhitespaceToken));\n    const delimIndex = tokens.findIndex((token) => token instanceof DelimToken && token.value === "/");\n    if (delimIndex !== -1) {\n      tokens = tokens.slice(delimIndex + 1);\n    } else if (!isPseudo) {\n      return;\n    }\n    const accumulated = [];\n    let index = 0;\n    while (index < tokens.length) {\n      if (tokens[index] instanceof StringToken) {\n        accumulated.push(tokens[index].value);\n        index++;\n      } else if (index + 2 < tokens.length && tokens[index] instanceof FunctionToken && tokens[index].value === "attr" && tokens[index + 1] instanceof IdentToken && tokens[index + 2] instanceof CloseParenToken) {\n        const attrName = tokens[index + 1].value;\n        accumulated.push(element.getAttribute(attrName) || "");\n        index += 3;\n      } else {\n        return;\n      }\n    }\n    return accumulated.join("");\n  } catch {\n  }\n}\nfunction getAriaLabelledByElements(element) {\n  const ref = element.getAttribute("aria-labelledby");\n  if (ref === null)\n    return null;\n  const refs = getIdRefs(element, ref);\n  return refs.length ? refs : null;\n}\nfunction allowsNameFromContent(role, targetDescendant) {\n  const alwaysAllowsNameFromContent = ["button", "cell", "checkbox", "columnheader", "gridcell", "heading", "link", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "row", "rowheader", "switch", "tab", "tooltip", "treeitem"].includes(role);\n  const descendantAllowsNameFromContent = targetDescendant && ["", "caption", "code", "contentinfo", "definition", "deletion", "emphasis", "insertion", "list", "listitem", "mark", "none", "paragraph", "presentation", "region", "row", "rowgroup", "section", "strong", "subscript", "superscript", "table", "term", "time"].includes(role);\n  return alwaysAllowsNameFromContent || descendantAllowsNameFromContent;\n}\nfunction getElementAccessibleName(element, includeHidden) {\n  const cache = includeHidden ? cacheAccessibleNameHidden : cacheAccessibleName;\n  let accessibleName = cache == null ? void 0 : cache.get(element);\n  if (accessibleName === void 0) {\n    accessibleName = "";\n    const elementProhibitsNaming = ["caption", "code", "definition", "deletion", "emphasis", "generic", "insertion", "mark", "paragraph", "presentation", "strong", "subscript", "suggestion", "superscript", "term", "time"].includes(getAriaRole(element) || "");\n    if (!elementProhibitsNaming) {\n      accessibleName = asFlatString(getTextAlternativeInternal(element, {\n        includeHidden,\n        visitedElements: /* @__PURE__ */ new Set(),\n        embeddedInTargetElement: "self"\n      }));\n    }\n    cache == null ? void 0 : cache.set(element, accessibleName);\n  }\n  return accessibleName;\n}\nfunction getElementAccessibleDescription(element, includeHidden) {\n  const cache = includeHidden ? cacheAccessibleDescriptionHidden : cacheAccessibleDescription;\n  let accessibleDescription = cache == null ? void 0 : cache.get(element);\n  if (accessibleDescription === void 0) {\n    accessibleDescription = "";\n    if (element.hasAttribute("aria-describedby")) {\n      const describedBy = getIdRefs(element, element.getAttribute("aria-describedby"));\n      accessibleDescription = asFlatString(describedBy.map((ref) => getTextAlternativeInternal(ref, {\n        includeHidden,\n        visitedElements: /* @__PURE__ */ new Set(),\n        embeddedInDescribedBy: { element: ref, hidden: isElementHiddenForAria(ref) }\n      })).join(" "));\n    } else if (element.hasAttribute("aria-description")) {\n      accessibleDescription = asFlatString(element.getAttribute("aria-description") || "");\n    } else {\n      accessibleDescription = asFlatString(element.getAttribute("title") || "");\n    }\n    cache == null ? void 0 : cache.set(element, accessibleDescription);\n  }\n  return accessibleDescription;\n}\nfunction getAriaInvalid(element) {\n  const ariaInvalid = element.getAttribute("aria-invalid");\n  if (!ariaInvalid || ariaInvalid.trim() === "" || ariaInvalid.toLocaleLowerCase() === "false")\n    return "false";\n  if (ariaInvalid === "true" || ariaInvalid === "grammar" || ariaInvalid === "spelling")\n    return ariaInvalid;\n  return "true";\n}\nfunction getValidityInvalid(element) {\n  if ("validity" in element) {\n    const validity = element.validity;\n    return (validity == null ? void 0 : validity.valid) === false;\n  }\n  return false;\n}\nfunction getElementAccessibleErrorMessage(element) {\n  const cache = cacheAccessibleErrorMessage;\n  let accessibleErrorMessage = cacheAccessibleErrorMessage == null ? void 0 : cacheAccessibleErrorMessage.get(element);\n  if (accessibleErrorMessage === void 0) {\n    accessibleErrorMessage = "";\n    const isAriaInvalid = getAriaInvalid(element) !== "false";\n    const isValidityInvalid = getValidityInvalid(element);\n    if (isAriaInvalid || isValidityInvalid) {\n      const errorMessageId = element.getAttribute("aria-errormessage");\n      const errorMessages = getIdRefs(element, errorMessageId);\n      const parts = errorMessages.map((errorMessage) => asFlatString(\n        getTextAlternativeInternal(errorMessage, {\n          visitedElements: /* @__PURE__ */ new Set(),\n          embeddedInDescribedBy: { element: errorMessage, hidden: isElementHiddenForAria(errorMessage) }\n        })\n      ));\n      accessibleErrorMessage = parts.join(" ").trim();\n    }\n    cache == null ? void 0 : cache.set(element, accessibleErrorMessage);\n  }\n  return accessibleErrorMessage;\n}\nfunction getTextAlternativeInternal(element, options) {\n  var _a, _b, _c, _d;\n  if (options.visitedElements.has(element))\n    return "";\n  const childOptions = {\n    ...options,\n    embeddedInTargetElement: options.embeddedInTargetElement === "self" ? "descendant" : options.embeddedInTargetElement\n  };\n  if (!options.includeHidden) {\n    const isEmbeddedInHiddenReferenceTraversal = !!((_a = options.embeddedInLabelledBy) == null ? void 0 : _a.hidden) || !!((_b = options.embeddedInDescribedBy) == null ? void 0 : _b.hidden) || !!((_c = options.embeddedInNativeTextAlternative) == null ? void 0 : _c.hidden) || !!((_d = options.embeddedInLabel) == null ? void 0 : _d.hidden);\n    if (isElementIgnoredForAria(element) || !isEmbeddedInHiddenReferenceTraversal && isElementHiddenForAria(element)) {\n      options.visitedElements.add(element);\n      return "";\n    }\n  }\n  const labelledBy = getAriaLabelledByElements(element);\n  if (!options.embeddedInLabelledBy) {\n    const accessibleName = (labelledBy || []).map((ref) => getTextAlternativeInternal(ref, {\n      ...options,\n      embeddedInLabelledBy: { element: ref, hidden: isElementHiddenForAria(ref) },\n      embeddedInDescribedBy: void 0,\n      embeddedInTargetElement: void 0,\n      embeddedInLabel: void 0,\n      embeddedInNativeTextAlternative: void 0\n    })).join(" ");\n    if (accessibleName)\n      return accessibleName;\n  }\n  const role = getAriaRole(element) || "";\n  const tagName = elementSafeTagName(element);\n  if (!!options.embeddedInLabel || !!options.embeddedInLabelledBy || options.embeddedInTargetElement === "descendant") {\n    const isOwnLabel = [...element.labels || []].includes(element);\n    const isOwnLabelledBy = (labelledBy || []).includes(element);\n    if (!isOwnLabel && !isOwnLabelledBy) {\n      if (role === "textbox") {\n        options.visitedElements.add(element);\n        if (tagName === "INPUT" || tagName === "TEXTAREA")\n          return element.value;\n        return element.textContent || "";\n      }\n      if (["combobox", "listbox"].includes(role)) {\n        options.visitedElements.add(element);\n        let selectedOptions;\n        if (tagName === "SELECT") {\n          selectedOptions = [...element.selectedOptions];\n          if (!selectedOptions.length && element.options.length)\n            selectedOptions.push(element.options[0]);\n        } else {\n          const listbox = role === "combobox" ? queryInAriaOwned(element, "*").find((e) => getAriaRole(e) === "listbox") : element;\n          selectedOptions = listbox ? queryInAriaOwned(listbox, \'[aria-selected="true"]\').filter((e) => getAriaRole(e) === "option") : [];\n        }\n        if (!selectedOptions.length && tagName === "INPUT") {\n          return element.value;\n        }\n        return selectedOptions.map((option) => getTextAlternativeInternal(option, childOptions)).join(" ");\n      }\n      if (["progressbar", "scrollbar", "slider", "spinbutton", "meter"].includes(role)) {\n        options.visitedElements.add(element);\n        if (element.hasAttribute("aria-valuetext"))\n          return element.getAttribute("aria-valuetext") || "";\n        if (element.hasAttribute("aria-valuenow"))\n          return element.getAttribute("aria-valuenow") || "";\n        return element.getAttribute("value") || "";\n      }\n      if (["menu"].includes(role)) {\n        options.visitedElements.add(element);\n        return "";\n      }\n    }\n  }\n  const ariaLabel = element.getAttribute("aria-label") || "";\n  if (trimFlatString(ariaLabel)) {\n    options.visitedElements.add(element);\n    return ariaLabel;\n  }\n  if (!["presentation", "none"].includes(role)) {\n    if (tagName === "INPUT" && ["button", "submit", "reset"].includes(element.type)) {\n      options.visitedElements.add(element);\n      const value = element.value || "";\n      if (trimFlatString(value))\n        return value;\n      if (element.type === "submit")\n        return "Submit";\n      if (element.type === "reset")\n        return "Reset";\n      const title = element.getAttribute("title") || "";\n      return title;\n    }\n    if (tagName === "INPUT" && element.type === "file") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length && !options.embeddedInLabelledBy)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      return "Choose File";\n    }\n    if (tagName === "INPUT" && element.type === "image") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length && !options.embeddedInLabelledBy)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const alt = element.getAttribute("alt") || "";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute("title") || "";\n      if (trimFlatString(title))\n        return title;\n      return "Submit";\n    }\n    if (!labelledBy && tagName === "BUTTON") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n    }\n    if (!labelledBy && tagName === "OUTPUT") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      return element.getAttribute("title") || "";\n    }\n    if (!labelledBy && (tagName === "TEXTAREA" || tagName === "SELECT" || tagName === "INPUT")) {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const usePlaceholder = tagName === "INPUT" && ["text", "password", "search", "tel", "email", "url"].includes(element.type) || tagName === "TEXTAREA";\n      const placeholder = element.getAttribute("placeholder") || "";\n      const title = element.getAttribute("title") || "";\n      if (!usePlaceholder || title)\n        return title;\n      return placeholder;\n    }\n    if (!labelledBy && tagName === "FIELDSET") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === "LEGEND") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute("title") || "";\n      return title;\n    }\n    if (!labelledBy && tagName === "FIGURE") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === "FIGCAPTION") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute("title") || "";\n      return title;\n    }\n    if (tagName === "IMG") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute("alt") || "";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute("title") || "";\n      return title;\n    }\n    if (tagName === "TABLE") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === "CAPTION") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const summary = element.getAttribute("summary") || "";\n      if (summary)\n        return summary;\n    }\n    if (tagName === "AREA") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute("alt") || "";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute("title") || "";\n      return title;\n    }\n    if (tagName === "SVG" || element.ownerSVGElement) {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === "TITLE" && child.ownerSVGElement) {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInLabelledBy: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n    }\n    if (element.ownerSVGElement && tagName === "A") {\n      const title = element.getAttribute("xlink:title") || "";\n      if (trimFlatString(title)) {\n        options.visitedElements.add(element);\n        return title;\n      }\n    }\n  }\n  const shouldNameFromContentForSummary = tagName === "SUMMARY" && !["presentation", "none"].includes(role);\n  if (allowsNameFromContent(role, options.embeddedInTargetElement === "descendant") || shouldNameFromContentForSummary || !!options.embeddedInLabelledBy || !!options.embeddedInDescribedBy || !!options.embeddedInLabel || !!options.embeddedInNativeTextAlternative) {\n    options.visitedElements.add(element);\n    const accessibleName = innerAccumulatedElementText(element, childOptions);\n    const maybeTrimmedAccessibleName = options.embeddedInTargetElement === "self" ? trimFlatString(accessibleName) : accessibleName;\n    if (maybeTrimmedAccessibleName)\n      return accessibleName;\n  }\n  if (!["presentation", "none"].includes(role) || tagName === "IFRAME") {\n    options.visitedElements.add(element);\n    const title = element.getAttribute("title") || "";\n    if (trimFlatString(title))\n      return title;\n  }\n  options.visitedElements.add(element);\n  return "";\n}\nfunction innerAccumulatedElementText(element, options) {\n  const tokens = [];\n  const visit = (node, skipSlotted) => {\n    var _a;\n    if (skipSlotted && node.assignedSlot)\n      return;\n    if (node.nodeType === 1) {\n      const display = ((_a = getElementComputedStyle(node)) == null ? void 0 : _a.display) || "inline";\n      let token = getTextAlternativeInternal(node, options);\n      if (display !== "inline" || node.nodeName === "BR")\n        token = " " + token + " ";\n      tokens.push(token);\n    } else if (node.nodeType === 3) {\n      tokens.push(node.textContent || "");\n    }\n  };\n  tokens.push(getCSSContent(element, "::before") || "");\n  const content = getCSSContent(element);\n  if (content !== void 0) {\n    tokens.push(content);\n  } else {\n    const assignedNodes = element.nodeName === "SLOT" ? element.assignedNodes() : [];\n    if (assignedNodes.length) {\n      for (const child of assignedNodes)\n        visit(child, false);\n    } else {\n      for (let child = element.firstChild; child; child = child.nextSibling)\n        visit(child, true);\n      if (element.shadowRoot) {\n        for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n          visit(child, true);\n      }\n      for (const owned of getIdRefs(element, element.getAttribute("aria-owns")))\n        visit(owned, true);\n    }\n  }\n  tokens.push(getCSSContent(element, "::after") || "");\n  return tokens.join("");\n}\nvar kAriaSelectedRoles = ["gridcell", "option", "row", "tab", "rowheader", "columnheader", "treeitem"];\nfunction getAriaSelected(element) {\n  if (elementSafeTagName(element) === "OPTION")\n    return element.selected;\n  if (kAriaSelectedRoles.includes(getAriaRole(element) || ""))\n    return getAriaBoolean(element.getAttribute("aria-selected")) === true;\n  return false;\n}\nvar kAriaCheckedRoles = ["checkbox", "menuitemcheckbox", "option", "radio", "switch", "menuitemradio", "treeitem"];\nfunction getAriaChecked(element) {\n  const result = getChecked(element, true);\n  return result === "error" ? false : result;\n}\nfunction getCheckedAllowMixed(element) {\n  return getChecked(element, true);\n}\nfunction getCheckedWithoutMixed(element) {\n  const result = getChecked(element, false);\n  return result;\n}\nfunction getChecked(element, allowMixed) {\n  const tagName = elementSafeTagName(element);\n  if (allowMixed && tagName === "INPUT" && element.indeterminate)\n    return "mixed";\n  if (tagName === "INPUT" && ["checkbox", "radio"].includes(element.type))\n    return element.checked;\n  if (kAriaCheckedRoles.includes(getAriaRole(element) || "")) {\n    const checked = element.getAttribute("aria-checked");\n    if (checked === "true")\n      return true;\n    if (allowMixed && checked === "mixed")\n      return "mixed";\n    return false;\n  }\n  return "error";\n}\nvar kAriaReadonlyRoles = ["checkbox", "combobox", "grid", "gridcell", "listbox", "radiogroup", "slider", "spinbutton", "textbox", "columnheader", "rowheader", "searchbox", "switch", "treegrid"];\nfunction getReadonly(element) {\n  const tagName = elementSafeTagName(element);\n  if (["INPUT", "TEXTAREA", "SELECT"].includes(tagName))\n    return element.hasAttribute("readonly");\n  if (kAriaReadonlyRoles.includes(getAriaRole(element) || ""))\n    return element.getAttribute("aria-readonly") === "true";\n  if (element.isContentEditable)\n    return false;\n  return "error";\n}\nvar kAriaPressedRoles = ["button"];\nfunction getAriaPressed(element) {\n  if (kAriaPressedRoles.includes(getAriaRole(element) || "")) {\n    const pressed = element.getAttribute("aria-pressed");\n    if (pressed === "true")\n      return true;\n    if (pressed === "mixed")\n      return "mixed";\n  }\n  return false;\n}\nvar kAriaExpandedRoles = ["application", "button", "checkbox", "combobox", "gridcell", "link", "listbox", "menuitem", "row", "rowheader", "tab", "treeitem", "columnheader", "menuitemcheckbox", "menuitemradio", "rowheader", "switch"];\nfunction getAriaExpanded(element) {\n  if (elementSafeTagName(element) === "DETAILS")\n    return element.open;\n  if (kAriaExpandedRoles.includes(getAriaRole(element) || "")) {\n    const expanded = element.getAttribute("aria-expanded");\n    if (expanded === null)\n      return void 0;\n    if (expanded === "true")\n      return true;\n    return false;\n  }\n  return void 0;\n}\nvar kAriaLevelRoles = ["heading", "listitem", "row", "treeitem"];\nfunction getAriaLevel(element) {\n  const native = { "H1": 1, "H2": 2, "H3": 3, "H4": 4, "H5": 5, "H6": 6 }[elementSafeTagName(element)];\n  if (native)\n    return native;\n  if (kAriaLevelRoles.includes(getAriaRole(element) || "")) {\n    const attr = element.getAttribute("aria-level");\n    const value = attr === null ? Number.NaN : Number(attr);\n    if (Number.isInteger(value) && value >= 1)\n      return value;\n  }\n  return 0;\n}\nvar kAriaDisabledRoles = ["application", "button", "composite", "gridcell", "group", "input", "link", "menuitem", "scrollbar", "separator", "tab", "checkbox", "columnheader", "combobox", "grid", "listbox", "menu", "menubar", "menuitemcheckbox", "menuitemradio", "option", "radio", "radiogroup", "row", "rowheader", "searchbox", "select", "slider", "spinbutton", "switch", "tablist", "textbox", "toolbar", "tree", "treegrid", "treeitem"];\nfunction getAriaDisabled(element) {\n  return isNativelyDisabled(element) || hasExplicitAriaDisabled(element);\n}\nfunction isNativelyDisabled(element) {\n  const isNativeFormControl = ["BUTTON", "INPUT", "SELECT", "TEXTAREA", "OPTION", "OPTGROUP"].includes(elementSafeTagName(element));\n  return isNativeFormControl && (element.hasAttribute("disabled") || belongsToDisabledOptGroup(element) || belongsToDisabledFieldSet(element));\n}\nfunction belongsToDisabledOptGroup(element) {\n  return elementSafeTagName(element) === "OPTION" && !!element.closest("OPTGROUP[DISABLED]");\n}\nfunction belongsToDisabledFieldSet(element) {\n  const fieldSetElement = element == null ? void 0 : element.closest("FIELDSET[DISABLED]");\n  if (!fieldSetElement)\n    return false;\n  const legendElement = fieldSetElement.querySelector(":scope > LEGEND");\n  return !legendElement || !legendElement.contains(element);\n}\nfunction hasExplicitAriaDisabled(element, isAncestor = false) {\n  if (!element)\n    return false;\n  if (isAncestor || kAriaDisabledRoles.includes(getAriaRole(element) || "")) {\n    const attribute = (element.getAttribute("aria-disabled") || "").toLowerCase();\n    if (attribute === "true")\n      return true;\n    if (attribute === "false")\n      return false;\n    return hasExplicitAriaDisabled(parentElementOrShadowHost(element), true);\n  }\n  return false;\n}\nfunction getAccessibleNameFromAssociatedLabels(labels, options) {\n  return [...labels].map((label) => getTextAlternativeInternal(label, {\n    ...options,\n    embeddedInLabel: { element: label, hidden: isElementHiddenForAria(label) },\n    embeddedInNativeTextAlternative: void 0,\n    embeddedInLabelledBy: void 0,\n    embeddedInDescribedBy: void 0,\n    embeddedInTargetElement: void 0\n  })).filter((accessibleName) => !!accessibleName).join(" ");\n}\nfunction receivesPointerEvents(element) {\n  const cache = cachePointerEvents;\n  let e = element;\n  let result;\n  const parents = [];\n  for (; e; e = parentElementOrShadowHost(e)) {\n    const cached = cache.get(e);\n    if (cached !== void 0) {\n      result = cached;\n      break;\n    }\n    parents.push(e);\n    const style = getElementComputedStyle(e);\n    if (!style) {\n      result = true;\n      break;\n    }\n    const value = style.pointerEvents;\n    if (value) {\n      result = value !== "none";\n      break;\n    }\n  }\n  if (result === void 0)\n    result = true;\n  for (const parent of parents)\n    cache.set(parent, result);\n  return result;\n}\nvar cacheAccessibleName;\nvar cacheAccessibleNameHidden;\nvar cacheAccessibleDescription;\nvar cacheAccessibleDescriptionHidden;\nvar cacheAccessibleErrorMessage;\nvar cacheIsHidden;\nvar cachePseudoContent;\nvar cachePseudoContentBefore;\nvar cachePseudoContentAfter;\nvar cachePointerEvents;\nvar cachesCounter2 = 0;\nfunction beginAriaCaches() {\n  beginDOMCaches();\n  ++cachesCounter2;\n  cacheAccessibleName != null ? cacheAccessibleName : cacheAccessibleName = /* @__PURE__ */ new Map();\n  cacheAccessibleNameHidden != null ? cacheAccessibleNameHidden : cacheAccessibleNameHidden = /* @__PURE__ */ new Map();\n  cacheAccessibleDescription != null ? cacheAccessibleDescription : cacheAccessibleDescription = /* @__PURE__ */ new Map();\n  cacheAccessibleDescriptionHidden != null ? cacheAccessibleDescriptionHidden : cacheAccessibleDescriptionHidden = /* @__PURE__ */ new Map();\n  cacheAccessibleErrorMessage != null ? cacheAccessibleErrorMessage : cacheAccessibleErrorMessage = /* @__PURE__ */ new Map();\n  cacheIsHidden != null ? cacheIsHidden : cacheIsHidden = /* @__PURE__ */ new Map();\n  cachePseudoContent != null ? cachePseudoContent : cachePseudoContent = /* @__PURE__ */ new Map();\n  cachePseudoContentBefore != null ? cachePseudoContentBefore : cachePseudoContentBefore = /* @__PURE__ */ new Map();\n  cachePseudoContentAfter != null ? cachePseudoContentAfter : cachePseudoContentAfter = /* @__PURE__ */ new Map();\n  cachePointerEvents != null ? cachePointerEvents : cachePointerEvents = /* @__PURE__ */ new Map();\n}\nfunction endAriaCaches() {\n  if (!--cachesCounter2) {\n    cacheAccessibleName = void 0;\n    cacheAccessibleNameHidden = void 0;\n    cacheAccessibleDescription = void 0;\n    cacheAccessibleDescriptionHidden = void 0;\n    cacheAccessibleErrorMessage = void 0;\n    cacheIsHidden = void 0;\n    cachePseudoContent = void 0;\n    cachePseudoContentBefore = void 0;\n    cachePseudoContentAfter = void 0;\n    cachePointerEvents = void 0;\n  }\n  endDOMCaches();\n}\nvar inputTypeToRole = {\n  "button": "button",\n  "checkbox": "checkbox",\n  "image": "button",\n  "number": "spinbutton",\n  "radio": "radio",\n  "range": "slider",\n  "reset": "button",\n  "submit": "button"\n};\n\n// packages/injected/src/ariaSnapshot.ts\nvar lastRef = 0;\nfunction toInternalOptions(options) {\n  if (options.mode === "ai") {\n    return {\n      visibility: "ariaOrVisible",\n      refs: "interactable",\n      refPrefix: options.refPrefix,\n      includeGenericRole: true,\n      renderActive: !options.doNotRenderActive,\n      renderCursorPointer: true\n    };\n  }\n  if (options.mode === "autoexpect") {\n    return { visibility: "ariaAndVisible", refs: "none" };\n  }\n  if (options.mode === "codegen") {\n    return { visibility: "aria", refs: "none", renderStringsAsRegex: true };\n  }\n  return { visibility: "aria", refs: "none" };\n}\nfunction generateAriaTree(rootElement, publicOptions) {\n  const options = toInternalOptions(publicOptions);\n  const visited = /* @__PURE__ */ new Set();\n  const snapshot = {\n    root: { role: "fragment", name: "", children: [], props: {}, box: computeBox(rootElement), receivesPointerEvents: true },\n    elements: /* @__PURE__ */ new Map(),\n    refs: /* @__PURE__ */ new Map(),\n    iframeRefs: []\n  };\n  setAriaNodeElement(snapshot.root, rootElement);\n  const visit = (ariaNode, node, parentElementVisible) => {\n    if (visited.has(node))\n      return;\n    visited.add(node);\n    if (node.nodeType === Node.TEXT_NODE && node.nodeValue) {\n      if (!parentElementVisible)\n        return;\n      const text = node.nodeValue;\n      if (ariaNode.role !== "textbox" && text)\n        ariaNode.children.push(node.nodeValue || "");\n      return;\n    }\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return;\n    const element = node;\n    const isElementVisibleForAria = !isElementHiddenForAria(element);\n    let visible = isElementVisibleForAria;\n    if (options.visibility === "ariaOrVisible")\n      visible = isElementVisibleForAria || isElementVisible(element);\n    if (options.visibility === "ariaAndVisible")\n      visible = isElementVisibleForAria && isElementVisible(element);\n    if (options.visibility === "aria" && !visible)\n      return;\n    const ariaChildren = [];\n    if (element.hasAttribute("aria-owns")) {\n      const ids = element.getAttribute("aria-owns").split(/\\s+/);\n      for (const id of ids) {\n        const ownedElement = rootElement.ownerDocument.getElementById(id);\n        if (ownedElement)\n          ariaChildren.push(ownedElement);\n      }\n    }\n    const childAriaNode = visible ? toAriaNode(element, options) : null;\n    if (childAriaNode) {\n      if (childAriaNode.ref) {\n        snapshot.elements.set(childAriaNode.ref, element);\n        snapshot.refs.set(element, childAriaNode.ref);\n        if (childAriaNode.role === "iframe")\n          snapshot.iframeRefs.push(childAriaNode.ref);\n      }\n      ariaNode.children.push(childAriaNode);\n    }\n    processElement(childAriaNode || ariaNode, element, ariaChildren, visible);\n  };\n  function processElement(ariaNode, element, ariaChildren, parentElementVisible) {\n    var _a;\n    const display = ((_a = getElementComputedStyle(element)) == null ? void 0 : _a.display) || "inline";\n    const treatAsBlock = display !== "inline" || element.nodeName === "BR" ? " " : "";\n    if (treatAsBlock)\n      ariaNode.children.push(treatAsBlock);\n    ariaNode.children.push(getCSSContent(element, "::before") || "");\n    const assignedNodes = element.nodeName === "SLOT" ? element.assignedNodes() : [];\n    if (assignedNodes.length) {\n      for (const child of assignedNodes)\n        visit(ariaNode, child, parentElementVisible);\n    } else {\n      for (let child = element.firstChild; child; child = child.nextSibling) {\n        if (!child.assignedSlot)\n          visit(ariaNode, child, parentElementVisible);\n      }\n      if (element.shadowRoot) {\n        for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n          visit(ariaNode, child, parentElementVisible);\n      }\n    }\n    for (const child of ariaChildren)\n      visit(ariaNode, child, parentElementVisible);\n    ariaNode.children.push(getCSSContent(element, "::after") || "");\n    if (treatAsBlock)\n      ariaNode.children.push(treatAsBlock);\n    if (ariaNode.children.length === 1 && ariaNode.name === ariaNode.children[0])\n      ariaNode.children = [];\n    if (ariaNode.role === "link" && element.hasAttribute("href")) {\n      const href = element.getAttribute("href");\n      ariaNode.props["url"] = href;\n    }\n    if (ariaNode.role === "textbox" && element.hasAttribute("placeholder") && element.getAttribute("placeholder") !== ariaNode.name) {\n      const placeholder = element.getAttribute("placeholder");\n      ariaNode.props["placeholder"] = placeholder;\n    }\n  }\n  beginAriaCaches();\n  try {\n    visit(snapshot.root, rootElement, true);\n  } finally {\n    endAriaCaches();\n  }\n  normalizeStringChildren(snapshot.root);\n  normalizeGenericRoles(snapshot.root);\n  return snapshot;\n}\nfunction computeAriaRef(ariaNode, options) {\n  var _a;\n  if (options.refs === "none")\n    return;\n  if (options.refs === "interactable" && (!ariaNode.box.visible || !ariaNode.receivesPointerEvents))\n    return;\n  const element = ariaNodeElement(ariaNode);\n  let ariaRef = element._ariaRef;\n  if (!ariaRef || ariaRef.role !== ariaNode.role || ariaRef.name !== ariaNode.name) {\n    ariaRef = { role: ariaNode.role, name: ariaNode.name, ref: ((_a = options.refPrefix) != null ? _a : "") + "e" + ++lastRef };\n    element._ariaRef = ariaRef;\n  }\n  ariaNode.ref = ariaRef.ref;\n}\nfunction toAriaNode(element, options) {\n  var _a;\n  const active = element.ownerDocument.activeElement === element;\n  if (element.nodeName === "IFRAME") {\n    const ariaNode = {\n      role: "iframe",\n      name: "",\n      children: [],\n      props: {},\n      box: computeBox(element),\n      receivesPointerEvents: true,\n      active\n    };\n    setAriaNodeElement(ariaNode, element);\n    computeAriaRef(ariaNode, options);\n    return ariaNode;\n  }\n  const defaultRole = options.includeGenericRole ? "generic" : null;\n  const role = (_a = getAriaRole(element)) != null ? _a : defaultRole;\n  if (!role || role === "presentation" || role === "none")\n    return null;\n  const name = normalizeWhiteSpace(getElementAccessibleName(element, false) || "");\n  const receivesPointerEvents2 = receivesPointerEvents(element);\n  const box = computeBox(element);\n  if (role === "generic" && box.inline && element.childNodes.length === 1 && element.childNodes[0].nodeType === Node.TEXT_NODE)\n    return null;\n  const result = {\n    role,\n    name,\n    children: [],\n    props: {},\n    box,\n    receivesPointerEvents: receivesPointerEvents2,\n    active\n  };\n  setAriaNodeElement(result, element);\n  computeAriaRef(result, options);\n  if (kAriaCheckedRoles.includes(role))\n    result.checked = getAriaChecked(element);\n  if (kAriaDisabledRoles.includes(role))\n    result.disabled = getAriaDisabled(element);\n  if (kAriaExpandedRoles.includes(role))\n    result.expanded = getAriaExpanded(element);\n  if (kAriaLevelRoles.includes(role))\n    result.level = getAriaLevel(element);\n  if (kAriaPressedRoles.includes(role))\n    result.pressed = getAriaPressed(element);\n  if (kAriaSelectedRoles.includes(role))\n    result.selected = getAriaSelected(element);\n  if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n    if (element.type !== "checkbox" && element.type !== "radio" && element.type !== "file")\n      result.children = [element.value];\n  }\n  return result;\n}\nfunction normalizeGenericRoles(node) {\n  const normalizeChildren = (node2) => {\n    const result = [];\n    for (const child of node2.children || []) {\n      if (typeof child === "string") {\n        result.push(child);\n        continue;\n      }\n      const normalized = normalizeChildren(child);\n      result.push(...normalized);\n    }\n    const removeSelf = node2.role === "generic" && !node2.name && result.length <= 1 && result.every((c) => typeof c !== "string" && !!c.ref);\n    if (removeSelf)\n      return result;\n    node2.children = result;\n    return [node2];\n  };\n  normalizeChildren(node);\n}\nfunction normalizeStringChildren(rootA11yNode) {\n  const flushChildren = (buffer, normalizedChildren) => {\n    if (!buffer.length)\n      return;\n    const text = normalizeWhiteSpace(buffer.join(""));\n    if (text)\n      normalizedChildren.push(text);\n    buffer.length = 0;\n  };\n  const visit = (ariaNode) => {\n    const normalizedChildren = [];\n    const buffer = [];\n    for (const child of ariaNode.children || []) {\n      if (typeof child === "string") {\n        buffer.push(child);\n      } else {\n        flushChildren(buffer, normalizedChildren);\n        visit(child);\n        normalizedChildren.push(child);\n      }\n    }\n    flushChildren(buffer, normalizedChildren);\n    ariaNode.children = normalizedChildren.length ? normalizedChildren : [];\n    if (ariaNode.children.length === 1 && ariaNode.children[0] === ariaNode.name)\n      ariaNode.children = [];\n  };\n  visit(rootA11yNode);\n}\nfunction matchesStringOrRegex(text, template) {\n  if (!template)\n    return true;\n  if (!text)\n    return false;\n  if (typeof template === "string")\n    return text === template;\n  return !!text.match(new RegExp(template.pattern));\n}\nfunction matchesTextValue(text, template) {\n  if (!(template == null ? void 0 : template.normalized))\n    return true;\n  if (!text)\n    return false;\n  if (text === template.normalized)\n    return true;\n  if (text === template.raw)\n    return true;\n  const regex = cachedRegex(template);\n  if (regex)\n    return !!text.match(regex);\n  return false;\n}\nvar cachedRegexSymbol = Symbol("cachedRegex");\nfunction cachedRegex(template) {\n  if (template[cachedRegexSymbol] !== void 0)\n    return template[cachedRegexSymbol];\n  const { raw } = template;\n  const canBeRegex = raw.startsWith("/") && raw.endsWith("/") && raw.length > 1;\n  let regex;\n  try {\n    regex = canBeRegex ? new RegExp(raw.slice(1, -1)) : null;\n  } catch (e) {\n    regex = null;\n  }\n  template[cachedRegexSymbol] = regex;\n  return regex;\n}\nfunction matchesExpectAriaTemplate(rootElement, template) {\n  const snapshot = generateAriaTree(rootElement, { mode: "expect" });\n  const matches = matchesNodeDeep(snapshot.root, template, false, false);\n  return {\n    matches,\n    received: {\n      raw: renderAriaTree(snapshot, { mode: "expect" }),\n      regex: renderAriaTree(snapshot, { mode: "codegen" })\n    }\n  };\n}\nfunction getAllElementsMatchingExpectAriaTemplate(rootElement, template) {\n  const root = generateAriaTree(rootElement, { mode: "expect" }).root;\n  const matches = matchesNodeDeep(root, template, true, false);\n  return matches.map((n) => ariaNodeElement(n));\n}\nfunction matchesNode(node, template, isDeepEqual) {\n  var _a;\n  if (typeof node === "string" && template.kind === "text")\n    return matchesTextValue(node, template.text);\n  if (node === null || typeof node !== "object" || template.kind !== "role")\n    return false;\n  if (template.role !== "fragment" && template.role !== node.role)\n    return false;\n  if (template.checked !== void 0 && template.checked !== node.checked)\n    return false;\n  if (template.disabled !== void 0 && template.disabled !== node.disabled)\n    return false;\n  if (template.expanded !== void 0 && template.expanded !== node.expanded)\n    return false;\n  if (template.level !== void 0 && template.level !== node.level)\n    return false;\n  if (template.pressed !== void 0 && template.pressed !== node.pressed)\n    return false;\n  if (template.selected !== void 0 && template.selected !== node.selected)\n    return false;\n  if (!matchesStringOrRegex(node.name, template.name))\n    return false;\n  if (!matchesTextValue(node.props.url, (_a = template.props) == null ? void 0 : _a.url))\n    return false;\n  if (template.containerMode === "contain")\n    return containsList(node.children || [], template.children || []);\n  if (template.containerMode === "equal")\n    return listEqual(node.children || [], template.children || [], false);\n  if (template.containerMode === "deep-equal" || isDeepEqual)\n    return listEqual(node.children || [], template.children || [], true);\n  return containsList(node.children || [], template.children || []);\n}\nfunction listEqual(children, template, isDeepEqual) {\n  if (template.length !== children.length)\n    return false;\n  for (let i = 0; i < template.length; ++i) {\n    if (!matchesNode(children[i], template[i], isDeepEqual))\n      return false;\n  }\n  return true;\n}\nfunction containsList(children, template) {\n  if (template.length > children.length)\n    return false;\n  const cc = children.slice();\n  const tt = template.slice();\n  for (const t of tt) {\n    let c = cc.shift();\n    while (c) {\n      if (matchesNode(c, t, false))\n        break;\n      c = cc.shift();\n    }\n    if (!c)\n      return false;\n  }\n  return true;\n}\nfunction matchesNodeDeep(root, template, collectAll, isDeepEqual) {\n  const results = [];\n  const visit = (node, parent) => {\n    if (matchesNode(node, template, isDeepEqual)) {\n      const result = typeof node === "string" ? parent : node;\n      if (result)\n        results.push(result);\n      return !collectAll;\n    }\n    if (typeof node === "string")\n      return false;\n    for (const child of node.children || []) {\n      if (visit(child, node))\n        return true;\n    }\n    return false;\n  };\n  visit(root, null);\n  return results;\n}\nfunction buildByRefMap(root, map = /* @__PURE__ */ new Map()) {\n  if (root == null ? void 0 : root.ref)\n    map.set(root.ref, root);\n  for (const child of (root == null ? void 0 : root.children) || []) {\n    if (typeof child !== "string")\n      buildByRefMap(child, map);\n  }\n  return map;\n}\nfunction compareSnapshots(ariaSnapshot, previousSnapshot) {\n  var _a;\n  const previousByRef = buildByRefMap(previousSnapshot == null ? void 0 : previousSnapshot.root);\n  const result = /* @__PURE__ */ new Map();\n  const visit = (ariaNode, previousNode) => {\n    let same = ariaNode.children.length === (previousNode == null ? void 0 : previousNode.children.length) && ariaNodesEqual(ariaNode, previousNode);\n    let canBeSkipped = same;\n    for (let childIndex = 0; childIndex < ariaNode.children.length; childIndex++) {\n      const child = ariaNode.children[childIndex];\n      const previousChild = previousNode == null ? void 0 : previousNode.children[childIndex];\n      if (typeof child === "string") {\n        same && (same = child === previousChild);\n        canBeSkipped && (canBeSkipped = child === previousChild);\n      } else {\n        let previous = typeof previousChild !== "string" ? previousChild : void 0;\n        if (child.ref)\n          previous = previousByRef.get(child.ref);\n        const sameChild = visit(child, previous);\n        if (!previous || !sameChild && !child.ref || previous !== previousChild)\n          canBeSkipped = false;\n        same && (same = sameChild && previous === previousChild);\n      }\n    }\n    result.set(ariaNode, same ? "same" : canBeSkipped ? "skip" : "changed");\n    return same;\n  };\n  visit(ariaSnapshot.root, previousByRef.get((_a = previousSnapshot == null ? void 0 : previousSnapshot.root) == null ? void 0 : _a.ref));\n  return result;\n}\nfunction filterSnapshotDiff(nodes, statusMap) {\n  const result = [];\n  const visit = (ariaNode) => {\n    const status = statusMap.get(ariaNode);\n    if (status === "same") {\n    } else if (status === "skip") {\n      for (const child of ariaNode.children) {\n        if (typeof child !== "string")\n          visit(child);\n      }\n    } else {\n      result.push(ariaNode);\n    }\n  };\n  for (const node of nodes) {\n    if (typeof node === "string")\n      result.push(node);\n    else\n      visit(node);\n  }\n  return result;\n}\nfunction renderAriaTree(ariaSnapshot, publicOptions, previousSnapshot) {\n  const options = toInternalOptions(publicOptions);\n  const lines = [];\n  const includeText = options.renderStringsAsRegex ? textContributesInfo : () => true;\n  const renderString = options.renderStringsAsRegex ? convertToBestGuessRegex : (str) => str;\n  let nodesToRender = ariaSnapshot.root.role === "fragment" ? ariaSnapshot.root.children : [ariaSnapshot.root];\n  const statusMap = compareSnapshots(ariaSnapshot, previousSnapshot);\n  if (previousSnapshot)\n    nodesToRender = filterSnapshotDiff(nodesToRender, statusMap);\n  const visitText = (text, indent) => {\n    const escaped = yamlEscapeValueIfNeeded(renderString(text));\n    if (escaped)\n      lines.push(indent + "- text: " + escaped);\n  };\n  const createKey = (ariaNode, renderCursorPointer) => {\n    let key = ariaNode.role;\n    if (ariaNode.name && ariaNode.name.length <= 900) {\n      const name = renderString(ariaNode.name);\n      if (name) {\n        const stringifiedName = name.startsWith("/") && name.endsWith("/") ? name : JSON.stringify(name);\n        key += " " + stringifiedName;\n      }\n    }\n    if (ariaNode.checked === "mixed")\n      key += ` [checked=mixed]`;\n    if (ariaNode.checked === true)\n      key += ` [checked]`;\n    if (ariaNode.disabled)\n      key += ` [disabled]`;\n    if (ariaNode.expanded)\n      key += ` [expanded]`;\n    if (ariaNode.active && options.renderActive)\n      key += ` [active]`;\n    if (ariaNode.level)\n      key += ` [level=${ariaNode.level}]`;\n    if (ariaNode.pressed === "mixed")\n      key += ` [pressed=mixed]`;\n    if (ariaNode.pressed === true)\n      key += ` [pressed]`;\n    if (ariaNode.selected === true)\n      key += ` [selected]`;\n    if (ariaNode.ref) {\n      key += ` [ref=${ariaNode.ref}]`;\n      if (renderCursorPointer && hasPointerCursor(ariaNode))\n        key += " [cursor=pointer]";\n    }\n    return key;\n  };\n  const getSingleInlinedTextChild = (ariaNode) => {\n    return (ariaNode == null ? void 0 : ariaNode.children.length) === 1 && typeof ariaNode.children[0] === "string" && !Object.keys(ariaNode.props).length ? ariaNode.children[0] : void 0;\n  };\n  const visit = (ariaNode, indent, renderCursorPointer) => {\n    if (statusMap.get(ariaNode) === "same" && ariaNode.ref) {\n      lines.push(indent + `- ref=${ariaNode.ref} [unchanged]`);\n      return;\n    }\n    const isDiffRoot = !!previousSnapshot && !indent;\n    const escapedKey = indent + "- " + (isDiffRoot ? "<changed> " : "") + yamlEscapeKeyIfNeeded(createKey(ariaNode, renderCursorPointer));\n    const singleInlinedTextChild = getSingleInlinedTextChild(ariaNode);\n    if (!ariaNode.children.length && !Object.keys(ariaNode.props).length) {\n      lines.push(escapedKey);\n    } else if (singleInlinedTextChild !== void 0) {\n      const shouldInclude = includeText(ariaNode, singleInlinedTextChild);\n      if (shouldInclude)\n        lines.push(escapedKey + ": " + yamlEscapeValueIfNeeded(renderString(singleInlinedTextChild)));\n      else\n        lines.push(escapedKey);\n    } else {\n      lines.push(escapedKey + ":");\n      for (const [name, value] of Object.entries(ariaNode.props))\n        lines.push(indent + "  - /" + name + ": " + yamlEscapeValueIfNeeded(value));\n      const childIndent = indent + "  ";\n      const inCursorPointer = !!ariaNode.ref && renderCursorPointer && hasPointerCursor(ariaNode);\n      for (const child of ariaNode.children) {\n        if (typeof child === "string")\n          visitText(includeText(ariaNode, child) ? child : "", childIndent);\n        else\n          visit(child, childIndent, renderCursorPointer && !inCursorPointer);\n      }\n    }\n  };\n  for (const nodeToRender of nodesToRender) {\n    if (typeof nodeToRender === "string")\n      visitText(nodeToRender, "");\n    else\n      visit(nodeToRender, "", !!options.renderCursorPointer);\n  }\n  return lines.join("\\n");\n}\nfunction convertToBestGuessRegex(text) {\n  const dynamicContent = [\n    // 2mb\n    { regex: /\\b[\\d,.]+[bkmBKM]+\\b/, replacement: "[\\\\d,.]+[bkmBKM]+" },\n    // 2ms, 20s\n    { regex: /\\b\\d+[hmsp]+\\b/, replacement: "\\\\d+[hmsp]+" },\n    { regex: /\\b[\\d,.]+[hmsp]+\\b/, replacement: "[\\\\d,.]+[hmsp]+" },\n    // Do not replace single digits with regex by default.\n    // 2+ digits: [Issue 22, 22.3, 2.33, 2,333]\n    { regex: /\\b\\d+,\\d+\\b/, replacement: "\\\\d+,\\\\d+" },\n    { regex: /\\b\\d+\\.\\d{2,}\\b/, replacement: "\\\\d+\\\\.\\\\d+" },\n    { regex: /\\b\\d{2,}\\.\\d+\\b/, replacement: "\\\\d+\\\\.\\\\d+" },\n    { regex: /\\b\\d{2,}\\b/, replacement: "\\\\d+" }\n  ];\n  let pattern = "";\n  let lastIndex = 0;\n  const combinedRegex = new RegExp(dynamicContent.map((r) => "(" + r.regex.source + ")").join("|"), "g");\n  text.replace(combinedRegex, (match, ...args) => {\n    const offset = args[args.length - 2];\n    const groups = args.slice(0, -2);\n    pattern += escapeRegExp(text.slice(lastIndex, offset));\n    for (let i = 0; i < groups.length; i++) {\n      if (groups[i]) {\n        const { replacement } = dynamicContent[i];\n        pattern += replacement;\n        break;\n      }\n    }\n    lastIndex = offset + match.length;\n    return match;\n  });\n  if (!pattern)\n    return text;\n  pattern += escapeRegExp(text.slice(lastIndex));\n  return String(new RegExp(pattern));\n}\nfunction textContributesInfo(node, text) {\n  if (!text.length)\n    return false;\n  if (!node.name)\n    return true;\n  if (node.name.length > text.length)\n    return false;\n  const substr = text.length <= 200 && node.name.length <= 200 ? longestCommonSubstring(text, node.name) : "";\n  let filtered = text;\n  while (substr && filtered.includes(substr))\n    filtered = filtered.replace(substr, "");\n  return filtered.trim().length / text.length > 0.1;\n}\nvar elementSymbol = Symbol("element");\nfunction ariaNodeElement(ariaNode) {\n  return ariaNode[elementSymbol];\n}\nfunction setAriaNodeElement(ariaNode, element) {\n  ariaNode[elementSymbol] = element;\n}\nfunction findNewElement(from, to) {\n  const node = findNewNode(from, to);\n  return node ? ariaNodeElement(node) : void 0;\n}\n\n// packages/injected/src/highlight.css?inline\nvar highlight_default = ":host{font-size:13px;font-family:system-ui,Ubuntu,Droid Sans,sans-serif;color:#333}svg{position:absolute;height:0}x-pw-tooltip{backdrop-filter:blur(5px);background-color:#fff;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:none;font-size:12.8px;font-weight:400;left:0;line-height:1.5;max-width:600px;position:absolute;top:0;padding:0;flex-direction:column;overflow:hidden}x-pw-tooltip-line{display:flex;max-width:600px;padding:6px;user-select:none;cursor:pointer}x-pw-tooltip-footer{display:flex;max-width:600px;padding:6px;user-select:none;color:#777}x-pw-dialog{background-color:#fff;pointer-events:auto;border-radius:6px;box-shadow:0 .5rem 1.2rem #0000004d;display:flex;flex-direction:column;position:absolute;z-index:10;font-size:13px}x-pw-dialog:not(.autosize){width:400px;height:150px}x-pw-dialog-body{display:flex;flex-direction:column;flex:auto}x-pw-dialog-body label{margin:5px 8px;display:flex;flex-direction:row;align-items:center}x-pw-highlight{position:absolute;top:0;left:0;width:0;height:0}x-pw-action-point{position:absolute;width:20px;height:20px;background:red;border-radius:10px;margin:-10px 0 0 -10px;z-index:2}x-pw-separator{height:1px;margin:6px 9px;background:#949494e5}x-pw-tool-gripper{height:28px;width:24px;margin:2px 0;cursor:grab}x-pw-tool-gripper:active{cursor:grabbing}x-pw-tool-gripper>x-div{width:16px;height:16px;margin:6px 4px;clip-path:url(#icon-gripper);background-color:#555}x-pw-tools-list>label{display:flex;align-items:center;margin:0 10px;user-select:none}x-pw-tools-list{display:flex;width:100%;border-bottom:1px solid #dddddd}x-pw-tool-item{pointer-events:auto;height:28px;width:28px;border-radius:3px}x-pw-tool-item:not(.disabled){cursor:pointer}x-pw-tool-item:not(.disabled):hover{background-color:#dbdbdb}x-pw-tool-item.toggled{background-color:#8acae480}x-pw-tool-item.toggled:not(.disabled):hover{background-color:#8acae4c4}x-pw-tool-item>x-div{width:16px;height:16px;margin:6px;background-color:#3a3a3a}x-pw-tool-item.disabled>x-div{background-color:#61616180;cursor:default}x-pw-tool-item.record.toggled{background-color:transparent}x-pw-tool-item.record.toggled:not(.disabled):hover{background-color:#dbdbdb}x-pw-tool-item.record.toggled>x-div{background-color:#a1260d}x-pw-tool-item.record.disabled.toggled>x-div{opacity:.8}x-pw-tool-item.accept>x-div{background-color:#388a34}x-pw-tool-item.record>x-div{clip-path:url(#icon-circle-large-filled)}x-pw-tool-item.record.toggled>x-div{clip-path:url(#icon-stop-circle)}x-pw-tool-item.pick-locator>x-div{clip-path:url(#icon-inspect)}x-pw-tool-item.text>x-div{clip-path:url(#icon-whole-word)}x-pw-tool-item.visibility>x-div{clip-path:url(#icon-eye)}x-pw-tool-item.value>x-div{clip-path:url(#icon-symbol-constant)}x-pw-tool-item.snapshot>x-div{clip-path:url(#icon-gist)}x-pw-tool-item.accept>x-div{clip-path:url(#icon-check)}x-pw-tool-item.cancel>x-div{clip-path:url(#icon-close)}x-pw-tool-item.succeeded>x-div{clip-path:url(#icon-pass);background-color:#388a34!important}x-pw-overlay{position:absolute;top:0;max-width:min-content;z-index:2147483647;background:transparent;pointer-events:auto}x-pw-overlay x-pw-tools-list{background-color:#fffd;box-shadow:#0000001a 0 5px 5px;border-radius:3px;border-bottom:none}x-pw-overlay x-pw-tool-item{margin:2px}textarea.text-editor{font-family:system-ui,Ubuntu,Droid Sans,sans-serif;flex:auto;border:none;margin:6px 10px;color:#333;outline:1px solid transparent!important;resize:none;padding:0;font-size:13px}textarea.text-editor.does-not-match{outline:1px solid red!important}x-div{display:block}x-spacer{flex:auto}*{box-sizing:border-box}*[hidden]{display:none!important}x-locator-editor{flex:none;width:100%;height:60px;padding:4px;border-bottom:1px solid #dddddd;outline:1px solid transparent}x-locator-editor.does-not-match{outline:1px solid red}.CodeMirror{width:100%!important;height:100%!important}x-pw-action-list{flex:auto;display:flex;flex-direction:column;user-select:none}x-pw-action-item{padding:6px 10px;cursor:pointer;overflow:hidden}x-pw-action-item:hover{background-color:#f2f2f2}x-pw-action-item:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}\\n";\n\n// packages/injected/src/highlight.ts\nvar Highlight = class {\n  constructor(injectedScript) {\n    this._renderedEntries = [];\n    this._language = "javascript";\n    this._injectedScript = injectedScript;\n    const document = injectedScript.document;\n    this._isUnderTest = injectedScript.isUnderTest;\n    this._glassPaneElement = document.createElement("x-pw-glass");\n    this._glassPaneElement.style.position = "fixed";\n    this._glassPaneElement.style.top = "0";\n    this._glassPaneElement.style.right = "0";\n    this._glassPaneElement.style.bottom = "0";\n    this._glassPaneElement.style.left = "0";\n    this._glassPaneElement.style.zIndex = "2147483647";\n    this._glassPaneElement.style.pointerEvents = "none";\n    this._glassPaneElement.style.display = "flex";\n    this._glassPaneElement.style.backgroundColor = "transparent";\n    this._actionPointElement = document.createElement("x-pw-action-point");\n    this._actionPointElement.setAttribute("hidden", "true");\n    this._glassPaneShadow = this._glassPaneElement.attachShadow({ mode: this._isUnderTest ? "open" : "closed" });\n    if (typeof this._glassPaneShadow.adoptedStyleSheets.push === "function") {\n      const sheet = new this._injectedScript.window.CSSStyleSheet();\n      sheet.replaceSync(highlight_default);\n      this._glassPaneShadow.adoptedStyleSheets.push(sheet);\n    } else {\n      const styleElement = this._injectedScript.document.createElement("style");\n      styleElement.textContent = highlight_default;\n      this._glassPaneShadow.appendChild(styleElement);\n    }\n    this._glassPaneShadow.appendChild(this._actionPointElement);\n  }\n  install() {\n    if (!this._injectedScript.document.documentElement)\n      return;\n    if (!this._injectedScript.document.documentElement.contains(this._glassPaneElement) || this._glassPaneElement.nextElementSibling)\n      this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);\n  }\n  setLanguage(language) {\n    this._language = language;\n  }\n  runHighlightOnRaf(selector) {\n    if (this._rafRequest)\n      this._injectedScript.utils.builtins.cancelAnimationFrame(this._rafRequest);\n    const elements = this._injectedScript.querySelectorAll(selector, this._injectedScript.document.documentElement);\n    const locator = asLocator(this._language, stringifySelector(selector));\n    const color = elements.length > 1 ? "#f6b26b7f" : "#6fa8dc7f";\n    this.updateHighlight(elements.map((element, index) => {\n      const suffix = elements.length > 1 ? ` [${index + 1} of ${elements.length}]` : "";\n      return { element, color, tooltipText: locator + suffix };\n    }));\n    this._rafRequest = this._injectedScript.utils.builtins.requestAnimationFrame(() => this.runHighlightOnRaf(selector));\n  }\n  uninstall() {\n    if (this._rafRequest)\n      this._injectedScript.utils.builtins.cancelAnimationFrame(this._rafRequest);\n    this._glassPaneElement.remove();\n  }\n  showActionPoint(x, y) {\n    this._actionPointElement.style.top = y + "px";\n    this._actionPointElement.style.left = x + "px";\n    this._actionPointElement.hidden = false;\n  }\n  hideActionPoint() {\n    this._actionPointElement.hidden = true;\n  }\n  clearHighlight() {\n    var _a, _b;\n    for (const entry of this._renderedEntries) {\n      (_a = entry.highlightElement) == null ? void 0 : _a.remove();\n      (_b = entry.tooltipElement) == null ? void 0 : _b.remove();\n    }\n    this._renderedEntries = [];\n  }\n  maskElements(elements, color) {\n    this.updateHighlight(elements.map((element) => ({ element, color })));\n  }\n  updateHighlight(entries) {\n    if (this._highlightIsUpToDate(entries))\n      return;\n    this.clearHighlight();\n    for (const entry of entries) {\n      const highlightElement = this._createHighlightElement();\n      this._glassPaneShadow.appendChild(highlightElement);\n      let tooltipElement;\n      if (entry.tooltipText) {\n        tooltipElement = this._injectedScript.document.createElement("x-pw-tooltip");\n        this._glassPaneShadow.appendChild(tooltipElement);\n        tooltipElement.style.top = "0";\n        tooltipElement.style.left = "0";\n        tooltipElement.style.display = "flex";\n        const lineElement = this._injectedScript.document.createElement("x-pw-tooltip-line");\n        lineElement.textContent = entry.tooltipText;\n        tooltipElement.appendChild(lineElement);\n      }\n      this._renderedEntries.push({ targetElement: entry.element, color: entry.color, tooltipElement, highlightElement });\n    }\n    for (const entry of this._renderedEntries) {\n      entry.box = entry.targetElement.getBoundingClientRect();\n      if (!entry.tooltipElement)\n        continue;\n      const { anchorLeft, anchorTop } = this.tooltipPosition(entry.box, entry.tooltipElement);\n      entry.tooltipTop = anchorTop;\n      entry.tooltipLeft = anchorLeft;\n    }\n    for (const entry of this._renderedEntries) {\n      if (entry.tooltipElement) {\n        entry.tooltipElement.style.top = entry.tooltipTop + "px";\n        entry.tooltipElement.style.left = entry.tooltipLeft + "px";\n      }\n      const box = entry.box;\n      entry.highlightElement.style.backgroundColor = entry.color;\n      entry.highlightElement.style.left = box.x + "px";\n      entry.highlightElement.style.top = box.y + "px";\n      entry.highlightElement.style.width = box.width + "px";\n      entry.highlightElement.style.height = box.height + "px";\n      entry.highlightElement.style.display = "block";\n      if (this._isUnderTest)\n        console.error("Highlight box for test: " + JSON.stringify({ x: box.x, y: box.y, width: box.width, height: box.height }));\n    }\n  }\n  firstBox() {\n    var _a;\n    return (_a = this._renderedEntries[0]) == null ? void 0 : _a.box;\n  }\n  firstTooltipBox() {\n    const entry = this._renderedEntries[0];\n    if (!entry || !entry.tooltipElement || entry.tooltipLeft === void 0 || entry.tooltipTop === void 0)\n      return;\n    return {\n      x: entry.tooltipLeft,\n      y: entry.tooltipTop,\n      left: entry.tooltipLeft,\n      top: entry.tooltipTop,\n      width: entry.tooltipElement.offsetWidth,\n      height: entry.tooltipElement.offsetHeight,\n      bottom: entry.tooltipTop + entry.tooltipElement.offsetHeight,\n      right: entry.tooltipLeft + entry.tooltipElement.offsetWidth,\n      toJSON: () => {\n      }\n    };\n  }\n  // Note: there is a copy of this method in dialog.tsx. Please fix bugs in both places.\n  tooltipPosition(box, tooltipElement) {\n    const tooltipWidth = tooltipElement.offsetWidth;\n    const tooltipHeight = tooltipElement.offsetHeight;\n    const totalWidth = this._glassPaneElement.offsetWidth;\n    const totalHeight = this._glassPaneElement.offsetHeight;\n    let anchorLeft = Math.max(5, box.left);\n    if (anchorLeft + tooltipWidth > totalWidth - 5)\n      anchorLeft = totalWidth - tooltipWidth - 5;\n    let anchorTop = Math.max(0, box.bottom) + 5;\n    if (anchorTop + tooltipHeight > totalHeight - 5) {\n      if (Math.max(0, box.top) > tooltipHeight + 5) {\n        anchorTop = Math.max(0, box.top) - tooltipHeight - 5;\n      } else {\n        anchorTop = totalHeight - 5 - tooltipHeight;\n      }\n    }\n    return { anchorLeft, anchorTop };\n  }\n  _highlightIsUpToDate(entries) {\n    if (entries.length !== this._renderedEntries.length)\n      return false;\n    for (let i = 0; i < this._renderedEntries.length; ++i) {\n      if (entries[i].element !== this._renderedEntries[i].targetElement)\n        return false;\n      if (entries[i].color !== this._renderedEntries[i].color)\n        return false;\n      const oldBox = this._renderedEntries[i].box;\n      if (!oldBox)\n        return false;\n      const box = entries[i].element.getBoundingClientRect();\n      if (box.top !== oldBox.top || box.right !== oldBox.right || box.bottom !== oldBox.bottom || box.left !== oldBox.left)\n        return false;\n    }\n    return true;\n  }\n  _createHighlightElement() {\n    return this._injectedScript.document.createElement("x-pw-highlight");\n  }\n  appendChild(element) {\n    this._glassPaneShadow.appendChild(element);\n  }\n  onGlassPaneClick(handler) {\n    this._glassPaneElement.style.pointerEvents = "auto";\n    this._glassPaneElement.style.backgroundColor = "rgba(0, 0, 0, 0.3)";\n    this._glassPaneElement.addEventListener("click", handler);\n  }\n  offGlassPaneClick(handler) {\n    this._glassPaneElement.style.pointerEvents = "none";\n    this._glassPaneElement.style.backgroundColor = "transparent";\n    this._glassPaneElement.removeEventListener("click", handler);\n  }\n};\n\n// packages/injected/src/layoutSelectorUtils.ts\nfunction boxRightOf(box1, box2, maxDistance) {\n  const distance = box1.left - box2.right;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box2.bottom - box1.bottom, 0) + Math.max(box1.top - box2.top, 0);\n}\nfunction boxLeftOf(box1, box2, maxDistance) {\n  const distance = box2.left - box1.right;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box2.bottom - box1.bottom, 0) + Math.max(box1.top - box2.top, 0);\n}\nfunction boxAbove(box1, box2, maxDistance) {\n  const distance = box2.top - box1.bottom;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box1.left - box2.left, 0) + Math.max(box2.right - box1.right, 0);\n}\nfunction boxBelow(box1, box2, maxDistance) {\n  const distance = box1.top - box2.bottom;\n  if (distance < 0 || maxDistance !== void 0 && distance > maxDistance)\n    return;\n  return distance + Math.max(box1.left - box2.left, 0) + Math.max(box2.right - box1.right, 0);\n}\nfunction boxNear(box1, box2, maxDistance) {\n  const kThreshold = maxDistance === void 0 ? 50 : maxDistance;\n  let score = 0;\n  if (box1.left - box2.right >= 0)\n    score += box1.left - box2.right;\n  if (box2.left - box1.right >= 0)\n    score += box2.left - box1.right;\n  if (box2.top - box1.bottom >= 0)\n    score += box2.top - box1.bottom;\n  if (box1.top - box2.bottom >= 0)\n    score += box1.top - box2.bottom;\n  return score > kThreshold ? void 0 : score;\n}\nvar kLayoutSelectorNames = ["left-of", "right-of", "above", "below", "near"];\nfunction layoutSelectorScore(name, element, inner, maxDistance) {\n  const box = element.getBoundingClientRect();\n  const scorer = { "left-of": boxLeftOf, "right-of": boxRightOf, "above": boxAbove, "below": boxBelow, "near": boxNear }[name];\n  let bestScore;\n  for (const e of inner) {\n    if (e === element)\n      continue;\n    const score = scorer(box, e.getBoundingClientRect(), maxDistance);\n    if (score === void 0)\n      continue;\n    if (bestScore === void 0 || score < bestScore)\n      bestScore = score;\n  }\n  return bestScore;\n}\n\n// packages/injected/src/selectorUtils.ts\nfunction matchesComponentAttribute(obj, attr) {\n  for (const token of attr.jsonPath) {\n    if (obj !== void 0 && obj !== null)\n      obj = obj[token];\n  }\n  return matchesAttributePart(obj, attr);\n}\nfunction matchesAttributePart(value, attr) {\n  const objValue = typeof value === "string" && !attr.caseSensitive ? value.toUpperCase() : value;\n  const attrValue = typeof attr.value === "string" && !attr.caseSensitive ? attr.value.toUpperCase() : attr.value;\n  if (attr.op === "<truthy>")\n    return !!objValue;\n  if (attr.op === "=") {\n    if (attrValue instanceof RegExp)\n      return typeof objValue === "string" && !!objValue.match(attrValue);\n    return objValue === attrValue;\n  }\n  if (typeof objValue !== "string" || typeof attrValue !== "string")\n    return false;\n  if (attr.op === "*=")\n    return objValue.includes(attrValue);\n  if (attr.op === "^=")\n    return objValue.startsWith(attrValue);\n  if (attr.op === "$=")\n    return objValue.endsWith(attrValue);\n  if (attr.op === "|=")\n    return objValue === attrValue || objValue.startsWith(attrValue + "-");\n  if (attr.op === "~=")\n    return objValue.split(" ").includes(attrValue);\n  return false;\n}\nfunction shouldSkipForTextMatching(element) {\n  const document = element.ownerDocument;\n  return element.nodeName === "SCRIPT" || element.nodeName === "NOSCRIPT" || element.nodeName === "STYLE" || document.head && document.head.contains(element);\n}\nfunction elementText(cache, root) {\n  let value = cache.get(root);\n  if (value === void 0) {\n    value = { full: "", normalized: "", immediate: [] };\n    if (!shouldSkipForTextMatching(root)) {\n      let currentImmediate = "";\n      if (root instanceof HTMLInputElement && (root.type === "submit" || root.type === "button")) {\n        value = { full: root.value, normalized: normalizeWhiteSpace(root.value), immediate: [root.value] };\n      } else {\n        for (let child = root.firstChild; child; child = child.nextSibling) {\n          if (child.nodeType === Node.TEXT_NODE) {\n            value.full += child.nodeValue || "";\n            currentImmediate += child.nodeValue || "";\n          } else if (child.nodeType === Node.COMMENT_NODE) {\n            continue;\n          } else {\n            if (currentImmediate)\n              value.immediate.push(currentImmediate);\n            currentImmediate = "";\n            if (child.nodeType === Node.ELEMENT_NODE)\n              value.full += elementText(cache, child).full;\n          }\n        }\n        if (currentImmediate)\n          value.immediate.push(currentImmediate);\n        if (root.shadowRoot)\n          value.full += elementText(cache, root.shadowRoot).full;\n        if (value.full)\n          value.normalized = normalizeWhiteSpace(value.full);\n      }\n    }\n    cache.set(root, value);\n  }\n  return value;\n}\nfunction elementMatchesText(cache, element, matcher) {\n  if (shouldSkipForTextMatching(element))\n    return "none";\n  if (!matcher(elementText(cache, element)))\n    return "none";\n  for (let child = element.firstChild; child; child = child.nextSibling) {\n    if (child.nodeType === Node.ELEMENT_NODE && matcher(elementText(cache, child)))\n      return "selfAndChildren";\n  }\n  if (element.shadowRoot && matcher(elementText(cache, element.shadowRoot)))\n    return "selfAndChildren";\n  return "self";\n}\nfunction getElementLabels(textCache, element) {\n  const labels = getAriaLabelledByElements(element);\n  if (labels)\n    return labels.map((label) => elementText(textCache, label));\n  const ariaLabel = element.getAttribute("aria-label");\n  if (ariaLabel !== null && !!ariaLabel.trim())\n    return [{ full: ariaLabel, normalized: normalizeWhiteSpace(ariaLabel), immediate: [ariaLabel] }];\n  const isNonHiddenInput = element.nodeName === "INPUT" && element.type !== "hidden";\n  if (["BUTTON", "METER", "OUTPUT", "PROGRESS", "SELECT", "TEXTAREA"].includes(element.nodeName) || isNonHiddenInput) {\n    const labels2 = element.labels;\n    if (labels2)\n      return [...labels2].map((label) => elementText(textCache, label));\n  }\n  return [];\n}\n\n// packages/injected/src/reactSelectorEngine.ts\nfunction getFunctionComponentName(component) {\n  return component.displayName || component.name || "Anonymous";\n}\nfunction getComponentName(reactElement) {\n  if (reactElement.type) {\n    switch (typeof reactElement.type) {\n      case "function":\n        return getFunctionComponentName(reactElement.type);\n      case "string":\n        return reactElement.type;\n      case "object":\n        return reactElement.type.displayName || (reactElement.type.render ? getFunctionComponentName(reactElement.type.render) : "");\n    }\n  }\n  if (reactElement._currentElement) {\n    const elementType = reactElement._currentElement.type;\n    if (typeof elementType === "string")\n      return elementType;\n    if (typeof elementType === "function")\n      return elementType.displayName || elementType.name || "Anonymous";\n  }\n  return "";\n}\nfunction getComponentKey(reactElement) {\n  var _a, _b;\n  return (_b = reactElement.key) != null ? _b : (_a = reactElement._currentElement) == null ? void 0 : _a.key;\n}\nfunction getChildren(reactElement) {\n  if (reactElement.child) {\n    const children = [];\n    for (let child = reactElement.child; child; child = child.sibling)\n      children.push(child);\n    return children;\n  }\n  if (!reactElement._currentElement)\n    return [];\n  const isKnownElement = (reactElement2) => {\n    var _a;\n    const elementType = (_a = reactElement2._currentElement) == null ? void 0 : _a.type;\n    return typeof elementType === "function" || typeof elementType === "string";\n  };\n  if (reactElement._renderedComponent) {\n    const child = reactElement._renderedComponent;\n    return isKnownElement(child) ? [child] : [];\n  }\n  if (reactElement._renderedChildren)\n    return [...Object.values(reactElement._renderedChildren)].filter(isKnownElement);\n  return [];\n}\nfunction getProps(reactElement) {\n  var _a;\n  const props = (\n    /* React 16+ */\n    reactElement.memoizedProps || /* React 15 */\n    ((_a = reactElement._currentElement) == null ? void 0 : _a.props)\n  );\n  if (!props || typeof props === "string")\n    return props;\n  const result = { ...props };\n  delete result.children;\n  return result;\n}\nfunction buildComponentsTree(reactElement) {\n  var _a;\n  const treeNode = {\n    key: getComponentKey(reactElement),\n    name: getComponentName(reactElement),\n    children: getChildren(reactElement).map(buildComponentsTree),\n    rootElements: [],\n    props: getProps(reactElement)\n  };\n  const rootElement = (\n    /* React 16+ */\n    reactElement.stateNode || /* React 15 */\n    reactElement._hostNode || /* React 15 */\n    ((_a = reactElement._renderedComponent) == null ? void 0 : _a._hostNode)\n  );\n  if (rootElement instanceof Element) {\n    treeNode.rootElements.push(rootElement);\n  } else {\n    for (const child of treeNode.children)\n      treeNode.rootElements.push(...child.rootElements);\n  }\n  return treeNode;\n}\nfunction filterComponentsTree(treeNode, searchFn, result = []) {\n  if (searchFn(treeNode))\n    result.push(treeNode);\n  for (const child of treeNode.children)\n    filterComponentsTree(child, searchFn, result);\n  return result;\n}\nfunction findReactRoots(root, roots = []) {\n  const document = root.ownerDocument || root;\n  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n  do {\n    const node = walker.currentNode;\n    const reactNode = node;\n    const rootKey = Object.keys(reactNode).find((key) => key.startsWith("__reactContainer") && reactNode[key] !== null);\n    if (rootKey) {\n      roots.push(reactNode[rootKey].stateNode.current);\n    } else {\n      const legacyRootKey = "_reactRootContainer";\n      if (reactNode.hasOwnProperty(legacyRootKey) && reactNode[legacyRootKey] !== null) {\n        roots.push(reactNode[legacyRootKey]._internalRoot.current);\n      }\n    }\n    if (node instanceof Element && node.hasAttribute("data-reactroot")) {\n      for (const key of Object.keys(node)) {\n        if (key.startsWith("__reactInternalInstance") || key.startsWith("__reactFiber"))\n          roots.push(node[key]);\n      }\n    }\n    const shadowRoot = node instanceof Element ? node.shadowRoot : null;\n    if (shadowRoot)\n      findReactRoots(shadowRoot, roots);\n  } while (walker.nextNode());\n  return roots;\n}\nvar createReactEngine = () => ({\n  queryAll(scope, selector) {\n    const { name, attributes } = parseAttributeSelector(selector, false);\n    const reactRoots = findReactRoots(scope.ownerDocument || scope);\n    const trees = reactRoots.map((reactRoot) => buildComponentsTree(reactRoot));\n    const treeNodes = trees.map((tree) => filterComponentsTree(tree, (treeNode) => {\n      var _a;\n      const props = (_a = treeNode.props) != null ? _a : {};\n      if (treeNode.key !== void 0)\n        props.key = treeNode.key;\n      if (name && treeNode.name !== name)\n        return false;\n      if (treeNode.rootElements.some((domNode) => !isInsideScope(scope, domNode)))\n        return false;\n      for (const attr of attributes) {\n        if (!matchesComponentAttribute(props, attr))\n          return false;\n      }\n      return true;\n    })).flat();\n    const allRootElements = /* @__PURE__ */ new Set();\n    for (const treeNode of treeNodes) {\n      for (const domNode of treeNode.rootElements)\n        allRootElements.add(domNode);\n    }\n    return [...allRootElements];\n  }\n});\n\n// packages/injected/src/roleSelectorEngine.ts\nvar kSupportedAttributes = ["selected", "checked", "pressed", "expanded", "level", "disabled", "name", "include-hidden"];\nkSupportedAttributes.sort();\nfunction validateSupportedRole(attr, roles, role) {\n  if (!roles.includes(role))\n    throw new Error(`"${attr}" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `"${role2}"`).join(", ")}`);\n}\nfunction validateSupportedValues(attr, values) {\n  if (attr.op !== "<truthy>" && !values.includes(attr.value))\n    throw new Error(`"${attr.name}" must be one of ${values.map((v) => JSON.stringify(v)).join(", ")}`);\n}\nfunction validateSupportedOp(attr, ops) {\n  if (!ops.includes(attr.op))\n    throw new Error(`"${attr.name}" does not support "${attr.op}" matcher`);\n}\nfunction validateAttributes(attrs, role) {\n  const options = { role };\n  for (const attr of attrs) {\n    switch (attr.name) {\n      case "checked": {\n        validateSupportedRole(attr.name, kAriaCheckedRoles, role);\n        validateSupportedValues(attr, [true, false, "mixed"]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.checked = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      case "pressed": {\n        validateSupportedRole(attr.name, kAriaPressedRoles, role);\n        validateSupportedValues(attr, [true, false, "mixed"]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.pressed = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      case "selected": {\n        validateSupportedRole(attr.name, kAriaSelectedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.selected = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      case "expanded": {\n        validateSupportedRole(attr.name, kAriaExpandedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.expanded = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      case "level": {\n        validateSupportedRole(attr.name, kAriaLevelRoles, role);\n        if (typeof attr.value === "string")\n          attr.value = +attr.value;\n        if (attr.op !== "=" || typeof attr.value !== "number" || Number.isNaN(attr.value))\n          throw new Error(`"level" attribute must be compared to a number`);\n        options.level = attr.value;\n        break;\n      }\n      case "disabled": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.disabled = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      case "name": {\n        if (attr.op === "<truthy>")\n          throw new Error(`"name" attribute must have a value`);\n        if (typeof attr.value !== "string" && !(attr.value instanceof RegExp))\n          throw new Error(`"name" attribute must be a string or a regular expression`);\n        options.name = attr.value;\n        options.nameOp = attr.op;\n        options.exact = attr.caseSensitive;\n        break;\n      }\n      case "include-hidden": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, ["<truthy>", "="]);\n        options.includeHidden = attr.op === "<truthy>" ? true : attr.value;\n        break;\n      }\n      default: {\n        throw new Error(`Unknown attribute "${attr.name}", must be one of ${kSupportedAttributes.map((a) => `"${a}"`).join(", ")}.`);\n      }\n    }\n  }\n  return options;\n}\nfunction queryRole(scope, options, internal) {\n  const result = [];\n  const match = (element) => {\n    if (getAriaRole(element) !== options.role)\n      return;\n    if (options.selected !== void 0 && getAriaSelected(element) !== options.selected)\n      return;\n    if (options.checked !== void 0 && getAriaChecked(element) !== options.checked)\n      return;\n    if (options.pressed !== void 0 && getAriaPressed(element) !== options.pressed)\n      return;\n    if (options.expanded !== void 0 && getAriaExpanded(element) !== options.expanded)\n      return;\n    if (options.level !== void 0 && getAriaLevel(element) !== options.level)\n      return;\n    if (options.disabled !== void 0 && getAriaDisabled(element) !== options.disabled)\n      return;\n    if (!options.includeHidden) {\n      const isHidden = isElementHiddenForAria(element);\n      if (isHidden)\n        return;\n    }\n    if (options.name !== void 0) {\n      const accessibleName = normalizeWhiteSpace(getElementAccessibleName(element, !!options.includeHidden));\n      if (typeof options.name === "string")\n        options.name = normalizeWhiteSpace(options.name);\n      if (internal && !options.exact && options.nameOp === "=")\n        options.nameOp = "*=";\n      if (!matchesAttributePart(accessibleName, { name: "", jsonPath: [], op: options.nameOp || "=", value: options.name, caseSensitive: !!options.exact }))\n        return;\n    }\n    result.push(element);\n  };\n  const query = (root) => {\n    const shadows = [];\n    if (root.shadowRoot)\n      shadows.push(root.shadowRoot);\n    for (const element of root.querySelectorAll("*")) {\n      match(element);\n      if (element.shadowRoot)\n        shadows.push(element.shadowRoot);\n    }\n    shadows.forEach(query);\n  };\n  query(scope);\n  return result;\n}\nfunction createRoleEngine(internal) {\n  return {\n    queryAll: (scope, selector) => {\n      const parsed = parseAttributeSelector(selector, true);\n      const role = parsed.name.toLowerCase();\n      if (!role)\n        throw new Error(`Role must not be empty`);\n      const options = validateAttributes(parsed.attributes, role);\n      beginAriaCaches();\n      try {\n        return queryRole(scope, options, internal);\n      } finally {\n        endAriaCaches();\n      }\n    }\n  };\n}\n\n// packages/injected/src/selectorEvaluator.ts\nvar SelectorEvaluatorImpl = class {\n  constructor() {\n    this._retainCacheCounter = 0;\n    this._cacheText = /* @__PURE__ */ new Map();\n    this._cacheQueryCSS = /* @__PURE__ */ new Map();\n    this._cacheMatches = /* @__PURE__ */ new Map();\n    this._cacheQuery = /* @__PURE__ */ new Map();\n    this._cacheMatchesSimple = /* @__PURE__ */ new Map();\n    this._cacheMatchesParents = /* @__PURE__ */ new Map();\n    this._cacheCallMatches = /* @__PURE__ */ new Map();\n    this._cacheCallQuery = /* @__PURE__ */ new Map();\n    this._cacheQuerySimple = /* @__PURE__ */ new Map();\n    this._engines = /* @__PURE__ */ new Map();\n    this._engines.set("not", notEngine);\n    this._engines.set("is", isEngine);\n    this._engines.set("where", isEngine);\n    this._engines.set("has", hasEngine);\n    this._engines.set("scope", scopeEngine);\n    this._engines.set("light", lightEngine);\n    this._engines.set("visible", visibleEngine);\n    this._engines.set("text", textEngine);\n    this._engines.set("text-is", textIsEngine);\n    this._engines.set("text-matches", textMatchesEngine);\n    this._engines.set("has-text", hasTextEngine);\n    this._engines.set("right-of", createLayoutEngine("right-of"));\n    this._engines.set("left-of", createLayoutEngine("left-of"));\n    this._engines.set("above", createLayoutEngine("above"));\n    this._engines.set("below", createLayoutEngine("below"));\n    this._engines.set("near", createLayoutEngine("near"));\n    this._engines.set("nth-match", nthMatchEngine);\n    const allNames = [...this._engines.keys()];\n    allNames.sort();\n    const parserNames = [...customCSSNames];\n    parserNames.sort();\n    if (allNames.join("|") !== parserNames.join("|"))\n      throw new Error(`Please keep customCSSNames in sync with evaluator engines: ${allNames.join("|")} vs ${parserNames.join("|")}`);\n  }\n  begin() {\n    ++this._retainCacheCounter;\n  }\n  end() {\n    --this._retainCacheCounter;\n    if (!this._retainCacheCounter) {\n      this._cacheQueryCSS.clear();\n      this._cacheMatches.clear();\n      this._cacheQuery.clear();\n      this._cacheMatchesSimple.clear();\n      this._cacheMatchesParents.clear();\n      this._cacheCallMatches.clear();\n      this._cacheCallQuery.clear();\n      this._cacheQuerySimple.clear();\n      this._cacheText.clear();\n    }\n  }\n  _cached(cache, main, rest, cb) {\n    if (!cache.has(main))\n      cache.set(main, []);\n    const entries = cache.get(main);\n    const entry = entries.find((e) => rest.every((value, index) => e.rest[index] === value));\n    if (entry)\n      return entry.result;\n    const result = cb();\n    entries.push({ rest, result });\n    return result;\n  }\n  _checkSelector(s) {\n    const wellFormed = typeof s === "object" && s && (Array.isArray(s) || "simples" in s && s.simples.length);\n    if (!wellFormed)\n      throw new Error(`Malformed selector "${s}"`);\n    return s;\n  }\n  matches(element, s, context) {\n    const selector = this._checkSelector(s);\n    this.begin();\n    try {\n      return this._cached(this._cacheMatches, element, [selector, context.scope, context.pierceShadow, context.originalScope], () => {\n        if (Array.isArray(selector))\n          return this._matchesEngine(isEngine, element, selector, context);\n        if (this._hasScopeClause(selector))\n          context = this._expandContextForScopeMatching(context);\n        if (!this._matchesSimple(element, selector.simples[selector.simples.length - 1].selector, context))\n          return false;\n        return this._matchesParents(element, selector, selector.simples.length - 2, context);\n      });\n    } finally {\n      this.end();\n    }\n  }\n  query(context, s) {\n    const selector = this._checkSelector(s);\n    this.begin();\n    try {\n      return this._cached(this._cacheQuery, selector, [context.scope, context.pierceShadow, context.originalScope], () => {\n        if (Array.isArray(selector))\n          return this._queryEngine(isEngine, context, selector);\n        if (this._hasScopeClause(selector))\n          context = this._expandContextForScopeMatching(context);\n        const previousScoreMap = this._scoreMap;\n        this._scoreMap = /* @__PURE__ */ new Map();\n        let elements = this._querySimple(context, selector.simples[selector.simples.length - 1].selector);\n        elements = elements.filter((element) => this._matchesParents(element, selector, selector.simples.length - 2, context));\n        if (this._scoreMap.size) {\n          elements.sort((a, b) => {\n            const aScore = this._scoreMap.get(a);\n            const bScore = this._scoreMap.get(b);\n            if (aScore === bScore)\n              return 0;\n            if (aScore === void 0)\n              return 1;\n            if (bScore === void 0)\n              return -1;\n            return aScore - bScore;\n          });\n        }\n        this._scoreMap = previousScoreMap;\n        return elements;\n      });\n    } finally {\n      this.end();\n    }\n  }\n  _markScore(element, score) {\n    if (this._scoreMap)\n      this._scoreMap.set(element, score);\n  }\n  _hasScopeClause(selector) {\n    return selector.simples.some((simple) => simple.selector.functions.some((f) => f.name === "scope"));\n  }\n  _expandContextForScopeMatching(context) {\n    if (context.scope.nodeType !== 1)\n      return context;\n    const scope = parentElementOrShadowHost(context.scope);\n    if (!scope)\n      return context;\n    return { ...context, scope, originalScope: context.originalScope || context.scope };\n  }\n  _matchesSimple(element, simple, context) {\n    return this._cached(this._cacheMatchesSimple, element, [simple, context.scope, context.pierceShadow, context.originalScope], () => {\n      if (element === context.scope)\n        return false;\n      if (simple.css && !this._matchesCSS(element, simple.css))\n        return false;\n      for (const func of simple.functions) {\n        if (!this._matchesEngine(this._getEngine(func.name), element, func.args, context))\n          return false;\n      }\n      return true;\n    });\n  }\n  _querySimple(context, simple) {\n    if (!simple.functions.length)\n      return this._queryCSS(context, simple.css || "*");\n    return this._cached(this._cacheQuerySimple, simple, [context.scope, context.pierceShadow, context.originalScope], () => {\n      let css = simple.css;\n      const funcs = simple.functions;\n      if (css === "*" && funcs.length)\n        css = void 0;\n      let elements;\n      let firstIndex = -1;\n      if (css !== void 0) {\n        elements = this._queryCSS(context, css);\n      } else {\n        firstIndex = funcs.findIndex((func) => this._getEngine(func.name).query !== void 0);\n        if (firstIndex === -1)\n          firstIndex = 0;\n        elements = this._queryEngine(this._getEngine(funcs[firstIndex].name), context, funcs[firstIndex].args);\n      }\n      for (let i = 0; i < funcs.length; i++) {\n        if (i === firstIndex)\n          continue;\n        const engine = this._getEngine(funcs[i].name);\n        if (engine.matches !== void 0)\n          elements = elements.filter((e) => this._matchesEngine(engine, e, funcs[i].args, context));\n      }\n      for (let i = 0; i < funcs.length; i++) {\n        if (i === firstIndex)\n          continue;\n        const engine = this._getEngine(funcs[i].name);\n        if (engine.matches === void 0)\n          elements = elements.filter((e) => this._matchesEngine(engine, e, funcs[i].args, context));\n      }\n      return elements;\n    });\n  }\n  _matchesParents(element, complex, index, context) {\n    if (index < 0)\n      return true;\n    return this._cached(this._cacheMatchesParents, element, [complex, index, context.scope, context.pierceShadow, context.originalScope], () => {\n      const { selector: simple, combinator } = complex.simples[index];\n      if (combinator === ">") {\n        const parent = parentElementOrShadowHostInContext(element, context);\n        if (!parent || !this._matchesSimple(parent, simple, context))\n          return false;\n        return this._matchesParents(parent, complex, index - 1, context);\n      }\n      if (combinator === "+") {\n        const previousSibling = previousSiblingInContext(element, context);\n        if (!previousSibling || !this._matchesSimple(previousSibling, simple, context))\n          return false;\n        return this._matchesParents(previousSibling, complex, index - 1, context);\n      }\n      if (combinator === "") {\n        let parent = parentElementOrShadowHostInContext(element, context);\n        while (parent) {\n          if (this._matchesSimple(parent, simple, context)) {\n            if (this._matchesParents(parent, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === "")\n              break;\n          }\n          parent = parentElementOrShadowHostInContext(parent, context);\n        }\n        return false;\n      }\n      if (combinator === "~") {\n        let previousSibling = previousSiblingInContext(element, context);\n        while (previousSibling) {\n          if (this._matchesSimple(previousSibling, simple, context)) {\n            if (this._matchesParents(previousSibling, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === "~")\n              break;\n          }\n          previousSibling = previousSiblingInContext(previousSibling, context);\n        }\n        return false;\n      }\n      if (combinator === ">=") {\n        let parent = element;\n        while (parent) {\n          if (this._matchesSimple(parent, simple, context)) {\n            if (this._matchesParents(parent, complex, index - 1, context))\n              return true;\n            if (complex.simples[index - 1].combinator === "")\n              break;\n          }\n          parent = parentElementOrShadowHostInContext(parent, context);\n        }\n        return false;\n      }\n      throw new Error(`Unsupported combinator "${combinator}"`);\n    });\n  }\n  _matchesEngine(engine, element, args, context) {\n    if (engine.matches)\n      return this._callMatches(engine, element, args, context);\n    if (engine.query)\n      return this._callQuery(engine, args, context).includes(element);\n    throw new Error(`Selector engine should implement "matches" or "query"`);\n  }\n  _queryEngine(engine, context, args) {\n    if (engine.query)\n      return this._callQuery(engine, args, context);\n    if (engine.matches)\n      return this._queryCSS(context, "*").filter((element) => this._callMatches(engine, element, args, context));\n    throw new Error(`Selector engine should implement "matches" or "query"`);\n  }\n  _callMatches(engine, element, args, context) {\n    return this._cached(this._cacheCallMatches, element, [engine, context.scope, context.pierceShadow, context.originalScope, ...args], () => {\n      return engine.matches(element, args, context, this);\n    });\n  }\n  _callQuery(engine, args, context) {\n    return this._cached(this._cacheCallQuery, engine, [context.scope, context.pierceShadow, context.originalScope, ...args], () => {\n      return engine.query(context, args, this);\n    });\n  }\n  _matchesCSS(element, css) {\n    return element.matches(css);\n  }\n  _queryCSS(context, css) {\n    return this._cached(this._cacheQueryCSS, css, [context.scope, context.pierceShadow, context.originalScope], () => {\n      let result = [];\n      function query(root) {\n        result = result.concat([...root.querySelectorAll(css)]);\n        if (!context.pierceShadow)\n          return;\n        if (root.shadowRoot)\n          query(root.shadowRoot);\n        for (const element of root.querySelectorAll("*")) {\n          if (element.shadowRoot)\n            query(element.shadowRoot);\n        }\n      }\n      query(context.scope);\n      return result;\n    });\n  }\n  _getEngine(name) {\n    const engine = this._engines.get(name);\n    if (!engine)\n      throw new Error(`Unknown selector engine "${name}"`);\n    return engine;\n  }\n};\nvar isEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`"is" engine expects non-empty selector list`);\n    return args.some((selector) => evaluator.matches(element, selector, context));\n  },\n  query(context, args, evaluator) {\n    if (args.length === 0)\n      throw new Error(`"is" engine expects non-empty selector list`);\n    let elements = [];\n    for (const arg of args)\n      elements = elements.concat(evaluator.query(context, arg));\n    return args.length === 1 ? elements : sortInDOMOrder(elements);\n  }\n};\nvar hasEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`"has" engine expects non-empty selector list`);\n    return evaluator.query({ ...context, scope: element }, args).length > 0;\n  }\n  // TODO: we can implement efficient "query" by matching "args" and returning\n  // all parents/descendants, just have to be careful with the ":scope" matching.\n};\nvar scopeEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 0)\n      throw new Error(`"scope" engine expects no arguments`);\n    const actualScope = context.originalScope || context.scope;\n    if (actualScope.nodeType === 9)\n      return element === actualScope.documentElement;\n    return element === actualScope;\n  },\n  query(context, args, evaluator) {\n    if (args.length !== 0)\n      throw new Error(`"scope" engine expects no arguments`);\n    const actualScope = context.originalScope || context.scope;\n    if (actualScope.nodeType === 9) {\n      const root = actualScope.documentElement;\n      return root ? [root] : [];\n    }\n    if (actualScope.nodeType === 1)\n      return [actualScope];\n    return [];\n  }\n};\nvar notEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0)\n      throw new Error(`"not" engine expects non-empty selector list`);\n    return !evaluator.matches(element, args, context);\n  }\n};\nvar lightEngine = {\n  query(context, args, evaluator) {\n    return evaluator.query({ ...context, pierceShadow: false }, args);\n  },\n  matches(element, args, context, evaluator) {\n    return evaluator.matches(element, args, { ...context, pierceShadow: false });\n  }\n};\nvar visibleEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length)\n      throw new Error(`"visible" engine expects no arguments`);\n    return isElementVisible(element);\n  }\n};\nvar textEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== "string")\n      throw new Error(`"text" engine expects a single string`);\n    const text = normalizeWhiteSpace(args[0]).toLowerCase();\n    const matcher = (elementText2) => elementText2.normalized.toLowerCase().includes(text);\n    return elementMatchesText(evaluator._cacheText, element, matcher) === "self";\n  }\n};\nvar textIsEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== "string")\n      throw new Error(`"text-is" engine expects a single string`);\n    const text = normalizeWhiteSpace(args[0]);\n    const matcher = (elementText2) => {\n      if (!text && !elementText2.immediate.length)\n        return true;\n      return elementText2.immediate.some((s) => normalizeWhiteSpace(s) === text);\n    };\n    return elementMatchesText(evaluator._cacheText, element, matcher) !== "none";\n  }\n};\nvar textMatchesEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length === 0 || typeof args[0] !== "string" || args.length > 2 || args.length === 2 && typeof args[1] !== "string")\n      throw new Error(`"text-matches" engine expects a regexp body and optional regexp flags`);\n    const re = new RegExp(args[0], args.length === 2 ? args[1] : void 0);\n    const matcher = (elementText2) => re.test(elementText2.full);\n    return elementMatchesText(evaluator._cacheText, element, matcher) === "self";\n  }\n};\nvar hasTextEngine = {\n  matches(element, args, context, evaluator) {\n    if (args.length !== 1 || typeof args[0] !== "string")\n      throw new Error(`"has-text" engine expects a single string`);\n    if (shouldSkipForTextMatching(element))\n      return false;\n    const text = normalizeWhiteSpace(args[0]).toLowerCase();\n    const matcher = (elementText2) => elementText2.normalized.toLowerCase().includes(text);\n    return matcher(elementText(evaluator._cacheText, element));\n  }\n};\nfunction createLayoutEngine(name) {\n  return {\n    matches(element, args, context, evaluator) {\n      const maxDistance = args.length && typeof args[args.length - 1] === "number" ? args[args.length - 1] : void 0;\n      const queryArgs = maxDistance === void 0 ? args : args.slice(0, args.length - 1);\n      if (args.length < 1 + (maxDistance === void 0 ? 0 : 1))\n        throw new Error(`"${name}" engine expects a selector list and optional maximum distance in pixels`);\n      const inner = evaluator.query(context, queryArgs);\n      const score = layoutSelectorScore(name, element, inner, maxDistance);\n      if (score === void 0)\n        return false;\n      evaluator._markScore(element, score);\n      return true;\n    }\n  };\n}\nvar nthMatchEngine = {\n  query(context, args, evaluator) {\n    let index = args[args.length - 1];\n    if (args.length < 2)\n      throw new Error(`"nth-match" engine expects non-empty selector list and an index argument`);\n    if (typeof index !== "number" || index < 1)\n      throw new Error(`"nth-match" engine expects a one-based index as the last argument`);\n    const elements = isEngine.query(context, args.slice(0, args.length - 1), evaluator);\n    index--;\n    return index < elements.length ? [elements[index]] : [];\n  }\n};\nfunction parentElementOrShadowHostInContext(element, context) {\n  if (element === context.scope)\n    return;\n  if (!context.pierceShadow)\n    return element.parentElement || void 0;\n  return parentElementOrShadowHost(element);\n}\nfunction previousSiblingInContext(element, context) {\n  if (element === context.scope)\n    return;\n  return element.previousElementSibling || void 0;\n}\nfunction sortInDOMOrder(elements) {\n  const elementToEntry = /* @__PURE__ */ new Map();\n  const roots = [];\n  const result = [];\n  function append(element) {\n    let entry = elementToEntry.get(element);\n    if (entry)\n      return entry;\n    const parent = parentElementOrShadowHost(element);\n    if (parent) {\n      const parentEntry = append(parent);\n      parentEntry.children.push(element);\n    } else {\n      roots.push(element);\n    }\n    entry = { children: [], taken: false };\n    elementToEntry.set(element, entry);\n    return entry;\n  }\n  for (const e of elements)\n    append(e).taken = true;\n  function visit(element) {\n    const entry = elementToEntry.get(element);\n    if (entry.taken)\n      result.push(element);\n    if (entry.children.length > 1) {\n      const set = new Set(entry.children);\n      entry.children = [];\n      let child = element.firstElementChild;\n      while (child && entry.children.length < set.size) {\n        if (set.has(child))\n          entry.children.push(child);\n        child = child.nextElementSibling;\n      }\n      child = element.shadowRoot ? element.shadowRoot.firstElementChild : null;\n      while (child && entry.children.length < set.size) {\n        if (set.has(child))\n          entry.children.push(child);\n        child = child.nextElementSibling;\n      }\n    }\n    entry.children.forEach(visit);\n  }\n  roots.forEach(visit);\n  return result;\n}\n\n// packages/injected/src/selectorGenerator.ts\nvar kTextScoreRange = 10;\nvar kExactPenalty = kTextScoreRange / 2;\nvar kTestIdScore = 1;\nvar kOtherTestIdScore = 2;\nvar kIframeByAttributeScore = 10;\nvar kBeginPenalizedScore = 50;\nvar kRoleWithNameScore = 100;\nvar kPlaceholderScore = 120;\nvar kLabelScore = 140;\nvar kAltTextScore = 160;\nvar kTextScore = 180;\nvar kTitleScore = 200;\nvar kTextScoreRegex = 250;\nvar kPlaceholderScoreExact = kPlaceholderScore + kExactPenalty;\nvar kLabelScoreExact = kLabelScore + kExactPenalty;\nvar kRoleWithNameScoreExact = kRoleWithNameScore + kExactPenalty;\nvar kAltTextScoreExact = kAltTextScore + kExactPenalty;\nvar kTextScoreExact = kTextScore + kExactPenalty;\nvar kTitleScoreExact = kTitleScore + kExactPenalty;\nvar kEndPenalizedScore = 300;\nvar kCSSIdScore = 500;\nvar kRoleWithoutNameScore = 510;\nvar kCSSInputTypeNameScore = 520;\nvar kCSSTagNameScore = 530;\nvar kNthScore = 1e4;\nvar kCSSFallbackScore = 1e7;\nvar kScoreThresholdForTextExpect = 1e3;\nfunction generateSelector(injectedScript, targetElement, options) {\n  var _a;\n  injectedScript._evaluator.begin();\n  const cache = { allowText: /* @__PURE__ */ new Map(), disallowText: /* @__PURE__ */ new Map() };\n  beginAriaCaches();\n  beginDOMCaches();\n  try {\n    let selectors = [];\n    if (options.forTextExpect) {\n      let targetTokens = cssFallback(injectedScript, targetElement.ownerDocument.documentElement, options);\n      for (let element = targetElement; element; element = parentElementOrShadowHost(element)) {\n        const tokens = generateSelectorFor(cache, injectedScript, element, { ...options, noText: true });\n        if (!tokens)\n          continue;\n        const score = combineScores(tokens);\n        if (score <= kScoreThresholdForTextExpect) {\n          targetTokens = tokens;\n          break;\n        }\n      }\n      selectors = [joinTokens(targetTokens)];\n    } else {\n      if (!targetElement.matches("input,textarea,select") && !targetElement.isContentEditable) {\n        const interactiveParent = closestCrossShadow(targetElement, "button,select,input,[role=button],[role=checkbox],[role=radio],a,[role=link]", options.root);\n        if (interactiveParent && isElementVisible(interactiveParent))\n          targetElement = interactiveParent;\n      }\n      if (options.multiple) {\n        const withText = generateSelectorFor(cache, injectedScript, targetElement, options);\n        const withoutText = generateSelectorFor(cache, injectedScript, targetElement, { ...options, noText: true });\n        let tokens = [withText, withoutText];\n        cache.allowText.clear();\n        cache.disallowText.clear();\n        if (withText && hasCSSIdToken(withText))\n          tokens.push(generateSelectorFor(cache, injectedScript, targetElement, { ...options, noCSSId: true }));\n        if (withoutText && hasCSSIdToken(withoutText))\n          tokens.push(generateSelectorFor(cache, injectedScript, targetElement, { ...options, noText: true, noCSSId: true }));\n        tokens = tokens.filter(Boolean);\n        if (!tokens.length) {\n          const css = cssFallback(injectedScript, targetElement, options);\n          tokens.push(css);\n          if (hasCSSIdToken(css))\n            tokens.push(cssFallback(injectedScript, targetElement, { ...options, noCSSId: true }));\n        }\n        selectors = [...new Set(tokens.map((t) => joinTokens(t)))];\n      } else {\n        const targetTokens = generateSelectorFor(cache, injectedScript, targetElement, options) || cssFallback(injectedScript, targetElement, options);\n        selectors = [joinTokens(targetTokens)];\n      }\n    }\n    const selector = selectors[0];\n    const parsedSelector = injectedScript.parseSelector(selector);\n    return {\n      selector,\n      selectors,\n      elements: injectedScript.querySelectorAll(parsedSelector, (_a = options.root) != null ? _a : targetElement.ownerDocument)\n    };\n  } finally {\n    endDOMCaches();\n    endAriaCaches();\n    injectedScript._evaluator.end();\n  }\n}\nfunction generateSelectorFor(cache, injectedScript, targetElement, options) {\n  var _a;\n  if (options.root && !isInsideScope(options.root, targetElement))\n    throw new Error(`Target element must belong to the root\'s subtree`);\n  if (targetElement === options.root)\n    return [{ engine: "css", selector: ":scope", score: 1 }];\n  if (targetElement.ownerDocument.documentElement === targetElement)\n    return [{ engine: "css", selector: "html", score: 1 }];\n  let result = null;\n  const updateResult = (candidate) => {\n    if (!result || combineScores(candidate) < combineScores(result))\n      result = candidate;\n  };\n  const candidates = [];\n  if (!options.noText) {\n    for (const candidate of buildTextCandidates(injectedScript, targetElement, !options.isRecursive))\n      candidates.push({ candidate, isTextCandidate: true });\n  }\n  for (const token of buildNoTextCandidates(injectedScript, targetElement, options)) {\n    if (options.omitInternalEngines && token.engine.startsWith("internal:"))\n      continue;\n    candidates.push({ candidate: [token], isTextCandidate: false });\n  }\n  candidates.sort((a, b) => combineScores(a.candidate) - combineScores(b.candidate));\n  for (const { candidate, isTextCandidate } of candidates) {\n    const elements = injectedScript.querySelectorAll(injectedScript.parseSelector(joinTokens(candidate)), (_a = options.root) != null ? _a : targetElement.ownerDocument);\n    if (!elements.includes(targetElement)) {\n      continue;\n    }\n    if (elements.length === 1) {\n      updateResult(candidate);\n      break;\n    }\n    const index = elements.indexOf(targetElement);\n    if (index > 5) {\n      continue;\n    }\n    updateResult([...candidate, { engine: "nth", selector: String(index), score: kNthScore }]);\n    if (options.isRecursive) {\n      continue;\n    }\n    for (let parent = parentElementOrShadowHost(targetElement); parent && parent !== options.root; parent = parentElementOrShadowHost(parent)) {\n      const filtered = elements.filter((e) => isInsideScope(parent, e) && e !== parent);\n      const newIndex = filtered.indexOf(targetElement);\n      if (filtered.length > 5 || newIndex === -1 || newIndex === index && filtered.length > 1) {\n        continue;\n      }\n      const inParent = filtered.length === 1 ? candidate : [...candidate, { engine: "nth", selector: String(newIndex), score: kNthScore }];\n      const idealSelectorForParent = { engine: "", selector: "", score: 1 };\n      if (result && combineScores([idealSelectorForParent, ...inParent]) >= combineScores(result)) {\n        continue;\n      }\n      const noText = !!options.noText || isTextCandidate;\n      const cacheMap = noText ? cache.disallowText : cache.allowText;\n      let parentTokens = cacheMap.get(parent);\n      if (parentTokens === void 0) {\n        parentTokens = generateSelectorFor(cache, injectedScript, parent, { ...options, isRecursive: true, noText }) || cssFallback(injectedScript, parent, options);\n        cacheMap.set(parent, parentTokens);\n      }\n      if (!parentTokens)\n        continue;\n      updateResult([...parentTokens, ...inParent]);\n    }\n  }\n  return result;\n}\nfunction buildNoTextCandidates(injectedScript, element, options) {\n  const candidates = [];\n  {\n    for (const attr of ["data-testid", "data-test-id", "data-test"]) {\n      if (attr !== options.testIdAttributeName && element.getAttribute(attr))\n        candidates.push({ engine: "css", selector: `[${attr}=${quoteCSSAttributeValue(element.getAttribute(attr))}]`, score: kOtherTestIdScore });\n    }\n    if (!options.noCSSId) {\n      const idAttr = element.getAttribute("id");\n      if (idAttr && !isGuidLike(idAttr))\n        candidates.push({ engine: "css", selector: makeSelectorForId(idAttr), score: kCSSIdScore });\n    }\n    candidates.push({ engine: "css", selector: escapeNodeName(element), score: kCSSTagNameScore });\n  }\n  if (element.nodeName === "IFRAME") {\n    for (const attribute of ["name", "title"]) {\n      if (element.getAttribute(attribute))\n        candidates.push({ engine: "css", selector: `${escapeNodeName(element)}[${attribute}=${quoteCSSAttributeValue(element.getAttribute(attribute))}]`, score: kIframeByAttributeScore });\n    }\n    if (element.getAttribute(options.testIdAttributeName))\n      candidates.push({ engine: "css", selector: `[${options.testIdAttributeName}=${quoteCSSAttributeValue(element.getAttribute(options.testIdAttributeName))}]`, score: kTestIdScore });\n    penalizeScoreForLength([candidates]);\n    return candidates;\n  }\n  if (element.getAttribute(options.testIdAttributeName))\n    candidates.push({ engine: "internal:testid", selector: `[${options.testIdAttributeName}=${escapeForAttributeSelector(element.getAttribute(options.testIdAttributeName), true)}]`, score: kTestIdScore });\n  if (element.nodeName === "INPUT" || element.nodeName === "TEXTAREA") {\n    const input = element;\n    if (input.placeholder) {\n      candidates.push({ engine: "internal:attr", selector: `[placeholder=${escapeForAttributeSelector(input.placeholder, true)}]`, score: kPlaceholderScoreExact });\n      for (const alternative of suitableTextAlternatives(input.placeholder))\n        candidates.push({ engine: "internal:attr", selector: `[placeholder=${escapeForAttributeSelector(alternative.text, false)}]`, score: kPlaceholderScore - alternative.scoreBonus });\n    }\n  }\n  const labels = getElementLabels(injectedScript._evaluator._cacheText, element);\n  for (const label of labels) {\n    const labelText = label.normalized;\n    candidates.push({ engine: "internal:label", selector: escapeForTextSelector(labelText, true), score: kLabelScoreExact });\n    for (const alternative of suitableTextAlternatives(labelText))\n      candidates.push({ engine: "internal:label", selector: escapeForTextSelector(alternative.text, false), score: kLabelScore - alternative.scoreBonus });\n  }\n  const ariaRole = getAriaRole(element);\n  if (ariaRole && !["none", "presentation"].includes(ariaRole))\n    candidates.push({ engine: "internal:role", selector: ariaRole, score: kRoleWithoutNameScore });\n  if (element.getAttribute("name") && ["BUTTON", "FORM", "FIELDSET", "FRAME", "IFRAME", "INPUT", "KEYGEN", "OBJECT", "OUTPUT", "SELECT", "TEXTAREA", "MAP", "META", "PARAM"].includes(element.nodeName))\n    candidates.push({ engine: "css", selector: `${escapeNodeName(element)}[name=${quoteCSSAttributeValue(element.getAttribute("name"))}]`, score: kCSSInputTypeNameScore });\n  if (["INPUT", "TEXTAREA"].includes(element.nodeName) && element.getAttribute("type") !== "hidden") {\n    if (element.getAttribute("type"))\n      candidates.push({ engine: "css", selector: `${escapeNodeName(element)}[type=${quoteCSSAttributeValue(element.getAttribute("type"))}]`, score: kCSSInputTypeNameScore });\n  }\n  if (["INPUT", "TEXTAREA", "SELECT"].includes(element.nodeName) && element.getAttribute("type") !== "hidden")\n    candidates.push({ engine: "css", selector: escapeNodeName(element), score: kCSSInputTypeNameScore + 1 });\n  penalizeScoreForLength([candidates]);\n  return candidates;\n}\nfunction buildTextCandidates(injectedScript, element, isTargetNode) {\n  if (element.nodeName === "SELECT")\n    return [];\n  const candidates = [];\n  const title = element.getAttribute("title");\n  if (title) {\n    candidates.push([{ engine: "internal:attr", selector: `[title=${escapeForAttributeSelector(title, true)}]`, score: kTitleScoreExact }]);\n    for (const alternative of suitableTextAlternatives(title))\n      candidates.push([{ engine: "internal:attr", selector: `[title=${escapeForAttributeSelector(alternative.text, false)}]`, score: kTitleScore - alternative.scoreBonus }]);\n  }\n  const alt = element.getAttribute("alt");\n  if (alt && ["APPLET", "AREA", "IMG", "INPUT"].includes(element.nodeName)) {\n    candidates.push([{ engine: "internal:attr", selector: `[alt=${escapeForAttributeSelector(alt, true)}]`, score: kAltTextScoreExact }]);\n    for (const alternative of suitableTextAlternatives(alt))\n      candidates.push([{ engine: "internal:attr", selector: `[alt=${escapeForAttributeSelector(alternative.text, false)}]`, score: kAltTextScore - alternative.scoreBonus }]);\n  }\n  const text = elementText(injectedScript._evaluator._cacheText, element).normalized;\n  const textAlternatives = text ? suitableTextAlternatives(text) : [];\n  if (text) {\n    if (isTargetNode) {\n      if (text.length <= 80)\n        candidates.push([{ engine: "internal:text", selector: escapeForTextSelector(text, true), score: kTextScoreExact }]);\n      for (const alternative of textAlternatives)\n        candidates.push([{ engine: "internal:text", selector: escapeForTextSelector(alternative.text, false), score: kTextScore - alternative.scoreBonus }]);\n    }\n    const cssToken = { engine: "css", selector: escapeNodeName(element), score: kCSSTagNameScore };\n    for (const alternative of textAlternatives)\n      candidates.push([cssToken, { engine: "internal:has-text", selector: escapeForTextSelector(alternative.text, false), score: kTextScore - alternative.scoreBonus }]);\n    if (isTargetNode && text.length <= 80) {\n      const re = new RegExp("^" + escapeRegExp(text) + "$");\n      candidates.push([cssToken, { engine: "internal:has-text", selector: escapeForTextSelector(re, false), score: kTextScoreRegex }]);\n    }\n  }\n  const ariaRole = getAriaRole(element);\n  if (ariaRole && !["none", "presentation"].includes(ariaRole)) {\n    const ariaName = getElementAccessibleName(element, false);\n    if (ariaName && !ariaName.match(/^\\p{Co}+$/u)) {\n      const roleToken = { engine: "internal:role", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, true)}]`, score: kRoleWithNameScoreExact };\n      candidates.push([roleToken]);\n      for (const alternative of suitableTextAlternatives(ariaName))\n        candidates.push([{ engine: "internal:role", selector: `${ariaRole}[name=${escapeForAttributeSelector(alternative.text, false)}]`, score: kRoleWithNameScore - alternative.scoreBonus }]);\n    } else {\n      const roleToken = { engine: "internal:role", selector: `${ariaRole}`, score: kRoleWithoutNameScore };\n      for (const alternative of textAlternatives)\n        candidates.push([roleToken, { engine: "internal:has-text", selector: escapeForTextSelector(alternative.text, false), score: kTextScore - alternative.scoreBonus }]);\n      if (isTargetNode && text.length <= 80) {\n        const re = new RegExp("^" + escapeRegExp(text) + "$");\n        candidates.push([roleToken, { engine: "internal:has-text", selector: escapeForTextSelector(re, false), score: kTextScoreRegex }]);\n      }\n    }\n  }\n  penalizeScoreForLength(candidates);\n  return candidates;\n}\nfunction makeSelectorForId(id) {\n  return /^[a-zA-Z][a-zA-Z0-9\\-\\_]+$/.test(id) ? "#" + id : `[id=${quoteCSSAttributeValue(id)}]`;\n}\nfunction hasCSSIdToken(tokens) {\n  return tokens.some((token) => token.engine === "css" && (token.selector.startsWith("#") || token.selector.startsWith(\'[id="\')));\n}\nfunction cssFallback(injectedScript, targetElement, options) {\n  var _a;\n  const root = (_a = options.root) != null ? _a : targetElement.ownerDocument;\n  const tokens = [];\n  function uniqueCSSSelector(prefix) {\n    const path = tokens.slice();\n    if (prefix)\n      path.unshift(prefix);\n    const selector = path.join(" > ");\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const node = injectedScript.querySelector(parsedSelector, root, false);\n    return node === targetElement ? selector : void 0;\n  }\n  function makeStrict(selector) {\n    const token = { engine: "css", selector, score: kCSSFallbackScore };\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const elements = injectedScript.querySelectorAll(parsedSelector, root);\n    if (elements.length === 1)\n      return [token];\n    const nth = { engine: "nth", selector: String(elements.indexOf(targetElement)), score: kNthScore };\n    return [token, nth];\n  }\n  for (let element = targetElement; element && element !== root; element = parentElementOrShadowHost(element)) {\n    let bestTokenForLevel = "";\n    if (element.id && !options.noCSSId) {\n      const token = makeSelectorForId(element.id);\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      bestTokenForLevel = token;\n    }\n    const parent = element.parentNode;\n    const classes = [...element.classList].map(escapeClassName);\n    for (let i = 0; i < classes.length; ++i) {\n      const token = "." + classes.slice(0, i + 1).join(".");\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel && parent) {\n        const sameClassSiblings = parent.querySelectorAll(token);\n        if (sameClassSiblings.length === 1)\n          bestTokenForLevel = token;\n      }\n    }\n    if (parent) {\n      const siblings = [...parent.children];\n      const nodeName = element.nodeName;\n      const sameTagSiblings = siblings.filter((sibling) => sibling.nodeName === nodeName);\n      const token = sameTagSiblings.indexOf(element) === 0 ? escapeNodeName(element) : `${escapeNodeName(element)}:nth-child(${1 + siblings.indexOf(element)})`;\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel)\n        bestTokenForLevel = token;\n    } else if (!bestTokenForLevel) {\n      bestTokenForLevel = escapeNodeName(element);\n    }\n    tokens.unshift(bestTokenForLevel);\n  }\n  return makeStrict(uniqueCSSSelector());\n}\nfunction penalizeScoreForLength(groups) {\n  for (const group of groups) {\n    for (const token of group) {\n      if (token.score > kBeginPenalizedScore && token.score < kEndPenalizedScore)\n        token.score += Math.min(kTextScoreRange, token.selector.length / 10 | 0);\n    }\n  }\n}\nfunction joinTokens(tokens) {\n  const parts = [];\n  let lastEngine = "";\n  for (const { engine, selector } of tokens) {\n    if (parts.length && (lastEngine !== "css" || engine !== "css" || selector.startsWith(":nth-match(")))\n      parts.push(">>");\n    lastEngine = engine;\n    if (engine === "css")\n      parts.push(selector);\n    else\n      parts.push(`${engine}=${selector}`);\n  }\n  return parts.join(" ");\n}\nfunction combineScores(tokens) {\n  let score = 0;\n  for (let i = 0; i < tokens.length; i++)\n    score += tokens[i].score * (tokens.length - i);\n  return score;\n}\nfunction isGuidLike(id) {\n  let lastCharacterType;\n  let transitionCount = 0;\n  for (let i = 0; i < id.length; ++i) {\n    const c = id[i];\n    let characterType;\n    if (c === "-" || c === "_")\n      continue;\n    if (c >= "a" && c <= "z")\n      characterType = "lower";\n    else if (c >= "A" && c <= "Z")\n      characterType = "upper";\n    else if (c >= "0" && c <= "9")\n      characterType = "digit";\n    else\n      characterType = "other";\n    if (characterType === "lower" && lastCharacterType === "upper") {\n      lastCharacterType = characterType;\n      continue;\n    }\n    if (lastCharacterType && lastCharacterType !== characterType)\n      ++transitionCount;\n    lastCharacterType = characterType;\n  }\n  return transitionCount >= id.length / 4;\n}\nfunction trimWordBoundary(text, maxLength) {\n  if (text.length <= maxLength)\n    return text;\n  text = text.substring(0, maxLength);\n  const match = text.match(/^(.*)\\b(.+?)$/);\n  if (!match)\n    return "";\n  return match[1].trimEnd();\n}\nfunction suitableTextAlternatives(text) {\n  let result = [];\n  {\n    const match = text.match(/^([\\d.,]+)[^.,\\w]/);\n    const leadingNumberLength = match ? match[1].length : 0;\n    if (leadingNumberLength) {\n      const alt = trimWordBoundary(text.substring(leadingNumberLength).trimStart(), 80);\n      result.push({ text: alt, scoreBonus: alt.length <= 30 ? 2 : 1 });\n    }\n  }\n  {\n    const match = text.match(/[^.,\\w]([\\d.,]+)$/);\n    const trailingNumberLength = match ? match[1].length : 0;\n    if (trailingNumberLength) {\n      const alt = trimWordBoundary(text.substring(0, text.length - trailingNumberLength).trimEnd(), 80);\n      result.push({ text: alt, scoreBonus: alt.length <= 30 ? 2 : 1 });\n    }\n  }\n  if (text.length <= 30) {\n    result.push({ text, scoreBonus: 0 });\n  } else {\n    result.push({ text: trimWordBoundary(text, 80), scoreBonus: 0 });\n    result.push({ text: trimWordBoundary(text, 30), scoreBonus: 1 });\n  }\n  result = result.filter((r) => r.text);\n  if (!result.length)\n    result.push({ text: text.substring(0, 80), scoreBonus: 0 });\n  return result;\n}\nfunction escapeNodeName(node) {\n  return node.nodeName.toLocaleLowerCase().replace(/[:\\.]/g, (char) => "\\\\" + char);\n}\nfunction escapeClassName(className) {\n  let result = "";\n  for (let i = 0; i < className.length; i++)\n    result += cssEscapeCharacter(className, i);\n  return result;\n}\nfunction cssEscapeCharacter(s, i) {\n  const c = s.charCodeAt(i);\n  if (c === 0)\n    return "\\uFFFD";\n  if (c >= 1 && c <= 31 || c >= 48 && c <= 57 && (i === 0 || i === 1 && s.charCodeAt(0) === 45))\n    return "\\\\" + c.toString(16) + " ";\n  if (i === 0 && c === 45 && s.length === 1)\n    return "\\\\" + s.charAt(i);\n  if (c >= 128 || c === 45 || c === 95 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122)\n    return s.charAt(i);\n  return "\\\\" + s.charAt(i);\n}\n\n// packages/injected/src/vueSelectorEngine.ts\nfunction basename(filename, ext) {\n  const normalized = filename.replace(/^[a-zA-Z]:/, "").replace(/\\\\/g, "/");\n  let result = normalized.substring(normalized.lastIndexOf("/") + 1);\n  if (ext && result.endsWith(ext))\n    result = result.substring(0, result.length - ext.length);\n  return result;\n}\nfunction toUpper(_, c) {\n  return c ? c.toUpperCase() : "";\n}\nvar classifyRE = /(?:^|[-_/])(\\w)/g;\nvar classify = (str) => {\n  return str && str.replace(classifyRE, toUpper);\n};\nfunction buildComponentsTreeVue3(instance) {\n  function getComponentTypeName(options) {\n    const name = options.name || options._componentTag || options.__playwright_guessedName;\n    if (name)\n      return name;\n    const file = options.__file;\n    if (file)\n      return classify(basename(file, ".vue"));\n  }\n  function saveComponentName(instance2, key) {\n    instance2.type.__playwright_guessedName = key;\n    return key;\n  }\n  function getInstanceName(instance2) {\n    var _a, _b, _c, _d;\n    const name = getComponentTypeName(instance2.type || {});\n    if (name)\n      return name;\n    if (instance2.root === instance2)\n      return "Root";\n    for (const key in (_b = (_a = instance2.parent) == null ? void 0 : _a.type) == null ? void 0 : _b.components) {\n      if (((_c = instance2.parent) == null ? void 0 : _c.type.components[key]) === instance2.type)\n        return saveComponentName(instance2, key);\n    }\n    for (const key in (_d = instance2.appContext) == null ? void 0 : _d.components) {\n      if (instance2.appContext.components[key] === instance2.type)\n        return saveComponentName(instance2, key);\n    }\n    return "Anonymous Component";\n  }\n  function isBeingDestroyed(instance2) {\n    return instance2._isBeingDestroyed || instance2.isUnmounted;\n  }\n  function isFragment(instance2) {\n    return instance2.subTree.type.toString() === "Symbol(Fragment)";\n  }\n  function getInternalInstanceChildren(subTree) {\n    const list = [];\n    if (subTree.component)\n      list.push(subTree.component);\n    if (subTree.suspense)\n      list.push(...getInternalInstanceChildren(subTree.suspense.activeBranch));\n    if (Array.isArray(subTree.children)) {\n      subTree.children.forEach((childSubTree) => {\n        if (childSubTree.component)\n          list.push(childSubTree.component);\n        else\n          list.push(...getInternalInstanceChildren(childSubTree));\n      });\n    }\n    return list.filter((child) => {\n      var _a;\n      return !isBeingDestroyed(child) && !((_a = child.type.devtools) == null ? void 0 : _a.hide);\n    });\n  }\n  function getRootElementsFromComponentInstance(instance2) {\n    if (isFragment(instance2))\n      return getFragmentRootElements(instance2.subTree);\n    return [instance2.subTree.el];\n  }\n  function getFragmentRootElements(vnode) {\n    if (!vnode.children)\n      return [];\n    const list = [];\n    for (let i = 0, l = vnode.children.length; i < l; i++) {\n      const childVnode = vnode.children[i];\n      if (childVnode.component)\n        list.push(...getRootElementsFromComponentInstance(childVnode.component));\n      else if (childVnode.el)\n        list.push(childVnode.el);\n    }\n    return list;\n  }\n  function buildComponentsTree2(instance2) {\n    return {\n      name: getInstanceName(instance2),\n      children: getInternalInstanceChildren(instance2.subTree).map(buildComponentsTree2),\n      rootElements: getRootElementsFromComponentInstance(instance2),\n      props: instance2.props\n    };\n  }\n  return buildComponentsTree2(instance);\n}\nfunction buildComponentsTreeVue2(instance) {\n  function getComponentName2(options) {\n    const name = options.displayName || options.name || options._componentTag;\n    if (name)\n      return name;\n    const file = options.__file;\n    if (file)\n      return classify(basename(file, ".vue"));\n  }\n  function getInstanceName(instance2) {\n    const name = getComponentName2(instance2.$options || instance2.fnOptions || {});\n    if (name)\n      return name;\n    return instance2.$root === instance2 ? "Root" : "Anonymous Component";\n  }\n  function getInternalInstanceChildren(instance2) {\n    if (instance2.$children)\n      return instance2.$children;\n    if (Array.isArray(instance2.subTree.children))\n      return instance2.subTree.children.filter((vnode) => !!vnode.component).map((vnode) => vnode.component);\n    return [];\n  }\n  function buildComponentsTree2(instance2) {\n    return {\n      name: getInstanceName(instance2),\n      children: getInternalInstanceChildren(instance2).map(buildComponentsTree2),\n      rootElements: [instance2.$el],\n      props: instance2._props\n    };\n  }\n  return buildComponentsTree2(instance);\n}\nfunction filterComponentsTree2(treeNode, searchFn, result = []) {\n  if (searchFn(treeNode))\n    result.push(treeNode);\n  for (const child of treeNode.children)\n    filterComponentsTree2(child, searchFn, result);\n  return result;\n}\nfunction findVueRoots(root, roots = []) {\n  const document = root.ownerDocument || root;\n  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n  const vue2Roots = /* @__PURE__ */ new Set();\n  do {\n    const node = walker.currentNode;\n    if (node.__vue__)\n      vue2Roots.add(node.__vue__.$root);\n    if (node.__vue_app__ && node._vnode && node._vnode.component)\n      roots.push({ root: node._vnode.component, version: 3 });\n    const shadowRoot = node instanceof Element ? node.shadowRoot : null;\n    if (shadowRoot)\n      findVueRoots(shadowRoot, roots);\n  } while (walker.nextNode());\n  for (const vue2root of vue2Roots) {\n    roots.push({\n      version: 2,\n      root: vue2root\n    });\n  }\n  return roots;\n}\nvar createVueEngine = () => ({\n  queryAll(scope, selector) {\n    const document = scope.ownerDocument || scope;\n    const { name, attributes } = parseAttributeSelector(selector, false);\n    const vueRoots = findVueRoots(document);\n    const trees = vueRoots.map((vueRoot) => vueRoot.version === 3 ? buildComponentsTreeVue3(vueRoot.root) : buildComponentsTreeVue2(vueRoot.root));\n    const treeNodes = trees.map((tree) => filterComponentsTree2(tree, (treeNode) => {\n      if (name && treeNode.name !== name)\n        return false;\n      if (treeNode.rootElements.some((rootElement) => !isInsideScope(scope, rootElement)))\n        return false;\n      for (const attr of attributes) {\n        if (!matchesComponentAttribute(treeNode.props, attr))\n          return false;\n      }\n      return true;\n    })).flat();\n    const allRootElements = /* @__PURE__ */ new Set();\n    for (const treeNode of treeNodes) {\n      for (const rootElement of treeNode.rootElements)\n        allRootElements.add(rootElement);\n    }\n    return [...allRootElements];\n  }\n});\n\n// packages/injected/src/xpathSelectorEngine.ts\nvar XPathEngine = {\n  queryAll(root, selector) {\n    if (selector.startsWith("/") && root.nodeType !== Node.DOCUMENT_NODE)\n      selector = "." + selector;\n    const result = [];\n    const document = root.ownerDocument || root;\n    if (!document)\n      return result;\n    const it = document.evaluate(selector, root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);\n    for (let node = it.iterateNext(); node; node = it.iterateNext()) {\n      if (node.nodeType === Node.ELEMENT_NODE)\n        result.push(node);\n    }\n    return result;\n  }\n};\n\n// packages/playwright-core/src/utils/isomorphic/locatorUtils.ts\nfunction getByAttributeTextSelector(attrName, text, options) {\n  return `internal:attr=[${attrName}=${escapeForAttributeSelector(text, (options == null ? void 0 : options.exact) || false)}]`;\n}\nfunction getByTestIdSelector(testIdAttributeName, testId) {\n  return `internal:testid=[${testIdAttributeName}=${escapeForAttributeSelector(testId, true)}]`;\n}\nfunction getByLabelSelector(text, options) {\n  return "internal:label=" + escapeForTextSelector(text, !!(options == null ? void 0 : options.exact));\n}\nfunction getByAltTextSelector(text, options) {\n  return getByAttributeTextSelector("alt", text, options);\n}\nfunction getByTitleSelector(text, options) {\n  return getByAttributeTextSelector("title", text, options);\n}\nfunction getByPlaceholderSelector(text, options) {\n  return getByAttributeTextSelector("placeholder", text, options);\n}\nfunction getByTextSelector(text, options) {\n  return "internal:text=" + escapeForTextSelector(text, !!(options == null ? void 0 : options.exact));\n}\nfunction getByRoleSelector(role, options = {}) {\n  const props = [];\n  if (options.checked !== void 0)\n    props.push(["checked", String(options.checked)]);\n  if (options.disabled !== void 0)\n    props.push(["disabled", String(options.disabled)]);\n  if (options.selected !== void 0)\n    props.push(["selected", String(options.selected)]);\n  if (options.expanded !== void 0)\n    props.push(["expanded", String(options.expanded)]);\n  if (options.includeHidden !== void 0)\n    props.push(["include-hidden", String(options.includeHidden)]);\n  if (options.level !== void 0)\n    props.push(["level", String(options.level)]);\n  if (options.name !== void 0)\n    props.push(["name", escapeForAttributeSelector(options.name, !!options.exact)]);\n  if (options.pressed !== void 0)\n    props.push(["pressed", String(options.pressed)]);\n  return `internal:role=${role}${props.map(([n, v]) => `[${n}=${v}]`).join("")}`;\n}\n\n// packages/injected/src/consoleApi.ts\nvar selectorSymbol = Symbol("selector");\nselectorSymbol;\nvar _Locator = class _Locator {\n  constructor(injectedScript, selector, options) {\n    if (options == null ? void 0 : options.hasText)\n      selector += ` >> internal:has-text=${escapeForTextSelector(options.hasText, false)}`;\n    if (options == null ? void 0 : options.hasNotText)\n      selector += ` >> internal:has-not-text=${escapeForTextSelector(options.hasNotText, false)}`;\n    if (options == null ? void 0 : options.has)\n      selector += ` >> internal:has=` + JSON.stringify(options.has[selectorSymbol]);\n    if (options == null ? void 0 : options.hasNot)\n      selector += ` >> internal:has-not=` + JSON.stringify(options.hasNot[selectorSymbol]);\n    if ((options == null ? void 0 : options.visible) !== void 0)\n      selector += ` >> visible=${options.visible ? "true" : "false"}`;\n    this[selectorSymbol] = selector;\n    if (selector) {\n      const parsed = injectedScript.parseSelector(selector);\n      this.element = injectedScript.querySelector(parsed, injectedScript.document, false);\n      this.elements = injectedScript.querySelectorAll(parsed, injectedScript.document);\n    }\n    const selectorBase = selector;\n    const self = this;\n    self.locator = (selector2, options2) => {\n      return new _Locator(injectedScript, selectorBase ? selectorBase + " >> " + selector2 : selector2, options2);\n    };\n    self.getByTestId = (testId) => self.locator(getByTestIdSelector(injectedScript.testIdAttributeNameForStrictErrorAndConsoleCodegen(), testId));\n    self.getByAltText = (text, options2) => self.locator(getByAltTextSelector(text, options2));\n    self.getByLabel = (text, options2) => self.locator(getByLabelSelector(text, options2));\n    self.getByPlaceholder = (text, options2) => self.locator(getByPlaceholderSelector(text, options2));\n    self.getByText = (text, options2) => self.locator(getByTextSelector(text, options2));\n    self.getByTitle = (text, options2) => self.locator(getByTitleSelector(text, options2));\n    self.getByRole = (role, options2 = {}) => self.locator(getByRoleSelector(role, options2));\n    self.filter = (options2) => new _Locator(injectedScript, selector, options2);\n    self.first = () => self.locator("nth=0");\n    self.last = () => self.locator("nth=-1");\n    self.nth = (index) => self.locator(`nth=${index}`);\n    self.and = (locator) => new _Locator(injectedScript, selectorBase + ` >> internal:and=` + JSON.stringify(locator[selectorSymbol]));\n    self.or = (locator) => new _Locator(injectedScript, selectorBase + ` >> internal:or=` + JSON.stringify(locator[selectorSymbol]));\n  }\n};\nvar Locator = _Locator;\nvar ConsoleAPI = class {\n  constructor(injectedScript) {\n    this._injectedScript = injectedScript;\n  }\n  install() {\n    if (this._injectedScript.window.playwright)\n      return;\n    this._injectedScript.window.playwright = {\n      $: (selector, strict) => this._querySelector(selector, !!strict),\n      $$: (selector) => this._querySelectorAll(selector),\n      inspect: (selector) => this._inspect(selector),\n      selector: (element) => this._selector(element),\n      generateLocator: (element, language) => this._generateLocator(element, language),\n      ariaSnapshot: (element, options) => {\n        return this._injectedScript.ariaSnapshot(element || this._injectedScript.document.body, options || { mode: "expect" });\n      },\n      resume: () => this._resume(),\n      ...new Locator(this._injectedScript, "")\n    };\n    delete this._injectedScript.window.playwright.filter;\n    delete this._injectedScript.window.playwright.first;\n    delete this._injectedScript.window.playwright.last;\n    delete this._injectedScript.window.playwright.nth;\n    delete this._injectedScript.window.playwright.and;\n    delete this._injectedScript.window.playwright.or;\n  }\n  _querySelector(selector, strict) {\n    if (typeof selector !== "string")\n      throw new Error(`Usage: playwright.query(\'Playwright >> selector\').`);\n    const parsed = this._injectedScript.parseSelector(selector);\n    return this._injectedScript.querySelector(parsed, this._injectedScript.document, strict);\n  }\n  _querySelectorAll(selector) {\n    if (typeof selector !== "string")\n      throw new Error(`Usage: playwright.$$(\'Playwright >> selector\').`);\n    const parsed = this._injectedScript.parseSelector(selector);\n    return this._injectedScript.querySelectorAll(parsed, this._injectedScript.document);\n  }\n  _inspect(selector) {\n    if (typeof selector !== "string")\n      throw new Error(`Usage: playwright.inspect(\'Playwright >> selector\').`);\n    this._injectedScript.window.inspect(this._querySelector(selector, false));\n  }\n  _selector(element) {\n    if (!(element instanceof Element))\n      throw new Error(`Usage: playwright.selector(element).`);\n    return this._injectedScript.generateSelectorSimple(element);\n  }\n  _generateLocator(element, language) {\n    if (!(element instanceof Element))\n      throw new Error(`Usage: playwright.locator(element).`);\n    const selector = this._injectedScript.generateSelectorSimple(element);\n    return asLocator(language || "javascript", selector);\n  }\n  _resume() {\n    if (!this._injectedScript.window.__pw_resume)\n      return false;\n    this._injectedScript.window.__pw_resume().catch(() => {\n    });\n  }\n};\n\n// packages/playwright-core/src/utils/isomorphic/utilityScriptSerializers.ts\nfunction isRegExp2(obj) {\n  try {\n    return obj instanceof RegExp || Object.prototype.toString.call(obj) === "[object RegExp]";\n  } catch (error) {\n    return false;\n  }\n}\nfunction isDate(obj) {\n  try {\n    return obj instanceof Date || Object.prototype.toString.call(obj) === "[object Date]";\n  } catch (error) {\n    return false;\n  }\n}\nfunction isURL(obj) {\n  try {\n    return obj instanceof URL || Object.prototype.toString.call(obj) === "[object URL]";\n  } catch (error) {\n    return false;\n  }\n}\nfunction isError(obj) {\n  var _a;\n  try {\n    return obj instanceof Error || obj && ((_a = Object.getPrototypeOf(obj)) == null ? void 0 : _a.name) === "Error";\n  } catch (error) {\n    return false;\n  }\n}\nfunction isTypedArray(obj, constructor) {\n  try {\n    return obj instanceof constructor || Object.prototype.toString.call(obj) === `[object ${constructor.name}]`;\n  } catch (error) {\n    return false;\n  }\n}\nvar typedArrayConstructors = {\n  i8: Int8Array,\n  ui8: Uint8Array,\n  ui8c: Uint8ClampedArray,\n  i16: Int16Array,\n  ui16: Uint16Array,\n  i32: Int32Array,\n  ui32: Uint32Array,\n  // TODO: add Float16Array once it\'s in baseline\n  f32: Float32Array,\n  f64: Float64Array,\n  bi64: BigInt64Array,\n  bui64: BigUint64Array\n};\nfunction typedArrayToBase64(array) {\n  if ("toBase64" in array)\n    return array.toBase64();\n  const binary = Array.from(new Uint8Array(array.buffer, array.byteOffset, array.byteLength)).map((b) => String.fromCharCode(b)).join("");\n  return btoa(binary);\n}\nfunction base64ToTypedArray(base64, TypedArrayConstructor) {\n  const binary = atob(base64);\n  const bytes = new Uint8Array(binary.length);\n  for (let i = 0; i < binary.length; i++)\n    bytes[i] = binary.charCodeAt(i);\n  return new TypedArrayConstructor(bytes.buffer);\n}\nfunction parseEvaluationResultValue(value, handles = [], refs = /* @__PURE__ */ new Map()) {\n  if (Object.is(value, void 0))\n    return void 0;\n  if (typeof value === "object" && value) {\n    if ("ref" in value)\n      return refs.get(value.ref);\n    if ("v" in value) {\n      if (value.v === "undefined")\n        return void 0;\n      if (value.v === "null")\n        return null;\n      if (value.v === "NaN")\n        return NaN;\n      if (value.v === "Infinity")\n        return Infinity;\n      if (value.v === "-Infinity")\n        return -Infinity;\n      if (value.v === "-0")\n        return -0;\n      return void 0;\n    }\n    if ("d" in value) {\n      return new Date(value.d);\n    }\n    if ("u" in value)\n      return new URL(value.u);\n    if ("bi" in value)\n      return BigInt(value.bi);\n    if ("e" in value) {\n      const error = new Error(value.e.m);\n      error.name = value.e.n;\n      error.stack = value.e.s;\n      return error;\n    }\n    if ("r" in value)\n      return new RegExp(value.r.p, value.r.f);\n    if ("a" in value) {\n      const result = [];\n      refs.set(value.id, result);\n      for (const a of value.a)\n        result.push(parseEvaluationResultValue(a, handles, refs));\n      return result;\n    }\n    if ("o" in value) {\n      const result = {};\n      refs.set(value.id, result);\n      for (const { k, v } of value.o) {\n        if (k === "__proto__")\n          continue;\n        result[k] = parseEvaluationResultValue(v, handles, refs);\n      }\n      return result;\n    }\n    if ("h" in value)\n      return handles[value.h];\n    if ("ta" in value)\n      return base64ToTypedArray(value.ta.b, typedArrayConstructors[value.ta.k]);\n  }\n  return value;\n}\nfunction serializeAsCallArgument(value, handleSerializer) {\n  return serialize(value, handleSerializer, { visited: /* @__PURE__ */ new Map(), lastId: 0 });\n}\nfunction serialize(value, handleSerializer, visitorInfo) {\n  if (value && typeof value === "object") {\n    if (typeof globalThis.Window === "function" && value instanceof globalThis.Window)\n      return "ref: <Window>";\n    if (typeof globalThis.Document === "function" && value instanceof globalThis.Document)\n      return "ref: <Document>";\n    if (typeof globalThis.Node === "function" && value instanceof globalThis.Node)\n      return "ref: <Node>";\n  }\n  return innerSerialize(value, handleSerializer, visitorInfo);\n}\nfunction innerSerialize(value, handleSerializer, visitorInfo) {\n  var _a;\n  const result = handleSerializer(value);\n  if ("fallThrough" in result)\n    value = result.fallThrough;\n  else\n    return result;\n  if (typeof value === "symbol")\n    return { v: "undefined" };\n  if (Object.is(value, void 0))\n    return { v: "undefined" };\n  if (Object.is(value, null))\n    return { v: "null" };\n  if (Object.is(value, NaN))\n    return { v: "NaN" };\n  if (Object.is(value, Infinity))\n    return { v: "Infinity" };\n  if (Object.is(value, -Infinity))\n    return { v: "-Infinity" };\n  if (Object.is(value, -0))\n    return { v: "-0" };\n  if (typeof value === "boolean")\n    return value;\n  if (typeof value === "number")\n    return value;\n  if (typeof value === "string")\n    return value;\n  if (typeof value === "bigint")\n    return { bi: value.toString() };\n  if (isError(value)) {\n    let stack;\n    if ((_a = value.stack) == null ? void 0 : _a.startsWith(value.name + ": " + value.message)) {\n      stack = value.stack;\n    } else {\n      stack = `${value.name}: ${value.message}\n${value.stack}`;\n    }\n    return { e: { n: value.name, m: value.message, s: stack } };\n  }\n  if (isDate(value))\n    return { d: value.toJSON() };\n  if (isURL(value))\n    return { u: value.toJSON() };\n  if (isRegExp2(value))\n    return { r: { p: value.source, f: value.flags } };\n  for (const [k, ctor] of Object.entries(typedArrayConstructors)) {\n    if (isTypedArray(value, ctor))\n      return { ta: { b: typedArrayToBase64(value), k } };\n  }\n  const id = visitorInfo.visited.get(value);\n  if (id)\n    return { ref: id };\n  if (Array.isArray(value)) {\n    const a = [];\n    const id2 = ++visitorInfo.lastId;\n    visitorInfo.visited.set(value, id2);\n    for (let i = 0; i < value.length; ++i)\n      a.push(serialize(value[i], handleSerializer, visitorInfo));\n    return { a, id: id2 };\n  }\n  if (typeof value === "object") {\n    const o = [];\n    const id2 = ++visitorInfo.lastId;\n    visitorInfo.visited.set(value, id2);\n    for (const name of Object.keys(value)) {\n      let item;\n      try {\n        item = value[name];\n      } catch (e) {\n        continue;\n      }\n      if (name === "toJSON" && typeof item === "function")\n        o.push({ k: name, v: { o: [], id: 0 } });\n      else\n        o.push({ k: name, v: serialize(item, handleSerializer, visitorInfo) });\n    }\n    let jsonWrapper;\n    try {\n      if (o.length === 0 && value.toJSON && typeof value.toJSON === "function")\n        jsonWrapper = { value: value.toJSON() };\n    } catch (e) {\n    }\n    if (jsonWrapper)\n      return innerSerialize(jsonWrapper.value, handleSerializer, visitorInfo);\n    return { o, id: id2 };\n  }\n}\n\n// packages/injected/src/utilityScript.ts\nvar UtilityScript = class {\n  constructor(global, isUnderTest) {\n    var _a, _b, _c, _d, _e, _f, _g, _h;\n    this.global = global;\n    this.isUnderTest = isUnderTest;\n    if (global.__pwClock) {\n      this.builtins = global.__pwClock.builtins;\n    } else {\n      this.builtins = {\n        setTimeout: (_a = global.setTimeout) == null ? void 0 : _a.bind(global),\n        clearTimeout: (_b = global.clearTimeout) == null ? void 0 : _b.bind(global),\n        setInterval: (_c = global.setInterval) == null ? void 0 : _c.bind(global),\n        clearInterval: (_d = global.clearInterval) == null ? void 0 : _d.bind(global),\n        requestAnimationFrame: (_e = global.requestAnimationFrame) == null ? void 0 : _e.bind(global),\n        cancelAnimationFrame: (_f = global.cancelAnimationFrame) == null ? void 0 : _f.bind(global),\n        requestIdleCallback: (_g = global.requestIdleCallback) == null ? void 0 : _g.bind(global),\n        cancelIdleCallback: (_h = global.cancelIdleCallback) == null ? void 0 : _h.bind(global),\n        performance: global.performance,\n        Intl: global.Intl,\n        Date: global.Date\n      };\n    }\n    if (this.isUnderTest)\n      global.builtins = this.builtins;\n  }\n  evaluate(isFunction, returnByValue, expression, argCount, ...argsAndHandles) {\n    const args = argsAndHandles.slice(0, argCount);\n    const handles = argsAndHandles.slice(argCount);\n    const parameters = [];\n    for (let i = 0; i < args.length; i++)\n      parameters[i] = parseEvaluationResultValue(args[i], handles);\n    let result = this.global.eval(expression);\n    if (isFunction === true) {\n      result = result(...parameters);\n    } else if (isFunction === false) {\n      result = result;\n    } else {\n      if (typeof result === "function")\n        result = result(...parameters);\n    }\n    return returnByValue ? this._promiseAwareJsonValueNoThrow(result) : result;\n  }\n  jsonValue(returnByValue, value) {\n    if (value === void 0)\n      return void 0;\n    return serializeAsCallArgument(value, (value2) => ({ fallThrough: value2 }));\n  }\n  _promiseAwareJsonValueNoThrow(value) {\n    const safeJson = (value2) => {\n      try {\n        return this.jsonValue(true, value2);\n      } catch (e) {\n        return void 0;\n      }\n    };\n    if (value && typeof value === "object" && typeof value.then === "function") {\n      return (async () => {\n        const promiseValue = await value;\n        return safeJson(promiseValue);\n      })();\n    }\n    return safeJson(value);\n  }\n};\n\n// packages/injected/src/injectedScript.ts\nvar InjectedScript = class {\n  constructor(window, options) {\n    this._testIdAttributeNameForStrictErrorAndConsoleCodegen = "data-testid";\n    this._lastAriaSnapshotForTrack = /* @__PURE__ */ new Map();\n    // Recorder must use any external dependencies through InjectedScript.\n    // Otherwise it will end up with a copy of all modules it uses, and any\n    // module-level globals will be duplicated, which leads to subtle bugs.\n    this.utils = {\n      asLocator,\n      cacheNormalizedWhitespaces,\n      elementText,\n      getAriaRole,\n      getElementAccessibleDescription,\n      getElementAccessibleName,\n      isElementVisible,\n      isInsideScope,\n      normalizeWhiteSpace,\n      parseAriaSnapshot,\n      generateAriaTree,\n      findNewElement,\n      // Builtins protect injected code from clock emulation.\n      builtins: null\n    };\n    this.window = window;\n    this.document = window.document;\n    this.isUnderTest = options.isUnderTest;\n    this.utils.builtins = new UtilityScript(window, options.isUnderTest).builtins;\n    this._sdkLanguage = options.sdkLanguage;\n    this._testIdAttributeNameForStrictErrorAndConsoleCodegen = options.testIdAttributeName;\n    this._evaluator = new SelectorEvaluatorImpl();\n    this.consoleApi = new ConsoleAPI(this);\n    this.onGlobalListenersRemoved = /* @__PURE__ */ new Set();\n    this._autoClosingTags = /* @__PURE__ */ new Set(["AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "MENUITEM", "META", "PARAM", "SOURCE", "TRACK", "WBR"]);\n    this._booleanAttributes = /* @__PURE__ */ new Set(["checked", "selected", "disabled", "readonly", "multiple"]);\n    this._eventTypes = /* @__PURE__ */ new Map([\n      ["auxclick", "mouse"],\n      ["click", "mouse"],\n      ["dblclick", "mouse"],\n      ["mousedown", "mouse"],\n      ["mouseeenter", "mouse"],\n      ["mouseleave", "mouse"],\n      ["mousemove", "mouse"],\n      ["mouseout", "mouse"],\n      ["mouseover", "mouse"],\n      ["mouseup", "mouse"],\n      ["mouseleave", "mouse"],\n      ["mousewheel", "mouse"],\n      ["keydown", "keyboard"],\n      ["keyup", "keyboard"],\n      ["keypress", "keyboard"],\n      ["textInput", "keyboard"],\n      ["touchstart", "touch"],\n      ["touchmove", "touch"],\n      ["touchend", "touch"],\n      ["touchcancel", "touch"],\n      ["pointerover", "pointer"],\n      ["pointerout", "pointer"],\n      ["pointerenter", "pointer"],\n      ["pointerleave", "pointer"],\n      ["pointerdown", "pointer"],\n      ["pointerup", "pointer"],\n      ["pointermove", "pointer"],\n      ["pointercancel", "pointer"],\n      ["gotpointercapture", "pointer"],\n      ["lostpointercapture", "pointer"],\n      ["focus", "focus"],\n      ["blur", "focus"],\n      ["drag", "drag"],\n      ["dragstart", "drag"],\n      ["dragend", "drag"],\n      ["dragover", "drag"],\n      ["dragenter", "drag"],\n      ["dragleave", "drag"],\n      ["dragexit", "drag"],\n      ["drop", "drag"],\n      ["wheel", "wheel"],\n      ["deviceorientation", "deviceorientation"],\n      ["deviceorientationabsolute", "deviceorientation"],\n      ["devicemotion", "devicemotion"]\n    ]);\n    this._hoverHitTargetInterceptorEvents = /* @__PURE__ */ new Set(["mousemove"]);\n    this._tapHitTargetInterceptorEvents = /* @__PURE__ */ new Set(["pointerdown", "pointerup", "touchstart", "touchend", "touchcancel"]);\n    this._mouseHitTargetInterceptorEvents = /* @__PURE__ */ new Set(["mousedown", "mouseup", "pointerdown", "pointerup", "click", "auxclick", "dblclick", "contextmenu"]);\n    this._allHitTargetInterceptorEvents = /* @__PURE__ */ new Set([...this._hoverHitTargetInterceptorEvents, ...this._tapHitTargetInterceptorEvents, ...this._mouseHitTargetInterceptorEvents]);\n    this._engines = /* @__PURE__ */ new Map();\n    this._engines.set("xpath", XPathEngine);\n    this._engines.set("xpath:light", XPathEngine);\n    this._engines.set("_react", createReactEngine());\n    this._engines.set("_vue", createVueEngine());\n    this._engines.set("role", createRoleEngine(false));\n    this._engines.set("text", this._createTextEngine(true, false));\n    this._engines.set("text:light", this._createTextEngine(false, false));\n    this._engines.set("id", this._createAttributeEngine("id", true));\n    this._engines.set("id:light", this._createAttributeEngine("id", false));\n    this._engines.set("data-testid", this._createAttributeEngine("data-testid", true));\n    this._engines.set("data-testid:light", this._createAttributeEngine("data-testid", false));\n    this._engines.set("data-test-id", this._createAttributeEngine("data-test-id", true));\n    this._engines.set("data-test-id:light", this._createAttributeEngine("data-test-id", false));\n    this._engines.set("data-test", this._createAttributeEngine("data-test", true));\n    this._engines.set("data-test:light", this._createAttributeEngine("data-test", false));\n    this._engines.set("css", this._createCSSEngine());\n    this._engines.set("nth", { queryAll: () => [] });\n    this._engines.set("visible", this._createVisibleEngine());\n    this._engines.set("internal:control", this._createControlEngine());\n    this._engines.set("internal:has", this._createHasEngine());\n    this._engines.set("internal:has-not", this._createHasNotEngine());\n    this._engines.set("internal:and", { queryAll: () => [] });\n    this._engines.set("internal:or", { queryAll: () => [] });\n    this._engines.set("internal:chain", this._createInternalChainEngine());\n    this._engines.set("internal:label", this._createInternalLabelEngine());\n    this._engines.set("internal:text", this._createTextEngine(true, true));\n    this._engines.set("internal:has-text", this._createInternalHasTextEngine());\n    this._engines.set("internal:has-not-text", this._createInternalHasNotTextEngine());\n    this._engines.set("internal:attr", this._createNamedAttributeEngine());\n    this._engines.set("internal:testid", this._createNamedAttributeEngine());\n    this._engines.set("internal:role", createRoleEngine(true));\n    this._engines.set("internal:describe", this._createDescribeEngine());\n    this._engines.set("aria-ref", this._createAriaRefEngine());\n    for (const { name, source } of options.customEngines)\n      this._engines.set(name, this.eval(source));\n    this._stableRafCount = options.stableRafCount;\n    this._browserName = options.browserName;\n    this._isUtilityWorld = !!options.isUtilityWorld;\n    setGlobalOptions({ browserNameForWorkarounds: options.browserName });\n    this._setupGlobalListenersRemovalDetection();\n    this._setupHitTargetInterceptors();\n    if (this.isUnderTest)\n      this.window.__injectedScript = this;\n  }\n  eval(expression) {\n    return this.window.eval(expression);\n  }\n  testIdAttributeNameForStrictErrorAndConsoleCodegen() {\n    return this._testIdAttributeNameForStrictErrorAndConsoleCodegen;\n  }\n  parseSelector(selector) {\n    const result = parseSelector(selector);\n    visitAllSelectorParts(result, (part) => {\n      if (!this._engines.has(part.name))\n        throw this.createStacklessError(`Unknown engine "${part.name}" while parsing selector ${selector}`);\n    });\n    return result;\n  }\n  generateSelector(targetElement, options) {\n    return generateSelector(this, targetElement, options);\n  }\n  generateSelectorSimple(targetElement, options) {\n    return generateSelector(this, targetElement, { ...options, testIdAttributeName: this._testIdAttributeNameForStrictErrorAndConsoleCodegen }).selector;\n  }\n  querySelector(selector, root, strict) {\n    const result = this.querySelectorAll(selector, root);\n    if (strict && result.length > 1)\n      throw this.strictModeViolationError(selector, result);\n    this.checkDeprecatedSelectorUsage(selector, result);\n    return result[0];\n  }\n  _queryNth(elements, part) {\n    const list = [...elements];\n    let nth = +part.body;\n    if (nth === -1)\n      nth = list.length - 1;\n    return new Set(list.slice(nth, nth + 1));\n  }\n  _queryLayoutSelector(elements, part, originalRoot) {\n    const name = part.name;\n    const body = part.body;\n    const result = [];\n    const inner = this.querySelectorAll(body.parsed, originalRoot);\n    for (const element of elements) {\n      const score = layoutSelectorScore(name, element, inner, body.distance);\n      if (score !== void 0)\n        result.push({ element, score });\n    }\n    result.sort((a, b) => a.score - b.score);\n    return new Set(result.map((r) => r.element));\n  }\n  ariaSnapshot(node, options) {\n    return this.incrementalAriaSnapshot(node, options).full;\n  }\n  incrementalAriaSnapshot(node, options) {\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      throw this.createStacklessError("Can only capture aria snapshot of Element nodes.");\n    const ariaSnapshot = generateAriaTree(node, options);\n    const full = renderAriaTree(ariaSnapshot, options);\n    let incremental;\n    if (options.track) {\n      const previousSnapshot = this._lastAriaSnapshotForTrack.get(options.track);\n      if (previousSnapshot)\n        incremental = renderAriaTree(ariaSnapshot, options, previousSnapshot);\n      this._lastAriaSnapshotForTrack.set(options.track, ariaSnapshot);\n    }\n    this._lastAriaSnapshotForQuery = ariaSnapshot;\n    return { full, incremental, iframeRefs: ariaSnapshot.iframeRefs };\n  }\n  ariaSnapshotForRecorder() {\n    const tree = generateAriaTree(this.document.body, { mode: "ai" });\n    const ariaSnapshot = renderAriaTree(tree, { mode: "ai" });\n    return { ariaSnapshot, refs: tree.refs };\n  }\n  getAllElementsMatchingExpectAriaTemplate(document, template) {\n    return getAllElementsMatchingExpectAriaTemplate(document.documentElement, template);\n  }\n  querySelectorAll(selector, root) {\n    if (selector.capture !== void 0) {\n      if (selector.parts.some((part) => part.name === "nth"))\n        throw this.createStacklessError(`Can\'t query n-th element in a request with the capture.`);\n      const withHas = { parts: selector.parts.slice(0, selector.capture + 1) };\n      if (selector.capture < selector.parts.length - 1) {\n        const parsed = { parts: selector.parts.slice(selector.capture + 1) };\n        const has = { name: "internal:has", body: { parsed }, source: stringifySelector(parsed) };\n        withHas.parts.push(has);\n      }\n      return this.querySelectorAll(withHas, root);\n    }\n    if (!root["querySelectorAll"])\n      throw this.createStacklessError("Node is not queryable.");\n    if (selector.capture !== void 0) {\n      throw this.createStacklessError("Internal error: there should not be a capture in the selector.");\n    }\n    if (root.nodeType === 11 && selector.parts.length === 1 && selector.parts[0].name === "css" && selector.parts[0].source === ":scope")\n      return [root];\n    this._evaluator.begin();\n    try {\n      let roots = /* @__PURE__ */ new Set([root]);\n      for (const part of selector.parts) {\n        if (part.name === "nth") {\n          roots = this._queryNth(roots, part);\n        } else if (part.name === "internal:and") {\n          const andElements = this.querySelectorAll(part.body.parsed, root);\n          roots = new Set(andElements.filter((e) => roots.has(e)));\n        } else if (part.name === "internal:or") {\n          const orElements = this.querySelectorAll(part.body.parsed, root);\n          roots = new Set(sortInDOMOrder(/* @__PURE__ */ new Set([...roots, ...orElements])));\n        } else if (kLayoutSelectorNames.includes(part.name)) {\n          roots = this._queryLayoutSelector(roots, part, root);\n        } else {\n          const next = /* @__PURE__ */ new Set();\n          for (const root2 of roots) {\n            const all = this._queryEngineAll(part, root2);\n            for (const one of all)\n              next.add(one);\n          }\n          roots = next;\n        }\n      }\n      return [...roots];\n    } finally {\n      this._evaluator.end();\n    }\n  }\n  _queryEngineAll(part, root) {\n    const result = this._engines.get(part.name).queryAll(root, part.body);\n    for (const element of result) {\n      if (!("nodeName" in element))\n        throw this.createStacklessError(`Expected a Node but got ${Object.prototype.toString.call(element)}`);\n    }\n    return result;\n  }\n  _createAttributeEngine(attribute, shadow) {\n    const toCSS = (selector) => {\n      const css = `[${attribute}=${JSON.stringify(selector)}]`;\n      return [{ simples: [{ selector: { css, functions: [] }, combinator: "" }] }];\n    };\n    return {\n      queryAll: (root, selector) => {\n        return this._evaluator.query({ scope: root, pierceShadow: shadow }, toCSS(selector));\n      }\n    };\n  }\n  _createCSSEngine() {\n    return {\n      queryAll: (root, body) => {\n        return this._evaluator.query({ scope: root, pierceShadow: true }, body);\n      }\n    };\n  }\n  _createTextEngine(shadow, internal) {\n    const queryAll = (root, selector) => {\n      const { matcher, kind } = createTextMatcher(selector, internal);\n      const result = [];\n      let lastDidNotMatchSelf = null;\n      const appendElement = (element) => {\n        if (kind === "lax" && lastDidNotMatchSelf && lastDidNotMatchSelf.contains(element))\n          return false;\n        const matches = elementMatchesText(this._evaluator._cacheText, element, matcher);\n        if (matches === "none")\n          lastDidNotMatchSelf = element;\n        if (matches === "self" || matches === "selfAndChildren" && kind === "strict" && !internal)\n          result.push(element);\n      };\n      if (root.nodeType === Node.ELEMENT_NODE)\n        appendElement(root);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: shadow }, "*");\n      for (const element of elements)\n        appendElement(element);\n      return result;\n    };\n    return { queryAll };\n  }\n  _createInternalHasTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [element] : [];\n      }\n    };\n  }\n  _createInternalHasNotTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [] : [element];\n      }\n    };\n  }\n  _createInternalLabelEngine() {\n    return {\n      queryAll: (root, selector) => {\n        const { matcher } = createTextMatcher(selector, true);\n        const allElements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, "*");\n        return allElements.filter((element) => {\n          return getElementLabels(this._evaluator._cacheText, element).some((label) => matcher(label));\n        });\n      }\n    };\n  }\n  _createNamedAttributeEngine() {\n    const queryAll = (root, selector) => {\n      const parsed = parseAttributeSelector(selector, true);\n      if (parsed.name || parsed.attributes.length !== 1)\n        throw new Error("Malformed attribute selector: " + selector);\n      const { name, value, caseSensitive } = parsed.attributes[0];\n      const lowerCaseValue = caseSensitive ? null : value.toLowerCase();\n      let matcher;\n      if (value instanceof RegExp)\n        matcher = (s) => !!s.match(value);\n      else if (caseSensitive)\n        matcher = (s) => s === value;\n      else\n        matcher = (s) => s.toLowerCase().includes(lowerCaseValue);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, `[${name}]`);\n      return elements.filter((e) => matcher(e.getAttribute(name)));\n    };\n    return { queryAll };\n  }\n  _createDescribeEngine() {\n    const queryAll = (root) => {\n      if (root.nodeType !== 1)\n        return [];\n      return [root];\n    };\n    return { queryAll };\n  }\n  _createControlEngine() {\n    return {\n      queryAll(root, body) {\n        if (body === "enter-frame")\n          return [];\n        if (body === "return-empty")\n          return [];\n        if (body === "component") {\n          if (root.nodeType !== 1)\n            return [];\n          return [root.childElementCount === 1 ? root.firstElementChild : root];\n        }\n        throw new Error(`Internal error, unknown internal:control selector ${body}`);\n      }\n    };\n  }\n  _createHasEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      const has = !!this.querySelector(body.parsed, root, false);\n      return has ? [root] : [];\n    };\n    return { queryAll };\n  }\n  _createHasNotEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      const has = !!this.querySelector(body.parsed, root, false);\n      return has ? [] : [root];\n    };\n    return { queryAll };\n  }\n  _createVisibleEngine() {\n    const queryAll = (root, body) => {\n      if (root.nodeType !== 1)\n        return [];\n      const visible = body === "true";\n      return isElementVisible(root) === visible ? [root] : [];\n    };\n    return { queryAll };\n  }\n  _createInternalChainEngine() {\n    const queryAll = (root, body) => {\n      return this.querySelectorAll(body.parsed, root);\n    };\n    return { queryAll };\n  }\n  extend(source, params) {\n    const constrFunction = this.window.eval(`\n    (() => {\n      const module = {};\n      ${source}\n      return module.exports.default();\n    })()`);\n    return new constrFunction(this, params);\n  }\n  async viewportRatio(element) {\n    return await new Promise((resolve) => {\n      const observer = new IntersectionObserver((entries) => {\n        resolve(entries[0].intersectionRatio);\n        observer.disconnect();\n      });\n      observer.observe(element);\n      this.utils.builtins.requestAnimationFrame(() => {\n      });\n    });\n  }\n  getElementBorderWidth(node) {\n    if (node.nodeType !== Node.ELEMENT_NODE || !node.ownerDocument || !node.ownerDocument.defaultView)\n      return { left: 0, top: 0 };\n    const style = node.ownerDocument.defaultView.getComputedStyle(node);\n    return { left: parseInt(style.borderLeftWidth || "", 10), top: parseInt(style.borderTopWidth || "", 10) };\n  }\n  describeIFrameStyle(iframe) {\n    if (!iframe.ownerDocument || !iframe.ownerDocument.defaultView)\n      return "error:notconnected";\n    const defaultView = iframe.ownerDocument.defaultView;\n    for (let e = iframe; e; e = parentElementOrShadowHost(e)) {\n      if (defaultView.getComputedStyle(e).transform !== "none")\n        return "transformed";\n    }\n    const iframeStyle = defaultView.getComputedStyle(iframe);\n    return {\n      left: parseInt(iframeStyle.borderLeftWidth || "", 10) + parseInt(iframeStyle.paddingLeft || "", 10),\n      top: parseInt(iframeStyle.borderTopWidth || "", 10) + parseInt(iframeStyle.paddingTop || "", 10)\n    };\n  }\n  retarget(node, behavior) {\n    let element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\n    if (!element)\n      return null;\n    if (behavior === "none")\n      return element;\n    if (!element.matches("input, textarea, select") && !element.isContentEditable) {\n      if (behavior === "button-link")\n        element = element.closest("button, [role=button], a, [role=link]") || element;\n      else\n        element = element.closest("button, [role=button], [role=checkbox], [role=radio]") || element;\n    }\n    if (behavior === "follow-label") {\n      if (!element.matches("a, input, textarea, button, select, [role=link], [role=button], [role=checkbox], [role=radio]") && !element.isContentEditable) {\n        const enclosingLabel = element.closest("label");\n        if (enclosingLabel && enclosingLabel.control)\n          element = enclosingLabel.control;\n      }\n    }\n    return element;\n  }\n  async checkElementStates(node, states) {\n    if (states.includes("stable")) {\n      const stableResult = await this._checkElementIsStable(node);\n      if (stableResult === false)\n        return { missingState: "stable" };\n      if (stableResult === "error:notconnected")\n        return "error:notconnected";\n    }\n    for (const state of states) {\n      if (state !== "stable") {\n        const result = this.elementState(node, state);\n        if (result.received === "error:notconnected")\n          return "error:notconnected";\n        if (!result.matches)\n          return { missingState: state };\n      }\n    }\n  }\n  async _checkElementIsStable(node) {\n    const continuePolling = Symbol("continuePolling");\n    let lastRect;\n    let stableRafCounter = 0;\n    let lastTime = 0;\n    const check = () => {\n      const element = this.retarget(node, "no-follow-label");\n      if (!element)\n        return "error:notconnected";\n      const time = this.utils.builtins.performance.now();\n      if (this._stableRafCount > 1 && time - lastTime < 15)\n        return continuePolling;\n      lastTime = time;\n      const clientRect = element.getBoundingClientRect();\n      const rect = { x: clientRect.top, y: clientRect.left, width: clientRect.width, height: clientRect.height };\n      if (lastRect) {\n        const samePosition = rect.x === lastRect.x && rect.y === lastRect.y && rect.width === lastRect.width && rect.height === lastRect.height;\n        if (!samePosition)\n          return false;\n        if (++stableRafCounter >= this._stableRafCount)\n          return true;\n      }\n      lastRect = rect;\n      return continuePolling;\n    };\n    let fulfill;\n    let reject;\n    const result = new Promise((f, r) => {\n      fulfill = f;\n      reject = r;\n    });\n    const raf = () => {\n      try {\n        const success = check();\n        if (success !== continuePolling)\n          fulfill(success);\n        else\n          this.utils.builtins.requestAnimationFrame(raf);\n      } catch (e) {\n        reject(e);\n      }\n    };\n    this.utils.builtins.requestAnimationFrame(raf);\n    return result;\n  }\n  _createAriaRefEngine() {\n    const queryAll = (root, selector) => {\n      var _a, _b;\n      const result = (_b = (_a = this._lastAriaSnapshotForQuery) == null ? void 0 : _a.elements) == null ? void 0 : _b.get(selector);\n      return result && result.isConnected ? [result] : [];\n    };\n    return { queryAll };\n  }\n  elementState(node, state) {\n    const element = this.retarget(node, ["visible", "hidden"].includes(state) ? "none" : "follow-label");\n    if (!element || !element.isConnected) {\n      if (state === "hidden")\n        return { matches: true, received: "hidden" };\n      return { matches: false, received: "error:notconnected" };\n    }\n    if (state === "visible" || state === "hidden") {\n      const visible = isElementVisible(element);\n      return {\n        matches: state === "visible" ? visible : !visible,\n        received: visible ? "visible" : "hidden"\n      };\n    }\n    if (state === "disabled" || state === "enabled") {\n      const disabled = getAriaDisabled(element);\n      return {\n        matches: state === "disabled" ? disabled : !disabled,\n        received: disabled ? "disabled" : "enabled"\n      };\n    }\n    if (state === "editable") {\n      const disabled = getAriaDisabled(element);\n      const readonly = getReadonly(element);\n      if (readonly === "error")\n        throw this.createStacklessError("Element is not an <input>, <textarea>, <select> or [contenteditable] and does not have a role allowing [aria-readonly]");\n      return {\n        matches: !disabled && !readonly,\n        received: disabled ? "disabled" : readonly ? "readOnly" : "editable"\n      };\n    }\n    if (state === "checked" || state === "unchecked") {\n      const need = state === "checked";\n      const checked = getCheckedWithoutMixed(element);\n      if (checked === "error")\n        throw this.createStacklessError("Not a checkbox or radio button");\n      const isRadio = element.nodeName === "INPUT" && element.type === "radio";\n      return {\n        matches: need === checked,\n        received: checked ? "checked" : "unchecked",\n        isRadio\n      };\n    }\n    if (state === "indeterminate") {\n      const checked = getCheckedAllowMixed(element);\n      if (checked === "error")\n        throw this.createStacklessError("Not a checkbox or radio button");\n      return {\n        matches: checked === "mixed",\n        received: checked === true ? "checked" : checked === false ? "unchecked" : "mixed"\n      };\n    }\n    throw this.createStacklessError(`Unexpected element state "${state}"`);\n  }\n  selectOptions(node, optionsToSelect) {\n    const element = this.retarget(node, "follow-label");\n    if (!element)\n      return "error:notconnected";\n    if (element.nodeName.toLowerCase() !== "select")\n      throw this.createStacklessError("Element is not a <select> element");\n    const select = element;\n    const options = [...select.options];\n    const selectedOptions = [];\n    let remainingOptionsToSelect = optionsToSelect.slice();\n    for (let index = 0; index < options.length; index++) {\n      const option = options[index];\n      const filter = (optionToSelect) => {\n        if (optionToSelect instanceof Node)\n          return option === optionToSelect;\n        let matches = true;\n        if (optionToSelect.valueOrLabel !== void 0)\n          matches = matches && (optionToSelect.valueOrLabel === option.value || optionToSelect.valueOrLabel === option.label);\n        if (optionToSelect.value !== void 0)\n          matches = matches && optionToSelect.value === option.value;\n        if (optionToSelect.label !== void 0)\n          matches = matches && optionToSelect.label === option.label;\n        if (optionToSelect.index !== void 0)\n          matches = matches && optionToSelect.index === index;\n        return matches;\n      };\n      if (!remainingOptionsToSelect.some(filter))\n        continue;\n      if (!this.elementState(option, "enabled").matches)\n        return "error:optionnotenabled";\n      selectedOptions.push(option);\n      if (select.multiple) {\n        remainingOptionsToSelect = remainingOptionsToSelect.filter((o) => !filter(o));\n      } else {\n        remainingOptionsToSelect = [];\n        break;\n      }\n    }\n    if (remainingOptionsToSelect.length)\n      return "error:optionsnotfound";\n    select.value = void 0;\n    selectedOptions.forEach((option) => option.selected = true);\n    select.dispatchEvent(new Event("input", { bubbles: true, composed: true }));\n    select.dispatchEvent(new Event("change", { bubbles: true }));\n    return selectedOptions.map((option) => option.value);\n  }\n  fill(node, value) {\n    const element = this.retarget(node, "follow-label");\n    if (!element)\n      return "error:notconnected";\n    if (element.nodeName.toLowerCase() === "input") {\n      const input = element;\n      const type = input.type.toLowerCase();\n      const kInputTypesToSetValue = /* @__PURE__ */ new Set(["color", "date", "time", "datetime-local", "month", "range", "week"]);\n      const kInputTypesToTypeInto = /* @__PURE__ */ new Set(["", "email", "number", "password", "search", "tel", "text", "url"]);\n      if (!kInputTypesToTypeInto.has(type) && !kInputTypesToSetValue.has(type))\n        throw this.createStacklessError(`Input of type "${type}" cannot be filled`);\n      if (type === "number") {\n        value = value.trim();\n        if (isNaN(Number(value)))\n          throw this.createStacklessError("Cannot type text into input[type=number]");\n      }\n      if (type === "color")\n        value = value.toLowerCase();\n      if (kInputTypesToSetValue.has(type)) {\n        value = value.trim();\n        input.focus();\n        input.value = value;\n        if (input.value !== value)\n          throw this.createStacklessError("Malformed value");\n        element.dispatchEvent(new Event("input", { bubbles: true, composed: true }));\n        element.dispatchEvent(new Event("change", { bubbles: true }));\n        return "done";\n      }\n    } else if (element.nodeName.toLowerCase() === "textarea") {\n    } else if (!element.isContentEditable) {\n      throw this.createStacklessError("Element is not an <input>, <textarea> or [contenteditable] element");\n    }\n    this.selectText(element);\n    return "needsinput";\n  }\n  selectText(node) {\n    const element = this.retarget(node, "follow-label");\n    if (!element)\n      return "error:notconnected";\n    if (element.nodeName.toLowerCase() === "input") {\n      const input = element;\n      input.select();\n      input.focus();\n      return "done";\n    }\n    if (element.nodeName.toLowerCase() === "textarea") {\n      const textarea = element;\n      textarea.selectionStart = 0;\n      textarea.selectionEnd = textarea.value.length;\n      textarea.focus();\n      return "done";\n    }\n    const range = element.ownerDocument.createRange();\n    range.selectNodeContents(element);\n    const selection = element.ownerDocument.defaultView.getSelection();\n    if (selection) {\n      selection.removeAllRanges();\n      selection.addRange(range);\n    }\n    element.focus();\n    return "done";\n  }\n  _activelyFocused(node) {\n    const activeElement = node.getRootNode().activeElement;\n    const isFocused = activeElement === node && !!node.ownerDocument && node.ownerDocument.hasFocus();\n    return { activeElement, isFocused };\n  }\n  focusNode(node, resetSelectionIfNotFocused) {\n    if (!node.isConnected)\n      return "error:notconnected";\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      throw this.createStacklessError("Node is not an element");\n    const { activeElement, isFocused: wasFocused } = this._activelyFocused(node);\n    if (node.isContentEditable && !wasFocused && activeElement && activeElement.blur) {\n      activeElement.blur();\n    }\n    node.focus();\n    node.focus();\n    if (resetSelectionIfNotFocused && !wasFocused && node.nodeName.toLowerCase() === "input") {\n      try {\n        const input = node;\n        input.setSelectionRange(0, 0);\n      } catch (e) {\n      }\n    }\n    return "done";\n  }\n  blurNode(node) {\n    if (!node.isConnected)\n      return "error:notconnected";\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      throw this.createStacklessError("Node is not an element");\n    node.blur();\n    return "done";\n  }\n  setInputFiles(node, payloads) {\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return "Node is not of type HTMLElement";\n    const element = node;\n    if (element.nodeName !== "INPUT")\n      return "Not an <input> element";\n    const input = element;\n    const type = (input.getAttribute("type") || "").toLowerCase();\n    if (type !== "file")\n      return "Not an input[type=file] element";\n    const files = payloads.map((file) => {\n      const bytes = Uint8Array.from(atob(file.buffer), (c) => c.charCodeAt(0));\n      return new File([bytes], file.name, { type: file.mimeType, lastModified: file.lastModifiedMs });\n    });\n    const dt = new DataTransfer();\n    for (const file of files)\n      dt.items.add(file);\n    input.files = dt.files;\n    input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));\n    input.dispatchEvent(new Event("change", { bubbles: true }));\n  }\n  expectHitTarget(hitPoint, targetElement) {\n    var _a;\n    const roots = [];\n    let parentElement = targetElement;\n    while (parentElement) {\n      const root = enclosingShadowRootOrDocument(parentElement);\n      if (!root)\n        break;\n      roots.push(root);\n      if (root.nodeType === 9)\n        break;\n      parentElement = root.host;\n    }\n    let hitElement;\n    for (let index = roots.length - 1; index >= 0; index--) {\n      const root = roots[index];\n      const elements = root.elementsFromPoint(hitPoint.x, hitPoint.y);\n      const singleElement = root.elementFromPoint(hitPoint.x, hitPoint.y);\n      if (singleElement && elements[0] && parentElementOrShadowHost(singleElement) === elements[0]) {\n        const style = this.window.getComputedStyle(singleElement);\n        if ((style == null ? void 0 : style.display) === "contents") {\n          elements.unshift(singleElement);\n        }\n      }\n      if (elements[0] && elements[0].shadowRoot === root && elements[1] === singleElement) {\n        elements.shift();\n      }\n      const innerElement = elements[0];\n      if (!innerElement)\n        break;\n      hitElement = innerElement;\n      if (index && innerElement !== roots[index - 1].host)\n        break;\n    }\n    const hitParents = [];\n    while (hitElement && hitElement !== targetElement) {\n      hitParents.push(hitElement);\n      hitElement = (_a = hitElement.assignedSlot) != null ? _a : parentElementOrShadowHost(hitElement);\n    }\n    if (hitElement === targetElement)\n      return "done";\n    const hitTargetDescription = this.previewNode(hitParents[0] || this.document.documentElement);\n    let rootHitTargetDescription;\n    let element = targetElement;\n    while (element) {\n      const index = hitParents.indexOf(element);\n      if (index !== -1) {\n        if (index > 1)\n          rootHitTargetDescription = this.previewNode(hitParents[index - 1]);\n        break;\n      }\n      element = parentElementOrShadowHost(element);\n    }\n    if (rootHitTargetDescription)\n      return { hitTargetDescription: `${hitTargetDescription} from ${rootHitTargetDescription} subtree` };\n    return { hitTargetDescription };\n  }\n  // Life of a pointer action, for example click.\n  //\n  // 0. Retry items 1 and 2 while action fails due to navigation or element being detached.\n  //   1. Resolve selector to an element.\n  //   2. Retry the following steps until the element is detached or frame navigates away.\n  //     2a. Wait for the element to be stable (not moving), visible and enabled.\n  //     2b. Scroll element into view. Scrolling alternates between:\n  //         - Built-in protocol scrolling.\n  //         - Anchoring to the top/left, bottom/right and center/center.\n  //         This is to scroll elements from under sticky headers/footers.\n  //     2c. Click point is calculated, either based on explicitly specified position,\n  //         or some visible point of the element based on protocol content quads.\n  //     2d. Click point relative to page viewport is converted relative to the target iframe\n  //         for the next hit-point check.\n  //     2e. (injected) Hit target at the click point must be a descendant of the target element.\n  //         This prevents mis-clicking in edge cases like <iframe> overlaying the target.\n  //     2f. (injected) Events specific for click (or some other action type) are intercepted on\n  //         the Window with capture:true. See 2i for details.\n  //         Note: this step is skipped for drag&drop (see inline comments for the reason).\n  //     2g. Necessary keyboard modifiers are pressed.\n  //     2h. Click event is issued (mousemove + mousedown + mouseup).\n  //     2i. (injected) For each event, we check that hit target at the event point\n  //         is a descendant of the target element.\n  //         This guarantees no race between issuing the event and handling it in the page,\n  //         for example due to layout shift.\n  //         When hit target check fails, we block all future events in the page.\n  //     2j. Keyboard modifiers are restored.\n  //     2k. (injected) Event interceptor is removed.\n  //     2l. All navigations triggered between 2g-2k are awaited to be either committed or canceled.\n  //     2m. If failed, wait for increasing amount of time before the next retry.\n  setupHitTargetInterceptor(node, action, hitPoint, blockAllEvents) {\n    const element = this.retarget(node, "button-link");\n    if (!element || !element.isConnected)\n      return "error:notconnected";\n    if (hitPoint) {\n      const preliminaryResult = this.expectHitTarget(hitPoint, element);\n      if (preliminaryResult !== "done")\n        return preliminaryResult.hitTargetDescription;\n    }\n    if (action === "drag")\n      return { stop: () => "done" };\n    const events = {\n      "hover": this._hoverHitTargetInterceptorEvents,\n      "tap": this._tapHitTargetInterceptorEvents,\n      "mouse": this._mouseHitTargetInterceptorEvents\n    }[action];\n    let result;\n    const listener = (event) => {\n      if (!events.has(event.type))\n        return;\n      if (!event.isTrusted)\n        return;\n      const point = !!this.window.TouchEvent && event instanceof this.window.TouchEvent ? event.touches[0] : event;\n      if (result === void 0 && point)\n        result = this.expectHitTarget({ x: point.clientX, y: point.clientY }, element);\n      if (blockAllEvents || result !== "done" && result !== void 0) {\n        event.preventDefault();\n        event.stopPropagation();\n        event.stopImmediatePropagation();\n      }\n    };\n    const stop = () => {\n      if (this._hitTargetInterceptor === listener)\n        this._hitTargetInterceptor = void 0;\n      return result || "done";\n    };\n    this._hitTargetInterceptor = listener;\n    return { stop };\n  }\n  dispatchEvent(node, type, eventInitObj) {\n    var _a, _b, _c, _d, _e;\n    let event;\n    const eventInit = { bubbles: true, cancelable: true, composed: true, ...eventInitObj };\n    switch (this._eventTypes.get(type)) {\n      case "mouse":\n        event = new MouseEvent(type, eventInit);\n        break;\n      case "keyboard":\n        event = new KeyboardEvent(type, eventInit);\n        break;\n      case "touch": {\n        if (this._browserName === "webkit") {\n          const createTouch = (t) => {\n            var _a2, _b2, _c2;\n            if (t instanceof Touch)\n              return t;\n            let pageX = t.pageX;\n            if (pageX === void 0 && t.clientX !== void 0)\n              pageX = t.clientX + (((_a2 = this.document.scrollingElement) == null ? void 0 : _a2.scrollLeft) || 0);\n            let pageY = t.pageY;\n            if (pageY === void 0 && t.clientY !== void 0)\n              pageY = t.clientY + (((_b2 = this.document.scrollingElement) == null ? void 0 : _b2.scrollTop) || 0);\n            return this.document.createTouch(this.window, (_c2 = t.target) != null ? _c2 : node, t.identifier, pageX, pageY, t.screenX, t.screenY, t.radiusX, t.radiusY, t.rotationAngle, t.force);\n          };\n          const createTouchList = (touches) => {\n            if (touches instanceof TouchList || !touches)\n              return touches;\n            return this.document.createTouchList(...touches.map(createTouch));\n          };\n          (_a = eventInit.target) != null ? _a : eventInit.target = node;\n          eventInit.touches = createTouchList(eventInit.touches);\n          eventInit.targetTouches = createTouchList(eventInit.targetTouches);\n          eventInit.changedTouches = createTouchList(eventInit.changedTouches);\n          event = new TouchEvent(type, eventInit);\n        } else {\n          (_b = eventInit.target) != null ? _b : eventInit.target = node;\n          eventInit.touches = (_c = eventInit.touches) == null ? void 0 : _c.map((t) => {\n            var _a2;\n            return t instanceof Touch ? t : new Touch({ ...t, target: (_a2 = t.target) != null ? _a2 : node });\n          });\n          eventInit.targetTouches = (_d = eventInit.targetTouches) == null ? void 0 : _d.map((t) => {\n            var _a2;\n            return t instanceof Touch ? t : new Touch({ ...t, target: (_a2 = t.target) != null ? _a2 : node });\n          });\n          eventInit.changedTouches = (_e = eventInit.changedTouches) == null ? void 0 : _e.map((t) => {\n            var _a2;\n            return t instanceof Touch ? t : new Touch({ ...t, target: (_a2 = t.target) != null ? _a2 : node });\n          });\n          event = new TouchEvent(type, eventInit);\n        }\n        break;\n      }\n      case "pointer":\n        event = new PointerEvent(type, eventInit);\n        break;\n      case "focus":\n        event = new FocusEvent(type, eventInit);\n        break;\n      case "drag":\n        event = new DragEvent(type, eventInit);\n        break;\n      case "wheel":\n        event = new WheelEvent(type, eventInit);\n        break;\n      case "deviceorientation":\n        try {\n          event = new DeviceOrientationEvent(type, eventInit);\n        } catch {\n          const { bubbles, cancelable, alpha, beta, gamma, absolute } = eventInit;\n          event = this.document.createEvent("DeviceOrientationEvent");\n          event.initDeviceOrientationEvent(type, bubbles, cancelable, alpha, beta, gamma, absolute);\n        }\n        break;\n      case "devicemotion":\n        try {\n          event = new DeviceMotionEvent(type, eventInit);\n        } catch {\n          const { bubbles, cancelable, acceleration, accelerationIncludingGravity, rotationRate, interval } = eventInit;\n          event = this.document.createEvent("DeviceMotionEvent");\n          event.initDeviceMotionEvent(type, bubbles, cancelable, acceleration, accelerationIncludingGravity, rotationRate, interval);\n        }\n        break;\n      default:\n        event = new Event(type, eventInit);\n        break;\n    }\n    node.dispatchEvent(event);\n  }\n  previewNode(node) {\n    if (node.nodeType === Node.TEXT_NODE)\n      return oneLine(`#text=${node.nodeValue || ""}`);\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return oneLine(`<${node.nodeName.toLowerCase()} />`);\n    const element = node;\n    const attrs = [];\n    for (let i = 0; i < element.attributes.length; i++) {\n      const { name, value } = element.attributes[i];\n      if (name === "style")\n        continue;\n      if (!value && this._booleanAttributes.has(name))\n        attrs.push(` ${name}`);\n      else\n        attrs.push(` ${name}="${value}"`);\n    }\n    attrs.sort((a, b) => a.length - b.length);\n    const attrText = trimStringWithEllipsis(attrs.join(""), 500);\n    if (this._autoClosingTags.has(element.nodeName))\n      return oneLine(`<${element.nodeName.toLowerCase()}${attrText}/>`);\n    const children = element.childNodes;\n    let onlyText = false;\n    if (children.length <= 5) {\n      onlyText = true;\n      for (let i = 0; i < children.length; i++)\n        onlyText = onlyText && children[i].nodeType === Node.TEXT_NODE;\n    }\n    const text = onlyText ? element.textContent || "" : children.length ? "\\u2026" : "";\n    return oneLine(`<${element.nodeName.toLowerCase()}${attrText}>${trimStringWithEllipsis(text, 50)}</${element.nodeName.toLowerCase()}>`);\n  }\n  _generateSelectors(elements) {\n    this._evaluator.begin();\n    beginAriaCaches();\n    beginDOMCaches();\n    try {\n      const maxElements = this._isUtilityWorld && this._browserName === "firefox" ? 2 : 10;\n      const infos = elements.slice(0, maxElements).map((m) => ({\n        preview: this.previewNode(m),\n        selector: this.generateSelectorSimple(m)\n      }));\n      return infos.map((info, i) => `${i + 1}) ${info.preview} aka ${asLocator(this._sdkLanguage, info.selector)}`);\n    } finally {\n      endDOMCaches();\n      endAriaCaches();\n      this._evaluator.end();\n    }\n  }\n  strictModeViolationError(selector, matches) {\n    const lines = this._generateSelectors(matches).map((line) => `\n    ` + line);\n    if (lines.length < matches.length)\n      lines.push("\\n    ...");\n    return this.createStacklessError(`strict mode violation: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} elements:${lines.join("")}\n`);\n  }\n  checkDeprecatedSelectorUsage(selector, matches) {\n    const kDeprecatedSelectors = /* @__PURE__ */ new Set([\n      "_react",\n      "_vue",\n      "xpath:light",\n      "text:light",\n      "id:light",\n      "data-testid:light",\n      "data-test-id:light",\n      "data-test:light"\n    ]);\n    if (!matches.length)\n      return;\n    const deperecated = selector.parts.find((part) => kDeprecatedSelectors.has(part.name));\n    if (!deperecated)\n      return;\n    const lines = this._generateSelectors(matches).map((line) => `\n    ` + line);\n    if (lines.length < matches.length)\n      lines.push("\\n    ...");\n    throw this.createStacklessError(`"${deperecated.name}" selector is not supported: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} element${matches.length === 1 ? "" : "s"}:${lines.join("")}\n`);\n  }\n  createStacklessError(message) {\n    if (this._browserName === "firefox") {\n      const error2 = new Error("Error: " + message);\n      error2.stack = "";\n      return error2;\n    }\n    const error = new Error(message);\n    delete error.stack;\n    return error;\n  }\n  createHighlight() {\n    return new Highlight(this);\n  }\n  maskSelectors(selectors, color) {\n    if (this._highlight)\n      this.hideHighlight();\n    this._highlight = new Highlight(this);\n    this._highlight.install();\n    const elements = [];\n    for (const selector of selectors)\n      elements.push(this.querySelectorAll(selector, this.document.documentElement));\n    this._highlight.maskElements(elements.flat(), color);\n  }\n  highlight(selector) {\n    if (!this._highlight) {\n      this._highlight = new Highlight(this);\n      this._highlight.install();\n    }\n    this._highlight.runHighlightOnRaf(selector);\n  }\n  hideHighlight() {\n    if (this._highlight) {\n      this._highlight.uninstall();\n      delete this._highlight;\n    }\n  }\n  markTargetElements(markedElements, callId) {\n    var _a, _b;\n    if (((_a = this._markedElements) == null ? void 0 : _a.callId) !== callId)\n      this._markedElements = void 0;\n    const previous = ((_b = this._markedElements) == null ? void 0 : _b.elements) || /* @__PURE__ */ new Set();\n    const unmarkEvent = new CustomEvent("__playwright_unmark_target__", {\n      bubbles: true,\n      cancelable: true,\n      detail: callId,\n      composed: true\n    });\n    for (const element of previous) {\n      if (!markedElements.has(element))\n        element.dispatchEvent(unmarkEvent);\n    }\n    const markEvent = new CustomEvent("__playwright_mark_target__", {\n      bubbles: true,\n      cancelable: true,\n      detail: callId,\n      composed: true\n    });\n    for (const element of markedElements) {\n      if (!previous.has(element))\n        element.dispatchEvent(markEvent);\n    }\n    this._markedElements = { callId, elements: markedElements };\n  }\n  _setupGlobalListenersRemovalDetection() {\n    const customEventName = "__playwright_global_listeners_check__";\n    let seenEvent = false;\n    const handleCustomEvent = () => seenEvent = true;\n    this.window.addEventListener(customEventName, handleCustomEvent);\n    new MutationObserver((entries) => {\n      const newDocumentElement = entries.some((entry) => Array.from(entry.addedNodes).includes(this.document.documentElement));\n      if (!newDocumentElement)\n        return;\n      seenEvent = false;\n      this.window.dispatchEvent(new CustomEvent(customEventName));\n      if (seenEvent)\n        return;\n      this.window.addEventListener(customEventName, handleCustomEvent);\n      for (const callback of this.onGlobalListenersRemoved)\n        callback();\n    }).observe(this.document, { childList: true });\n  }\n  _setupHitTargetInterceptors() {\n    const listener = (event) => {\n      var _a;\n      return (_a = this._hitTargetInterceptor) == null ? void 0 : _a.call(this, event);\n    };\n    const addHitTargetInterceptorListeners = () => {\n      for (const event of this._allHitTargetInterceptorEvents)\n        this.window.addEventListener(event, listener, { capture: true, passive: false });\n    };\n    addHitTargetInterceptorListeners();\n    this.onGlobalListenersRemoved.add(addHitTargetInterceptorListeners);\n  }\n  async expect(element, options, elements) {\n    var _a, _b;\n    const isArray = options.expression === "to.have.count" || options.expression.endsWith(".array");\n    if (isArray)\n      return this.expectArray(elements, options);\n    if (!element) {\n      if (!options.isNot && options.expression === "to.be.hidden")\n        return { matches: true };\n      if (options.isNot && options.expression === "to.be.visible")\n        return { matches: false };\n      if (!options.isNot && options.expression === "to.be.detached")\n        return { matches: true };\n      if (options.isNot && options.expression === "to.be.attached")\n        return { matches: false };\n      if (options.isNot && options.expression === "to.be.in.viewport")\n        return { matches: false };\n      if (options.expression === "to.have.title" && ((_a = options == null ? void 0 : options.expectedText) == null ? void 0 : _a[0])) {\n        const matcher = new ExpectedTextMatcher(options.expectedText[0]);\n        const received = this.document.title;\n        return { received, matches: matcher.matches(received) };\n      }\n      if (options.expression === "to.have.url" && ((_b = options == null ? void 0 : options.expectedText) == null ? void 0 : _b[0])) {\n        const matcher = new ExpectedTextMatcher(options.expectedText[0]);\n        const received = this.document.location.href;\n        return { received, matches: matcher.matches(received) };\n      }\n      return { matches: options.isNot, missingReceived: true };\n    }\n    return await this.expectSingleElement(element, options);\n  }\n  async expectSingleElement(element, options) {\n    var _a, _b;\n    const expression = options.expression;\n    {\n      let result;\n      if (expression === "to.have.attribute") {\n        const hasAttribute = element.hasAttribute(options.expressionArg);\n        result = {\n          matches: hasAttribute,\n          received: hasAttribute ? "attribute present" : "attribute not present"\n        };\n      } else if (expression === "to.be.checked") {\n        const { checked, indeterminate } = options.expectedValue;\n        if (indeterminate) {\n          if (checked !== void 0)\n            throw this.createStacklessError("Can\'t assert indeterminate and checked at the same time");\n          result = this.elementState(element, "indeterminate");\n        } else {\n          result = this.elementState(element, checked === false ? "unchecked" : "checked");\n        }\n      } else if (expression === "to.be.disabled") {\n        result = this.elementState(element, "disabled");\n      } else if (expression === "to.be.editable") {\n        result = this.elementState(element, "editable");\n      } else if (expression === "to.be.readonly") {\n        result = this.elementState(element, "editable");\n        result.matches = !result.matches;\n      } else if (expression === "to.be.empty") {\n        if (element.nodeName === "INPUT" || element.nodeName === "TEXTAREA") {\n          const value = element.value;\n          result = { matches: !value, received: value ? "notEmpty" : "empty" };\n        } else {\n          const text = (_a = element.textContent) == null ? void 0 : _a.trim();\n          result = { matches: !text, received: text ? "notEmpty" : "empty" };\n        }\n      } else if (expression === "to.be.enabled") {\n        result = this.elementState(element, "enabled");\n      } else if (expression === "to.be.focused") {\n        const focused = this._activelyFocused(element).isFocused;\n        result = {\n          matches: focused,\n          received: focused ? "focused" : "inactive"\n        };\n      } else if (expression === "to.be.hidden") {\n        result = this.elementState(element, "hidden");\n      } else if (expression === "to.be.visible") {\n        result = this.elementState(element, "visible");\n      } else if (expression === "to.be.attached") {\n        result = {\n          matches: true,\n          received: "attached"\n        };\n      } else if (expression === "to.be.detached") {\n        result = {\n          matches: false,\n          received: "attached"\n        };\n      }\n      if (result) {\n        if (result.received === "error:notconnected")\n          throw this.createStacklessError("Element is not connected");\n        return result;\n      }\n    }\n    {\n      if (expression === "to.have.property") {\n        let target = element;\n        const properties = options.expressionArg.split(".");\n        for (let i = 0; i < properties.length - 1; i++) {\n          if (typeof target !== "object" || !(properties[i] in target))\n            return { received: void 0, matches: false };\n          target = target[properties[i]];\n        }\n        const received = target[properties[properties.length - 1]];\n        const matches = deepEquals(received, options.expectedValue);\n        return { received, matches };\n      }\n    }\n    {\n      if (expression === "to.be.in.viewport") {\n        const ratio = await this.viewportRatio(element);\n        return { received: `viewport ratio ${ratio}`, matches: ratio > 0 && ratio > ((_b = options.expectedNumber) != null ? _b : 0) - 1e-9 };\n      }\n    }\n    {\n      if (expression === "to.have.values") {\n        element = this.retarget(element, "follow-label");\n        if (element.nodeName !== "SELECT" || !element.multiple)\n          throw this.createStacklessError("Not a select element with a multiple attribute");\n        const received = [...element.selectedOptions].map((o) => o.value);\n        if (received.length !== options.expectedText.length)\n          return { received, matches: false };\n        return { received, matches: received.map((r, i) => new ExpectedTextMatcher(options.expectedText[i]).matches(r)).every(Boolean) };\n      }\n    }\n    {\n      if (expression === "to.match.aria") {\n        const result = matchesExpectAriaTemplate(element, options.expectedValue);\n        return {\n          received: result.received,\n          matches: !!result.matches.length\n        };\n      }\n    }\n    {\n      let received;\n      if (expression === "to.have.attribute.value") {\n        const value = element.getAttribute(options.expressionArg);\n        if (value === null)\n          return { received: null, matches: false };\n        received = value;\n      } else if (["to.have.class", "to.contain.class"].includes(expression)) {\n        if (!options.expectedText)\n          throw this.createStacklessError("Expected text is not provided for " + expression);\n        return {\n          received: element.classList.toString(),\n          matches: new ExpectedTextMatcher(options.expectedText[0]).matchesClassList(\n            this,\n            element.classList,\n            /* partial */\n            expression === "to.contain.class"\n          )\n        };\n      } else if (expression === "to.have.css") {\n        received = this.window.getComputedStyle(element).getPropertyValue(options.expressionArg);\n      } else if (expression === "to.have.id") {\n        received = element.id;\n      } else if (expression === "to.have.text") {\n        received = options.useInnerText ? element.innerText : elementText(/* @__PURE__ */ new Map(), element).full;\n      } else if (expression === "to.have.accessible.name") {\n        received = getElementAccessibleName(\n          element,\n          false\n          /* includeHidden */\n        );\n      } else if (expression === "to.have.accessible.description") {\n        received = getElementAccessibleDescription(\n          element,\n          false\n          /* includeHidden */\n        );\n      } else if (expression === "to.have.accessible.error.message") {\n        received = getElementAccessibleErrorMessage(element);\n      } else if (expression === "to.have.role") {\n        received = getAriaRole(element) || "";\n      } else if (expression === "to.have.value") {\n        element = this.retarget(element, "follow-label");\n        if (element.nodeName !== "INPUT" && element.nodeName !== "TEXTAREA" && element.nodeName !== "SELECT")\n          throw this.createStacklessError("Not an input element");\n        received = element.value;\n      }\n      if (received !== void 0 && options.expectedText) {\n        const matcher = new ExpectedTextMatcher(options.expectedText[0]);\n        return { received, matches: matcher.matches(received) };\n      }\n    }\n    throw this.createStacklessError("Unknown expect matcher: " + expression);\n  }\n  expectArray(elements, options) {\n    const expression = options.expression;\n    if (expression === "to.have.count") {\n      const received2 = elements.length;\n      const matches2 = received2 === options.expectedNumber;\n      return { received: received2, matches: matches2 };\n    }\n    if (!options.expectedText)\n      throw this.createStacklessError("Expected text is not provided for " + expression);\n    if (["to.have.class.array", "to.contain.class.array"].includes(expression)) {\n      const receivedClassLists = elements.map((e) => e.classList);\n      const received2 = receivedClassLists.map(String);\n      if (receivedClassLists.length !== options.expectedText.length)\n        return { received: received2, matches: false };\n      const matches2 = this._matchSequentially(\n        options.expectedText,\n        receivedClassLists,\n        (matcher, r) => matcher.matchesClassList(\n          this,\n          r,\n          /* partial */\n          expression === "to.contain.class.array"\n        )\n      );\n      return {\n        received: received2,\n        matches: matches2\n      };\n    }\n    if (!["to.contain.text.array", "to.have.text.array"].includes(expression))\n      throw this.createStacklessError("Unknown expect matcher: " + expression);\n    const received = elements.map((e) => options.useInnerText ? e.innerText : elementText(/* @__PURE__ */ new Map(), e).full);\n    const lengthShouldMatch = expression !== "to.contain.text.array";\n    const matchesLength = received.length === options.expectedText.length || !lengthShouldMatch;\n    if (!matchesLength)\n      return { received, matches: false };\n    const matches = this._matchSequentially(options.expectedText, received, (matcher, r) => matcher.matches(r));\n    return { received, matches };\n  }\n  _matchSequentially(expectedText, received, matchFn) {\n    const matchers = expectedText.map((e) => new ExpectedTextMatcher(e));\n    let mIndex = 0;\n    let rIndex = 0;\n    while (mIndex < matchers.length && rIndex < received.length) {\n      if (matchFn(matchers[mIndex], received[rIndex]))\n        ++mIndex;\n      ++rIndex;\n    }\n    return mIndex === matchers.length;\n  }\n};\nfunction oneLine(s) {\n  return s.replace(/\\n/g, "\\u21B5").replace(/\\t/g, "\\u21C6");\n}\nfunction cssUnquote(s) {\n  s = s.substring(1, s.length - 1);\n  if (!s.includes("\\\\"))\n    return s;\n  const r = [];\n  let i = 0;\n  while (i < s.length) {\n    if (s[i] === "\\\\" && i + 1 < s.length)\n      i++;\n    r.push(s[i++]);\n  }\n  return r.join("");\n}\nfunction createTextMatcher(selector, internal) {\n  if (selector[0] === "/" && selector.lastIndexOf("/") > 0) {\n    const lastSlash = selector.lastIndexOf("/");\n    const re = new RegExp(selector.substring(1, lastSlash), selector.substring(lastSlash + 1));\n    return { matcher: (elementText2) => re.test(elementText2.full), kind: "regex" };\n  }\n  const unquote = internal ? JSON.parse.bind(JSON) : cssUnquote;\n  let strict = false;\n  if (selector.length > 1 && selector[0] === \'"\' && selector[selector.length - 1] === \'"\') {\n    selector = unquote(selector);\n    strict = true;\n  } else if (internal && selector.length > 1 && selector[0] === \'"\' && selector[selector.length - 2] === \'"\' && selector[selector.length - 1] === "i") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = false;\n  } else if (internal && selector.length > 1 && selector[0] === \'"\' && selector[selector.length - 2] === \'"\' && selector[selector.length - 1] === "s") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = true;\n  } else if (selector.length > 1 && selector[0] === "\'" && selector[selector.length - 1] === "\'") {\n    selector = unquote(selector);\n    strict = true;\n  }\n  selector = normalizeWhiteSpace(selector);\n  if (strict) {\n    if (internal)\n      return { kind: "strict", matcher: (elementText2) => elementText2.normalized === selector };\n    const strictTextNodeMatcher = (elementText2) => {\n      if (!selector && !elementText2.immediate.length)\n        return true;\n      return elementText2.immediate.some((s) => normalizeWhiteSpace(s) === selector);\n    };\n    return { matcher: strictTextNodeMatcher, kind: "strict" };\n  }\n  selector = selector.toLowerCase();\n  return { kind: "lax", matcher: (elementText2) => elementText2.normalized.toLowerCase().includes(selector) };\n}\nvar ExpectedTextMatcher = class {\n  constructor(expected) {\n    this._normalizeWhiteSpace = expected.normalizeWhiteSpace;\n    this._ignoreCase = expected.ignoreCase;\n    this._string = expected.matchSubstring ? void 0 : this.normalize(expected.string);\n    this._substring = expected.matchSubstring ? this.normalize(expected.string) : void 0;\n    if (expected.regexSource) {\n      const flags = new Set((expected.regexFlags || "").split(""));\n      if (expected.ignoreCase === false)\n        flags.delete("i");\n      if (expected.ignoreCase === true)\n        flags.add("i");\n      this._regex = new RegExp(expected.regexSource, [...flags].join(""));\n    }\n  }\n  matches(text) {\n    if (!this._regex)\n      text = this.normalize(text);\n    if (this._string !== void 0)\n      return text === this._string;\n    if (this._substring !== void 0)\n      return text.includes(this._substring);\n    if (this._regex)\n      return !!this._regex.test(text);\n    return false;\n  }\n  matchesClassList(injectedScript, classList, partial) {\n    if (partial) {\n      if (this._regex)\n        throw injectedScript.createStacklessError("Partial matching does not support regular expressions. Please provide a string value.");\n      return this._string.split(/\\s+/g).filter(Boolean).every((className) => classList.contains(className));\n    }\n    return this.matches(classList.toString());\n  }\n  normalize(s) {\n    if (!s)\n      return s;\n    if (this._normalizeWhiteSpace)\n      s = normalizeWhiteSpace(s);\n    if (this._ignoreCase)\n      s = s.toLocaleLowerCase();\n    return s;\n  }\n};\nfunction deepEquals(a, b) {\n  if (a === b)\n    return true;\n  if (a && b && typeof a === "object" && typeof b === "object") {\n    if (a.constructor !== b.constructor)\n      return false;\n    if (Array.isArray(a)) {\n      if (a.length !== b.length)\n        return false;\n      for (let i = 0; i < a.length; ++i) {\n        if (!deepEquals(a[i], b[i]))\n          return false;\n      }\n      return true;\n    }\n    if (a instanceof RegExp)\n      return a.source === b.source && a.flags === b.flags;\n    if (a.valueOf !== Object.prototype.valueOf)\n      return a.valueOf() === b.valueOf();\n    if (a.toString !== Object.prototype.toString)\n      return a.toString() === b.toString();\n    const keys = Object.keys(a);\n    if (keys.length !== Object.keys(b).length)\n      return false;\n    for (let i = 0; i < keys.length; ++i) {\n      if (!b.hasOwnProperty(keys[i]))\n        return false;\n    }\n    for (const key of keys) {\n      if (!deepEquals(a[key], b[key]))\n        return false;\n    }\n    return true;\n  }\n  if (typeof a === "number" && typeof b === "number")\n    return isNaN(a) && isNaN(b);\n  return false;\n}\n';
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  source
});
