@siteping/widget 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3713 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +3689 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.bun/@medv+finder@3.2.0/node_modules/@medv/finder/finder.js","../src/dom/fingerprint.ts","../src/dom/text-context.ts","../src/dom/xpath.ts","../src/dom/anchor.ts","../src/dom-utils.ts","../src/icons.ts","../src/styles/theme.ts","../src/popup.ts","../src/annotator.ts","../src/api-client.ts","../src/events.ts","../src/fab.ts","../src/identity.ts","../src/dom/fuzzy.ts","../src/dom/resolver.ts","../src/markers.ts","../src/panel.ts","../src/styles/animations.ts","../src/styles/base.ts","../src/tooltip.ts","../src/launcher.ts","../src/index.ts"],"sourcesContent":["// License: MIT\n// Author: Anton Medvedev <anton@medv.io>\n// Source: https://github.com/antonmedv/finder\nlet config;\nlet rootDocument;\nlet start;\nexport function finder(input, options) {\n start = new Date();\n if (input.nodeType !== Node.ELEMENT_NODE) {\n throw new Error(`Can't generate CSS selector for non-element node type.`);\n }\n if ('html' === input.tagName.toLowerCase()) {\n return 'html';\n }\n const defaults = {\n root: document.body,\n idName: (name) => true,\n className: (name) => true,\n tagName: (name) => true,\n attr: (name, value) => false,\n seedMinLength: 1,\n optimizedMinLength: 2,\n threshold: 1000,\n maxNumberOfTries: 10000,\n timeoutMs: undefined,\n };\n config = { ...defaults, ...options };\n rootDocument = findRootDocument(config.root, defaults);\n let path = bottomUpSearch(input, 'all', () => bottomUpSearch(input, 'two', () => bottomUpSearch(input, 'one', () => bottomUpSearch(input, 'none'))));\n if (path) {\n const optimized = sort(optimize(path, input));\n if (optimized.length > 0) {\n path = optimized[0];\n }\n return selector(path);\n }\n else {\n throw new Error(`Selector was not found.`);\n }\n}\nfunction findRootDocument(rootNode, defaults) {\n if (rootNode.nodeType === Node.DOCUMENT_NODE) {\n return rootNode;\n }\n if (rootNode === defaults.root) {\n return rootNode.ownerDocument;\n }\n return rootNode;\n}\nfunction bottomUpSearch(input, limit, fallback) {\n let path = null;\n let stack = [];\n let current = input;\n let i = 0;\n while (current) {\n const elapsedTime = new Date().getTime() - start.getTime();\n if (config.timeoutMs !== undefined && elapsedTime > config.timeoutMs) {\n throw new Error(`Timeout: Can't find a unique selector after ${elapsedTime}ms`);\n }\n let level = maybe(id(current)) ||\n maybe(...attr(current)) ||\n maybe(...classNames(current)) ||\n maybe(tagName(current)) || [any()];\n const nth = index(current);\n if (limit == 'all') {\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n }\n else if (limit == 'two') {\n level = level.slice(0, 1);\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n }\n else if (limit == 'one') {\n const [node] = (level = level.slice(0, 1));\n if (nth && dispensableNth(node)) {\n level = [nthChild(node, nth)];\n }\n }\n else if (limit == 'none') {\n level = [any()];\n if (nth) {\n level = [nthChild(level[0], nth)];\n }\n }\n for (let node of level) {\n node.level = i;\n }\n stack.push(level);\n if (stack.length >= config.seedMinLength) {\n path = findUniquePath(stack, fallback);\n if (path) {\n break;\n }\n }\n current = current.parentElement;\n i++;\n }\n if (!path) {\n path = findUniquePath(stack, fallback);\n }\n if (!path && fallback) {\n return fallback();\n }\n return path;\n}\nfunction findUniquePath(stack, fallback) {\n const paths = sort(combinations(stack));\n if (paths.length > config.threshold) {\n return fallback ? fallback() : null;\n }\n for (let candidate of paths) {\n if (unique(candidate)) {\n return candidate;\n }\n }\n return null;\n}\nfunction selector(path) {\n let node = path[0];\n let query = node.name;\n for (let i = 1; i < path.length; i++) {\n const level = path[i].level || 0;\n if (node.level === level - 1) {\n query = `${path[i].name} > ${query}`;\n }\n else {\n query = `${path[i].name} ${query}`;\n }\n node = path[i];\n }\n return query;\n}\nfunction penalty(path) {\n return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);\n}\nfunction unique(path) {\n const css = selector(path);\n switch (rootDocument.querySelectorAll(css).length) {\n case 0:\n throw new Error(`Can't select any node with this selector: ${css}`);\n case 1:\n return true;\n default:\n return false;\n }\n}\nfunction id(input) {\n const elementId = input.getAttribute('id');\n if (elementId && config.idName(elementId)) {\n return {\n name: '#' + CSS.escape(elementId),\n penalty: 0,\n };\n }\n return null;\n}\nfunction attr(input) {\n const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));\n return attrs.map((attr) => ({\n name: `[${CSS.escape(attr.name)}=\"${CSS.escape(attr.value)}\"]`,\n penalty: 0.5,\n }));\n}\nfunction classNames(input) {\n const names = Array.from(input.classList).filter(config.className);\n return names.map((name) => ({\n name: '.' + CSS.escape(name),\n penalty: 1,\n }));\n}\nfunction tagName(input) {\n const name = input.tagName.toLowerCase();\n if (config.tagName(name)) {\n return {\n name,\n penalty: 2,\n };\n }\n return null;\n}\nfunction any() {\n return {\n name: '*',\n penalty: 3,\n };\n}\nfunction index(input) {\n const parent = input.parentNode;\n if (!parent) {\n return null;\n }\n let child = parent.firstChild;\n if (!child) {\n return null;\n }\n let i = 0;\n while (child) {\n if (child.nodeType === Node.ELEMENT_NODE) {\n i++;\n }\n if (child === input) {\n break;\n }\n child = child.nextSibling;\n }\n return i;\n}\nfunction nthChild(node, i) {\n return {\n name: node.name + `:nth-child(${i})`,\n penalty: node.penalty + 1,\n };\n}\nfunction dispensableNth(node) {\n return node.name !== 'html' && !node.name.startsWith('#');\n}\nfunction maybe(...level) {\n const list = level.filter(notEmpty);\n if (list.length > 0) {\n return list;\n }\n return null;\n}\nfunction notEmpty(value) {\n return value !== null && value !== undefined;\n}\nfunction* combinations(stack, path = []) {\n if (stack.length > 0) {\n for (let node of stack[0]) {\n yield* combinations(stack.slice(1, stack.length), path.concat(node));\n }\n }\n else {\n yield path;\n }\n}\nfunction sort(paths) {\n return [...paths].sort((a, b) => penalty(a) - penalty(b));\n}\nfunction* optimize(path, input, scope = {\n counter: 0,\n visited: new Map(),\n}) {\n if (path.length > 2 && path.length > config.optimizedMinLength) {\n for (let i = 1; i < path.length - 1; i++) {\n if (scope.counter > config.maxNumberOfTries) {\n return; // Okay At least I tried!\n }\n scope.counter += 1;\n const newPath = [...path];\n newPath.splice(i, 1);\n const newPathKey = selector(newPath);\n if (scope.visited.has(newPathKey)) {\n return;\n }\n if (unique(newPath) && same(newPath, input)) {\n yield newPath;\n scope.visited.set(newPathKey, true);\n yield* optimize(newPath, input, scope);\n }\n }\n }\n}\nfunction same(path, input) {\n return rootDocument.querySelector(selector(path)) === input;\n}\n","/**\n * Element fingerprinting for robust DOM re-anchoring.\n *\n * Captures structural properties (child count, sibling index, stable attributes)\n * that survive CSS class changes and minor DOM reshuffling.\n * Inspired by Similo (academic state-of-the-art, 98.8% accuracy).\n */\n\nconst STABLE_ATTRS = [\"role\", \"aria-label\", \"type\", \"name\", \"href\", \"src\", \"data-testid\", \"data-id\"] as const;\n\n/** Simple 32-bit hash (djb2). */\nfunction djb2(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Generate a compact structural fingerprint for a DOM element.\n *\n * Format: `\"childCount:siblingIdx:attrHash\"`\n * - `childCount` — number of direct child elements\n * - `siblingIdx` — position among same-tag siblings (0-based)\n * - `attrHash` — djb2 hash of stable attributes (role, aria-label, type, etc.)\n *\n * Tag name is NOT included — it's stored separately in `AnchorData.elementTag`.\n */\nexport function generateFingerprint(element: Element): string {\n const childCount = element.children.length;\n\n // Position among same-tag siblings\n let siblingIdx = 0;\n const parent = element.parentElement;\n if (parent) {\n for (const child of parent.children) {\n if (child === element) break;\n if (child.tagName === element.tagName) siblingIdx++;\n }\n }\n\n // Hash stable attributes\n const attrs: string[] = [];\n for (const attr of STABLE_ATTRS) {\n const val = element.getAttribute(attr);\n if (val) attrs.push(`${attr}=${val}`);\n }\n const attrHash = attrs.length > 0 ? djb2(attrs.join(\",\")) : \"0\";\n\n return `${childCount}:${siblingIdx}:${attrHash}`;\n}\n\n/**\n * Score how well a candidate element matches a stored fingerprint.\n * Returns 0–1.\n *\n * Weights:\n * - Child count match: 0.2 (tolerant — ±2 gets partial credit)\n * - Sibling index match: 0.4 (positional — most discriminating)\n * - Attribute hash match: 0.4 (identity — exact or nothing)\n */\nexport function scoreFingerprint(candidate: Element, storedFingerprint: string): number {\n const parts = storedFingerprint.split(\":\");\n if (parts.length !== 3) return 0;\n\n const [storedChildren, storedSibIdx, storedAttrHash] = parts;\n const storedChildCount = Number(storedChildren);\n const storedSibIndex = Number(storedSibIdx);\n if (Number.isNaN(storedChildCount) || Number.isNaN(storedSibIndex)) return 0;\n\n const candidateFp = generateFingerprint(candidate);\n const [candChildren, candSibIdx, candAttrHash] = candidateFp.split(\":\");\n\n let score = 0;\n\n // Child count (0.2)\n const childDiff = Math.abs(Number(candChildren) - storedChildCount);\n if (childDiff === 0) score += 0.2;\n else if (childDiff <= 2) score += 0.1;\n else if (childDiff <= 5) score += 0.03;\n\n // Sibling index (0.4)\n const sibDiff = Math.abs(Number(candSibIdx) - storedSibIndex);\n if (sibDiff === 0) score += 0.4;\n else if (sibDiff === 1) score += 0.2;\n else if (sibDiff <= 3) score += 0.08;\n\n // Attribute hash (0.4)\n if (candAttrHash === storedAttrHash) score += 0.4;\n\n return score;\n}\n","/**\n * Shared text-context helpers for DOM anchoring.\n * Used by both anchor generation (anchor.ts) and resolution (resolver.ts).\n */\n\n/**\n * Extract ~32 chars of text from the nearest sibling with content.\n * Walks up to 3 siblings in the given direction.\n */\nexport function adjacentText(element: Element, direction: \"before\" | \"after\"): string {\n const prop = direction === \"before\" ? \"previousElementSibling\" : \"nextElementSibling\";\n let sibling: Element | null = element[prop];\n let attempts = 3;\n\n while (sibling && attempts > 0) {\n const text = sibling.textContent?.trim();\n if (text) {\n return direction === \"before\" ? text.slice(-32) : text.slice(0, 32);\n }\n sibling = sibling[prop];\n attempts--;\n }\n\n return \"\";\n}\n\n/** Collect text from immediate siblings for disambiguation context. */\nexport function neighborText(element: Element): string {\n const prev = element.previousElementSibling?.textContent?.trim().slice(0, 40) ?? \"\";\n const next = element.nextElementSibling?.textContent?.trim().slice(0, 40) ?? \"\";\n return [prev, next].filter(Boolean).join(\" | \");\n}\n","/**\n * Generate an optimized XPath for a DOM element.\n *\n * Strategy:\n * - If the element has a unique id → //tag[@id='value']\n * - Otherwise, walk up the tree building /tag[position] segments\n * until we hit an ancestor with an id or reach <body>\n * - Cap depth at 6 levels to keep paths short\n */\nexport function generateXPath(element: Element): string {\n if (element.id) {\n const safeId = element.id.includes(\"'\") ? `concat('${element.id.replace(/'/g, \"',\\\"'\\\",'\")}')` : `'${element.id}'`;\n return `//${element.localName}[@id=${safeId}]`;\n }\n\n const segments: string[] = [];\n let current: Element | null = element;\n\n while (current && current !== document.body && segments.length < 6) {\n const tag = current.localName;\n const parent: Element | null = current.parentElement;\n\n if (current.id) {\n const safeId = current.id.includes(\"'\")\n ? `concat('${current.id.replace(/'/g, \"',\\\"'\\\",'\")}')`\n : `'${current.id}'`;\n segments.unshift(`/${tag}[@id=${safeId}]`);\n return \"/\" + segments.join(\"\");\n }\n\n // Compute position among same-tag siblings\n let position = 1;\n if (parent) {\n for (const sibling of parent.children) {\n if (sibling === current) break;\n if (sibling.localName === tag) position++;\n }\n }\n\n segments.unshift(`/${tag}[${position}]`);\n current = parent;\n }\n\n return \"/html/body\" + segments.join(\"\");\n}\n","import { finder } from \"@medv/finder\";\nimport type { AnchorData, RectData } from \"@siteping/core\";\nimport { generateFingerprint } from \"./fingerprint.js\";\nimport { adjacentText, neighborText } from \"./text-context.js\";\nimport { generateXPath } from \"./xpath.js\";\n\n/**\n * Generate a multi-selector anchor for a DOM element.\n *\n * Uses three complementary strategies (Hypothesis-inspired):\n * 1. CSS selector via @medv/finder (primary — fast, compact)\n * 2. XPath (fallback — survives class changes)\n * 3. Text snippet (fallback — survives structural changes)\n */\nexport function generateAnchor(element: Element): AnchorData {\n const cssSelector = finder(element, {\n // Filter out CSS-in-JS hashed class names\n className: (name: string) => !/^(css|sc|emotion|styled)-/.test(name) && !/^[a-z]{1,3}[A-Za-z0-9]{4,8}$/.test(name),\n // Prefer stable attributes\n attr: (name: string) => [\"data-testid\", \"data-id\", \"role\", \"aria-label\"].includes(name),\n // Exclude framework-generated dynamic IDs\n idName: (name: string) => !name.startsWith(\"radix-\") && !/^:r[0-9]+:$/.test(name),\n seedMinLength: 3,\n optimizedMinLength: 2,\n });\n\n const xpath = generateXPath(element);\n\n const rawText = element.textContent?.trim() ?? \"\";\n const textSnippet = rawText.slice(0, 120);\n\n const textPrefix = adjacentText(element, \"before\");\n const textSuffix = adjacentText(element, \"after\");\n const fingerprint = generateFingerprint(element);\n const neighbor = neighborText(element);\n\n return {\n cssSelector,\n xpath,\n textSnippet,\n textPrefix,\n textSuffix,\n fingerprint,\n neighborText: neighbor,\n elementTag: element.tagName,\n elementId: element.id || undefined,\n };\n}\n\n/**\n * Find the deepest DOM element that fully contains the drawn rectangle.\n * Walks from the center of the rect down through overlapping elements.\n */\nexport function findAnchorElement(rect: DOMRect, root: Element = document.documentElement): Element {\n const centerX = rect.x + rect.width / 2;\n const centerY = rect.y + rect.height / 2;\n\n // Get the element at the center point\n const elementAtCenter = document.elementFromPoint(centerX, centerY);\n if (!elementAtCenter || elementAtCenter === root) return document.body;\n\n // Walk up to find the smallest element whose bounding box contains the full rect\n let candidate: Element = elementAtCenter;\n let current: Element | null = elementAtCenter;\n\n while (current && current !== document.body) {\n const bounds = current.getBoundingClientRect();\n if (\n bounds.left <= rect.x &&\n bounds.top <= rect.y &&\n bounds.right >= rect.x + rect.width &&\n bounds.bottom >= rect.y + rect.height\n ) {\n candidate = current;\n break;\n }\n current = current.parentElement;\n }\n\n return candidate;\n}\n\n/**\n * Convert absolute rectangle coordinates to percentages\n * relative to an anchor element's bounding box.\n */\nexport function rectToPercentages(rect: DOMRect, anchorBounds: DOMRect): RectData {\n // Guard against zero-dimension anchors (collapsed/hidden elements)\n if (anchorBounds.width <= 0 || anchorBounds.height <= 0) {\n return { xPct: 0, yPct: 0, wPct: 1, hPct: 1 };\n }\n return {\n xPct: (rect.x - anchorBounds.x) / anchorBounds.width,\n yPct: (rect.y - anchorBounds.y) / anchorBounds.height,\n wPct: rect.width / anchorBounds.width,\n hPct: rect.height / anchorBounds.height,\n };\n}\n","/**\n * Safe DOM creation utilities.\n * All user content is set via textContent (never innerHTML).\n * SVG icons use a DOMParser for trusted static strings.\n */\n\n/**\n * Parse a trusted SVG string into an SVGElement.\n * Only use with hardcoded icon constants — never with user input.\n * Uses createContextualFragment for native document-context parsing\n * (DOMParser creates nodes in a foreign document that don't render in Shadow DOM).\n */\nexport function parseSvg(svgString: string): SVGSVGElement {\n const range = document.createRange();\n const fragment = range.createContextualFragment(svgString);\n const svg = fragment.firstElementChild;\n if (!svg || svg.nodeName.toLowerCase() !== \"svg\") {\n throw new Error(\"[siteping] Invalid SVG string\");\n }\n return svg as SVGSVGElement;\n}\n\n/** Create an element with optional class and style */\nexport function el(tag: string, attrs?: Record<string, string>): HTMLElement {\n const element = document.createElement(tag);\n if (attrs) {\n for (const [key, value] of Object.entries(attrs)) {\n if (key === \"class\") {\n element.className = value;\n } else if (key === \"style\") {\n element.style.cssText = value;\n } else {\n element.setAttribute(key, value);\n }\n }\n }\n return element;\n}\n\n/** Set text content safely (no HTML injection possible) */\nexport function setText(element: HTMLElement | SVGElement, text: string): void {\n element.textContent = text;\n}\n\n/** Format a relative date string in French */\nexport function formatRelativeDate(isoString: string): string {\n const diff = Date.now() - new Date(isoString).getTime();\n const minutes = Math.floor(diff / 60_000);\n if (minutes < 1) return \"maintenant\";\n if (minutes < 60) return `il y a ${minutes}min`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `il y a ${hours}h`;\n const days = Math.floor(hours / 24);\n if (days < 7) return `il y a ${days}j`;\n return new Date(isoString).toLocaleDateString(\"fr-FR\");\n}\n","/** SVG icon strings for the widget UI. Kept as template strings to avoid DOM parsing overhead. */\n\nexport const ICON_SITEPING = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/><circle cx=\"12\" cy=\"10\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"8\" cy=\"10\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"16\" cy=\"10\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/></svg>`;\n\nexport const ICON_CHAT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>`;\n\nexport const ICON_ANNOTATE = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><path d=\"M3 9h18\"/><path d=\"M9 3v18\"/></svg>`;\n\nexport const ICON_EYE = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`;\n\nexport const ICON_EYE_OFF = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\"/><path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\"/><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/></svg>`;\n\nexport const ICON_CLOSE = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\nexport const ICON_SEARCH = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/></svg>`;\n\nexport const ICON_CHECK = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`;\n\nexport const ICON_QUESTION = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/></svg>`;\n\nexport const ICON_CHANGE = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"/><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"/></svg>`;\n\nexport const ICON_BUG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"8\" y=\"6\" width=\"8\" height=\"14\" rx=\"4\"/><path d=\"M19 9h2\"/><path d=\"M3 9h2\"/><path d=\"M19 13h2\"/><path d=\"M3 13h2\"/><path d=\"M19 17h2\"/><path d=\"M3 17h2\"/><path d=\"M10 2h4\"/></svg>`;\n\nexport const ICON_OTHER = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"1\"/><circle cx=\"19\" cy=\"12\" r=\"1\"/><circle cx=\"5\" cy=\"12\" r=\"1\"/></svg>`;\n\nexport const ICON_UNDO = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>`;\n\nexport const ICON_TRASH = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/><line x1=\"10\" y1=\"11\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"11\" x2=\"14\" y2=\"17\"/></svg>`;\n","/** Color palette and glassmorphism tokens derived from the accent color */\nexport interface ThemeColors {\n accent: string;\n accentLight: string;\n accentDark: string;\n accentGlow: string;\n accentGradient: string;\n bg: string;\n bgHover: string;\n text: string;\n textSecondary: string;\n textTertiary: string;\n border: string;\n shadow: string;\n // Glass tokens\n glassBg: string;\n glassBgHeavy: string;\n glassBorder: string;\n glassBorderSubtle: string;\n // Feedback type colors\n typeQuestion: string;\n typeChangement: string;\n typeBug: string;\n typeAutre: string;\n // Soft type backgrounds (pastel)\n typeQuestionBg: string;\n typeChangementBg: string;\n typeBugBg: string;\n typeAutreBg: string;\n}\n\nconst DEFAULT_ACCENT = \"#0066ff\";\nconst HEX6_RE = /^#[0-9a-fA-F]{6}$/;\nconst HEX3_RE = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/;\nconst HEX8_RE = /^#[0-9a-fA-F]{8}$/;\n\n/** Normalize any accent color to a 6-digit hex, or fall back to default */\nfunction normalizeHex(color: string): string {\n if (HEX6_RE.test(color)) return color;\n const short = HEX3_RE.test(color) ? color.match(HEX3_RE) : null;\n if (short) return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`;\n if (HEX8_RE.test(color)) return color.slice(0, 7);\n return DEFAULT_ACCENT;\n}\n\n/** Darken a hex color by a percentage (0-1) */\nfunction darkenHex(hex: string, amount: number): string {\n const r = Math.max(0, Math.round(parseInt(hex.slice(1, 3), 16) * (1 - amount)));\n const g = Math.max(0, Math.round(parseInt(hex.slice(3, 5), 16) * (1 - amount)));\n const b = Math.max(0, Math.round(parseInt(hex.slice(5, 7), 16) * (1 - amount)));\n return `#${r.toString(16).padStart(2, \"0\")}${g.toString(16).padStart(2, \"0\")}${b.toString(16).padStart(2, \"0\")}`;\n}\n\nexport function buildThemeColors(accent: string = DEFAULT_ACCENT): ThemeColors {\n const hex = normalizeHex(accent);\n const dark = darkenHex(hex, 0.15);\n return {\n accent: hex,\n accentLight: hex + \"14\", // 8% opacity\n accentDark: dark,\n accentGlow: hex + \"33\", // 20% opacity\n accentGradient: `linear-gradient(135deg, ${hex}, ${dark})`,\n bg: \"#ffffff\",\n bgHover: \"#f8f9fb\",\n text: \"#0f172a\",\n textSecondary: \"#475569\",\n textTertiary: \"#64748b\",\n border: \"#e2e8f0\",\n shadow: \"rgba(0, 0, 0, 0.06)\",\n // Glass tokens\n glassBg: \"rgba(255, 255, 255, 0.72)\",\n glassBgHeavy: \"rgba(255, 255, 255, 0.85)\",\n glassBorder: \"rgba(255, 255, 255, 0.35)\",\n glassBorderSubtle: \"rgba(255, 255, 255, 0.18)\",\n // Vibrant type colors\n typeQuestion: \"#3b82f6\",\n typeChangement: \"#f59e0b\",\n typeBug: \"#ef4444\",\n typeAutre: \"#64748b\",\n // Pastel backgrounds\n typeQuestionBg: \"#eff6ff\",\n typeChangementBg: \"#fffbeb\",\n typeBugBg: \"#fef2f2\",\n typeAutreBg: \"#f8fafc\",\n };\n}\n\nexport function getTypeColor(type: string, colors: ThemeColors): string {\n switch (type) {\n case \"question\":\n return colors.typeQuestion;\n case \"changement\":\n return colors.typeChangement;\n case \"bug\":\n return colors.typeBug;\n default:\n return colors.typeAutre;\n }\n}\n\nexport function getTypeBgColor(type: string, colors: ThemeColors): string {\n switch (type) {\n case \"question\":\n return colors.typeQuestionBg;\n case \"changement\":\n return colors.typeChangementBg;\n case \"bug\":\n return colors.typeBugBg;\n default:\n return colors.typeAutreBg;\n }\n}\n\nexport function cssVariables(colors: ThemeColors): string {\n return `\n --sp-accent: ${colors.accent};\n --sp-accent-light: ${colors.accentLight};\n --sp-accent-dark: ${colors.accentDark};\n --sp-accent-glow: ${colors.accentGlow};\n --sp-accent-gradient: ${colors.accentGradient};\n --sp-bg: ${colors.bg};\n --sp-bg-hover: ${colors.bgHover};\n --sp-text: ${colors.text};\n --sp-text-secondary: ${colors.textSecondary};\n --sp-text-tertiary: ${colors.textTertiary};\n --sp-border: ${colors.border};\n --sp-shadow: ${colors.shadow};\n --sp-glass-bg: ${colors.glassBg};\n --sp-glass-bg-heavy: ${colors.glassBgHeavy};\n --sp-glass-border: ${colors.glassBorder};\n --sp-glass-border-subtle: ${colors.glassBorderSubtle};\n --sp-type-question: ${colors.typeQuestion};\n --sp-type-changement: ${colors.typeChangement};\n --sp-type-bug: ${colors.typeBug};\n --sp-type-autre: ${colors.typeAutre};\n --sp-type-question-bg: ${colors.typeQuestionBg};\n --sp-type-changement-bg: ${colors.typeChangementBg};\n --sp-type-bug-bg: ${colors.typeBugBg};\n --sp-type-autre-bg: ${colors.typeAutreBg};\n --sp-radius: 12px;\n --sp-radius-lg: 16px;\n --sp-radius-xl: 20px;\n --sp-radius-full: 9999px;\n --sp-blur: 20px;\n --sp-blur-heavy: 32px;\n --sp-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04);\n --sp-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.04);\n --sp-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04);\n --sp-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.04);\n --sp-shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.12), 0 8px 16px rgba(0, 0, 0, 0.06);\n --sp-font: \"Inter\", system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n `;\n}\n","import type { FeedbackType } from \"@siteping/core\";\nimport { el, parseSvg, setText } from \"./dom-utils.js\";\nimport { ICON_BUG, ICON_CHANGE, ICON_OTHER, ICON_QUESTION } from \"./icons.js\";\nimport { getTypeBgColor, getTypeColor, type ThemeColors } from \"./styles/theme.js\";\n\ninterface PopupResult {\n type: FeedbackType;\n message: string;\n}\n\ninterface TypeOption {\n type: FeedbackType;\n label: string;\n icon: string;\n}\n\nconst TYPE_OPTIONS: TypeOption[] = [\n { type: \"question\", label: \"Question\", icon: ICON_QUESTION },\n { type: \"changement\", label: \"Changement\", icon: ICON_CHANGE },\n { type: \"bug\", label: \"Bug\", icon: ICON_BUG },\n { type: \"autre\", label: \"Autre\", icon: ICON_OTHER },\n];\n\n/**\n * Popup form shown after drawing an annotation rectangle.\n *\n * Glassmorphism design: frosted glass background, soft shadows,\n * pill-shaped type buttons, gradient submit button.\n * Lives outside Shadow DOM.\n */\nexport class Popup {\n private root: HTMLElement;\n private selectedType: FeedbackType | null = null;\n private textarea: HTMLTextAreaElement;\n private submitBtn: HTMLButtonElement;\n private resolve: ((result: PopupResult | null) => void) | null = null;\n\n constructor(private readonly colors: ThemeColors) {\n this.root = el(\"div\", {\n style: `\n position:fixed;\n z-index:2147483647;\n width:300px;\n padding:16px;\n border-radius:16px;\n background:rgba(255, 255, 255, 0.82);\n backdrop-filter:blur(24px);\n -webkit-backdrop-filter:blur(24px);\n border:1px solid rgba(255, 255, 255, 0.35);\n box-shadow:0 8px 32px rgba(0,0,0,0.1), 0 2px 8px rgba(0,0,0,0.04);\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n opacity:0;\n transform:translateY(8px) scale(0.98);\n transition:opacity 0.25s cubic-bezier(0.16, 1, 0.3, 1),transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n display:none;\n -webkit-font-smoothing:antialiased;\n `,\n });\n\n // Type selector grid (2x2)\n const typeRow = el(\"div\", { style: \"display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:12px;\" });\n for (const option of TYPE_OPTIONS) {\n const btn = document.createElement(\"button\");\n btn.style.cssText = `\n height:34px;\n border-radius:9999px;border:1px solid #e2e8f0;\n background:rgba(255,255,255,0.8);cursor:pointer;\n display:flex;align-items:center;justify-content:center;gap:5px;\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:12px;font-weight:500;color:#64748b;\n transition:all 0.2s ease;\n padding:0 10px;\n `;\n const icon = parseSvg(option.icon);\n icon.setAttribute(\"style\", \"width:13px;height:13px;flex-shrink:0;\");\n btn.appendChild(icon);\n const labelSpan = document.createElement(\"span\");\n setText(labelSpan, option.label);\n btn.appendChild(labelSpan);\n btn.dataset.type = option.type;\n\n btn.addEventListener(\"click\", () => {\n this.selectType(option.type, typeRow);\n });\n\n btn.addEventListener(\"mouseenter\", () => {\n if (btn.dataset.type !== this.selectedType) {\n const bgColor = getTypeBgColor(btn.dataset.type ?? \"\", this.colors);\n btn.style.background = bgColor;\n btn.style.borderColor = getTypeColor(btn.dataset.type ?? \"\", this.colors) + \"40\";\n }\n });\n\n btn.addEventListener(\"mouseleave\", () => {\n if (btn.dataset.type !== this.selectedType) {\n btn.style.background = \"rgba(255,255,255,0.8)\";\n btn.style.borderColor = \"#e2e8f0\";\n }\n });\n\n typeRow.appendChild(btn);\n }\n\n // Textarea\n this.textarea = document.createElement(\"textarea\");\n this.textarea.style.cssText = `\n width:100%;min-height:72px;max-height:152px;\n padding:10px 12px;border-radius:12px;\n border:1px solid #e2e8f0;\n background:rgba(255,255,255,0.85);\n color:#0f172a;font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:13px;line-height:1.5;resize:vertical;\n outline:none;transition:all 0.2s ease;\n box-sizing:border-box;\n `;\n this.textarea.placeholder = \"Décrivez votre retour...\";\n this.textarea.setAttribute(\"aria-label\", \"Message de feedback\");\n\n // Keyboard shortcut hint\n const hint = el(\"div\", {\n style: `\n font-size:11px;color:#94a3b8;\n text-align:right;margin-top:4px;\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n letter-spacing:0.01em;\n `,\n });\n const isMac = navigator.platform.includes(\"Mac\");\n setText(hint, isMac ? \"\\u2318+Entr\\u00e9e pour envoyer\" : \"Ctrl+Entr\\u00e9e pour envoyer\");\n\n this.textarea.addEventListener(\"focus\", () => {\n this.textarea.style.borderColor = this.colors.accent;\n this.textarea.style.boxShadow = `0 0 0 3px ${this.colors.accent}14`;\n this.textarea.style.background = \"#fff\";\n });\n this.textarea.addEventListener(\"blur\", () => {\n this.textarea.style.borderColor = \"#e2e8f0\";\n this.textarea.style.boxShadow = \"none\";\n this.textarea.style.background = \"rgba(255,255,255,0.85)\";\n });\n this.textarea.addEventListener(\"input\", () => {\n this.updateSubmitState();\n });\n this.textarea.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && (e.ctrlKey || e.metaKey)) {\n e.preventDefault();\n this.submit();\n }\n if (e.key === \"Escape\") {\n this.cancel();\n }\n });\n\n // Button row\n const btnRow = el(\"div\", { style: \"display:flex;justify-content:flex-end;gap:8px;margin-top:12px;\" });\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.style.cssText = `\n height:34px;padding:0 16px;border-radius:9999px;\n border:1px solid #e2e8f0;\n background:rgba(255,255,255,0.8);\n color:#64748b;font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:13px;font-weight:500;cursor:pointer;\n transition:all 0.2s ease;\n `;\n setText(cancelBtn, \"Annuler\");\n cancelBtn.addEventListener(\"click\", () => this.cancel());\n cancelBtn.addEventListener(\"mouseenter\", () => {\n cancelBtn.style.borderColor = this.colors.accent;\n cancelBtn.style.color = this.colors.accent;\n });\n cancelBtn.addEventListener(\"mouseleave\", () => {\n cancelBtn.style.borderColor = \"#e2e8f0\";\n cancelBtn.style.color = \"#64748b\";\n });\n\n this.submitBtn = document.createElement(\"button\");\n this.submitBtn.style.cssText = `\n height:34px;padding:0 18px;border-radius:9999px;\n border:none;background:${this.colors.accentGradient};\n color:#fff;font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:13px;font-weight:600;cursor:pointer;\n opacity:0.35;pointer-events:none;\n transition:all 0.2s ease;\n box-shadow:0 2px 8px ${this.colors.accentGlow};\n `;\n setText(this.submitBtn, \"Envoyer\");\n this.submitBtn.addEventListener(\"click\", () => this.submit());\n\n btnRow.appendChild(cancelBtn);\n btnRow.appendChild(this.submitBtn);\n\n this.root.appendChild(typeRow);\n this.root.appendChild(this.textarea);\n this.root.appendChild(hint);\n this.root.appendChild(btnRow);\n document.body.appendChild(this.root);\n }\n\n /**\n * Show the popup near a drawn rectangle and return the user's input.\n * Returns null if cancelled.\n */\n show(rectBounds: DOMRect): Promise<PopupResult | null> {\n return new Promise((resolve) => {\n this.resolve = resolve;\n this.selectedType = null;\n this.textarea.value = \"\";\n this.updateSubmitState();\n this.resetTypeButtons();\n\n // Position: bottom-left of rect, 8px below\n let top = rectBounds.bottom + 8;\n let left = rectBounds.left;\n\n // Collision: flip up if not enough space below\n if (top + 220 > window.innerHeight) {\n top = rectBounds.top - 220 - 8;\n }\n // Collision: flip right if not enough space on left\n if (left + 300 > window.innerWidth) {\n left = rectBounds.right - 300;\n }\n left = Math.max(8, left);\n top = Math.max(8, top);\n\n this.root.style.top = `${top}px`;\n this.root.style.left = `${left}px`;\n this.root.style.display = \"block\";\n\n // Trigger animation\n requestAnimationFrame(() => {\n this.root.style.opacity = \"1\";\n this.root.style.transform = \"translateY(0) scale(1)\";\n this.textarea.focus();\n });\n });\n }\n\n private selectType(type: FeedbackType, container: HTMLElement): void {\n this.selectedType = type;\n const buttons = container.querySelectorAll<HTMLButtonElement>(\"button\");\n for (const btn of buttons) {\n const isActive = btn.dataset.type === type;\n const color = getTypeColor(btn.dataset.type ?? \"\", this.colors);\n const bgColor = getTypeBgColor(btn.dataset.type ?? \"\", this.colors);\n btn.style.background = isActive ? bgColor : \"rgba(255,255,255,0.8)\";\n btn.style.borderColor = isActive ? color + \"60\" : \"#e2e8f0\";\n btn.style.color = isActive ? color : \"#64748b\";\n btn.style.fontWeight = isActive ? \"600\" : \"500\";\n }\n this.updateSubmitState();\n }\n\n private resetTypeButtons(): void {\n const buttons = this.root.querySelectorAll<HTMLButtonElement>(\"button[data-type]\");\n for (const btn of buttons) {\n btn.style.background = \"rgba(255,255,255,0.8)\";\n btn.style.borderColor = \"#e2e8f0\";\n btn.style.color = \"#64748b\";\n btn.style.fontWeight = \"500\";\n }\n }\n\n private updateSubmitState(): void {\n const enabled = this.selectedType !== null && this.textarea.value.trim().length > 0;\n this.submitBtn.style.opacity = enabled ? \"1\" : \"0.35\";\n this.submitBtn.style.pointerEvents = enabled ? \"auto\" : \"none\";\n }\n\n private submit(): void {\n if (!this.selectedType || !this.textarea.value.trim()) return;\n this.resolve?.({ type: this.selectedType, message: this.textarea.value.trim() });\n this.resolve = null;\n this.hideElement();\n }\n\n private cancel(): void {\n this.resolve?.(null);\n this.resolve = null;\n this.hideElement();\n }\n\n private hideElement(): void {\n this.root.style.opacity = \"0\";\n this.root.style.transform = \"translateY(8px) scale(0.98)\";\n setTimeout(() => {\n this.root.style.display = \"none\";\n }, 250);\n }\n\n destroy(): void {\n this.root.remove();\n }\n}\n","import type { AnnotationPayload, FeedbackType, SitepingConfig } from \"@siteping/core\";\nimport { findAnchorElement, generateAnchor, rectToPercentages } from \"./dom/anchor.js\";\nimport { el, setText } from \"./dom-utils.js\";\nimport type { EventBus, WidgetEvents } from \"./events.js\";\nimport { Popup } from \"./popup.js\";\nimport type { ThemeColors } from \"./styles/theme.js\";\n\nexport interface AnnotationComplete {\n annotation: AnnotationPayload;\n type: FeedbackType;\n message: string;\n}\n\n/**\n * Annotation mode: full-page overlay with rectangle drawing.\n *\n * Glassmorphism design:\n * - Frosted glass toolbar at top\n * - Subtle tinted overlay\n * - Accent-colored drawing rectangle with glow\n */\nexport class Annotator {\n private overlay: HTMLElement | null = null;\n private toolbar: HTMLElement | null = null;\n private drawingRect: HTMLElement | null = null;\n private startX = 0;\n private startY = 0;\n private isDrawing = false;\n private isActive = false;\n private popup: Popup;\n private savedOverflow = \"\";\n\n constructor(\n private readonly config: SitepingConfig,\n private readonly colors: ThemeColors,\n private readonly bus: EventBus<WidgetEvents>,\n ) {\n this.popup = new Popup(colors);\n\n this.bus.on(\"annotation:start\", () => this.activate());\n }\n\n private activate(): void {\n if (this.isActive) return;\n this.isActive = true;\n this.config.onAnnotationStart?.();\n\n // Lock page scroll\n this.savedOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n // Overlay — subtle blue tint for depth\n this.overlay = el(\"div\", {\n style: `\n position:fixed;inset:0;\n z-index:2147483646;\n background:rgba(15, 23, 42, 0.04);\n cursor:crosshair;\n `,\n });\n\n // Toolbar — glassmorphism bar\n this.toolbar = el(\"div\", {\n style: `\n position:fixed;top:0;left:0;right:0;\n z-index:2147483647;\n height:52px;\n background:rgba(255, 255, 255, 0.82);\n backdrop-filter:blur(24px);\n -webkit-backdrop-filter:blur(24px);\n border-bottom:1px solid rgba(255, 255, 255, 0.35);\n display:flex;align-items:center;justify-content:center;gap:16px;\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:14px;color:#0f172a;\n box-shadow:0 4px 16px rgba(0,0,0,0.06);\n -webkit-font-smoothing:antialiased;\n `,\n });\n\n const dot = el(\"span\", {\n style: `\n width:8px;height:8px;border-radius:50%;\n background:${this.colors.accent};\n box-shadow:0 0 8px ${this.colors.accentGlow};\n animation:pulse 1.5s ease-in-out infinite;\n `,\n });\n\n // Add pulse animation inline\n const style = document.createElement(\"style\");\n style.textContent = `@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.4}}`;\n this.toolbar.appendChild(style);\n\n const instruction = el(\"span\", { style: \"font-weight:500;letter-spacing:-0.01em;\" });\n setText(instruction, \"Tracez un rectangle sur la zone \\u00e0 commenter\");\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.style.cssText = `\n height:34px;padding:0 18px;border-radius:9999px;\n border:1px solid #e2e8f0;\n background:rgba(255,255,255,0.8);\n color:#64748b;font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:13px;font-weight:500;cursor:pointer;\n transition:all 0.2s ease;\n `;\n setText(cancelBtn, \"Annuler\");\n cancelBtn.addEventListener(\"click\", () => this.deactivate());\n cancelBtn.addEventListener(\"mouseenter\", () => {\n cancelBtn.style.borderColor = \"#ef4444\";\n cancelBtn.style.color = \"#ef4444\";\n cancelBtn.style.background = \"rgba(239,68,68,0.06)\";\n });\n cancelBtn.addEventListener(\"mouseleave\", () => {\n cancelBtn.style.borderColor = \"#e2e8f0\";\n cancelBtn.style.color = \"#64748b\";\n cancelBtn.style.background = \"rgba(255,255,255,0.8)\";\n });\n\n this.toolbar.appendChild(dot);\n this.toolbar.appendChild(instruction);\n this.toolbar.appendChild(cancelBtn);\n\n // Mouse events\n this.overlay.addEventListener(\"mousedown\", this.onMouseDown);\n this.overlay.addEventListener(\"mousemove\", this.onMouseMove);\n this.overlay.addEventListener(\"mouseup\", this.onMouseUp);\n\n // Escape to cancel\n document.addEventListener(\"keydown\", this.onKeyDown);\n\n document.body.appendChild(this.overlay);\n document.body.appendChild(this.toolbar);\n }\n\n private deactivate(): void {\n if (!this.isActive) return;\n this.isActive = false;\n this.isDrawing = false;\n\n document.body.style.overflow = this.savedOverflow;\n document.removeEventListener(\"keydown\", this.onKeyDown);\n\n this.overlay?.remove();\n this.toolbar?.remove();\n this.drawingRect?.remove();\n this.overlay = null;\n this.toolbar = null;\n this.drawingRect = null;\n\n this.config.onAnnotationEnd?.();\n this.bus.emit(\"annotation:end\");\n }\n\n private onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === \"Escape\") this.deactivate();\n };\n\n private onMouseDown = (e: MouseEvent): void => {\n this.isDrawing = true;\n this.startX = e.clientX;\n this.startY = e.clientY;\n\n this.drawingRect?.remove();\n this.drawingRect = el(\"div\", {\n style: `\n position:fixed;\n border:2px solid ${this.colors.accent};\n background:${this.colors.accent}12;\n pointer-events:none;\n border-radius:8px;\n box-shadow:0 0 16px ${this.colors.accentGlow};\n transition:box-shadow 0.15s ease;\n `,\n });\n this.overlay?.appendChild(this.drawingRect);\n };\n\n private onMouseMove = (e: MouseEvent): void => {\n if (!this.isDrawing || !this.drawingRect) return;\n\n const x = Math.min(e.clientX, this.startX);\n const y = Math.min(e.clientY, this.startY);\n const w = Math.abs(e.clientX - this.startX);\n const h = Math.abs(e.clientY - this.startY);\n\n this.drawingRect.style.left = `${x}px`;\n this.drawingRect.style.top = `${y}px`;\n this.drawingRect.style.width = `${w}px`;\n this.drawingRect.style.height = `${h}px`;\n };\n\n private onMouseUp = async (e: MouseEvent): Promise<void> => {\n if (!this.isDrawing || !this.drawingRect) return;\n this.isDrawing = false;\n\n const x = Math.min(e.clientX, this.startX);\n const y = Math.min(e.clientY, this.startY);\n const w = Math.abs(e.clientX - this.startX);\n const h = Math.abs(e.clientY - this.startY);\n\n // Ignore tiny rectangles (accidental clicks)\n if (w < 10 || h < 10) {\n this.drawingRect.remove();\n this.drawingRect = null;\n return;\n }\n\n const rectBounds = new DOMRect(x, y, w, h);\n\n // Show popup for type + message\n const result = await this.popup.show(rectBounds);\n\n if (!result) {\n this.drawingRect?.remove();\n this.drawingRect = null;\n return;\n }\n\n // Build annotation payload BEFORE deactivating (needs overlay for elementFromPoint)\n const annotation = this.buildAnnotation(rectBounds);\n this.drawingRect?.remove();\n this.drawingRect = null;\n this.deactivate();\n\n // Emit via event bus (not DOM — overlay is already null after deactivate)\n this.bus.emit(\"annotation:complete\", {\n annotation,\n type: result.type,\n message: result.message,\n });\n };\n\n /**\n * Build an AnnotationPayload from a drawn rectangle.\n * Temporarily hides the overlay to access the real DOM underneath.\n */\n private buildAnnotation(rectBounds: DOMRect): AnnotationPayload {\n // Temporarily hide overlay to find the real element underneath\n if (this.overlay) this.overlay.style.pointerEvents = \"none\";\n const anchorElement = findAnchorElement(rectBounds);\n if (this.overlay) this.overlay.style.pointerEvents = \"auto\";\n\n const anchor = generateAnchor(anchorElement);\n const anchorBounds = anchorElement.getBoundingClientRect();\n const rect = rectToPercentages(rectBounds, anchorBounds);\n\n return {\n anchor,\n rect,\n scrollX: window.scrollX,\n scrollY: window.scrollY,\n viewportW: window.innerWidth,\n viewportH: window.innerHeight,\n devicePixelRatio: window.devicePixelRatio,\n };\n }\n destroy(): void {\n this.deactivate();\n this.popup.destroy();\n }\n}\n","import type { FeedbackPayload, FeedbackResponse, FeedbackStatus, FeedbackType } from \"@siteping/core\";\n\nconst MAX_RETRIES = 3;\nconst TIMEOUT_MS = 10_000;\nconst RETRY_QUEUE_KEY = \"siteping_retry_queue\";\n\n// ---------------------------------------------------------------------------\n// Core fetch with retry + exponential backoff + jitter\n// ---------------------------------------------------------------------------\n\nasync function resilientFetch(url: string, init: RequestInit, retries = MAX_RETRIES): Promise<Response> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);\n\n try {\n const response = await fetch(url, {\n ...init,\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n // Don't retry client errors (4xx) — only server errors (5xx)\n if (response.ok || (response.status >= 400 && response.status < 500)) {\n return response;\n }\n\n if (attempt === retries) return response;\n } catch (error) {\n clearTimeout(timeout);\n if (attempt === retries) throw error;\n }\n\n // Exponential backoff with jitter: 1s, 2s, 4s + random ±500ms\n const baseDelay = 1000 * 2 ** attempt;\n const jitter = Math.random() * 1000 - 500;\n await new Promise((r) => setTimeout(r, baseDelay + jitter));\n }\n\n throw new Error(\"Max retries exceeded\");\n}\n\n// ---------------------------------------------------------------------------\n// Retry queue — persist failed feedbacks for retry on next page load\n// ---------------------------------------------------------------------------\n\nfunction queueForRetry(endpoint: string, payload: FeedbackPayload): void {\n try {\n const raw = localStorage.getItem(RETRY_QUEUE_KEY);\n const queue: Array<{ endpoint: string; payload: FeedbackPayload }> = raw ? JSON.parse(raw) : [];\n queue.push({ endpoint, payload });\n localStorage.setItem(RETRY_QUEUE_KEY, JSON.stringify(queue));\n } catch {\n // localStorage full or unavailable — silently drop\n }\n}\n\nexport async function flushRetryQueue(endpoint: string): Promise<void> {\n try {\n const raw = localStorage.getItem(RETRY_QUEUE_KEY);\n if (!raw) return;\n\n const queue: Array<{ endpoint: string; payload: FeedbackPayload }> = JSON.parse(raw);\n\n const toRetry = queue.filter((e) => e.endpoint === endpoint);\n if (toRetry.length === 0) return;\n\n const failed: Array<{ endpoint: string; payload: FeedbackPayload }> = [];\n\n for (const entry of toRetry) {\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(entry.payload),\n });\n if (!res.ok) failed.push(entry);\n } catch {\n failed.push(entry);\n }\n }\n\n // Rebuild queue: keep unrelated entries + failed retries\n const remaining = queue.filter((e) => e.endpoint !== endpoint).concat(failed);\n if (remaining.length > 0) {\n localStorage.setItem(RETRY_QUEUE_KEY, JSON.stringify(remaining));\n } else {\n localStorage.removeItem(RETRY_QUEUE_KEY);\n }\n } catch {\n // Ignore — localStorage may be unavailable\n }\n}\n\n// ---------------------------------------------------------------------------\n// API client\n// ---------------------------------------------------------------------------\n\nexport class ApiClient {\n constructor(private readonly endpoint: string) {}\n\n async sendFeedback(payload: FeedbackPayload): Promise<FeedbackResponse> {\n try {\n const response = await resilientFetch(this.endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"Unknown error\");\n throw new Error(`Failed to send feedback: ${response.status} ${text}`);\n }\n\n return await response.json();\n } catch (error) {\n queueForRetry(this.endpoint, payload);\n throw error;\n }\n }\n\n async getFeedbacks(\n projectName: string,\n options?: {\n page?: number;\n limit?: number;\n type?: FeedbackType;\n status?: FeedbackStatus;\n search?: string;\n },\n ): Promise<{ feedbacks: FeedbackResponse[]; total: number }> {\n const params = new URLSearchParams({ projectName });\n if (options?.page) params.set(\"page\", String(options.page));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.type) params.set(\"type\", options.type);\n if (options?.status) params.set(\"status\", options.status);\n if (options?.search) params.set(\"search\", options.search);\n\n const response = await resilientFetch(`${this.endpoint}?${params.toString()}`, { method: \"GET\" });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch feedbacks: ${response.status}`);\n }\n\n return await response.json();\n }\n\n async resolveFeedback(id: string, resolved: boolean): Promise<FeedbackResponse> {\n const response = await resilientFetch(this.endpoint, {\n method: \"PATCH\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ id, status: resolved ? \"resolved\" : \"open\" }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to update feedback: ${response.status}`);\n }\n\n return await response.json();\n }\n\n async deleteFeedback(id: string): Promise<void> {\n const response = await resilientFetch(this.endpoint, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ id }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete feedback: ${response.status}`);\n }\n }\n\n async deleteAllFeedbacks(projectName: string): Promise<void> {\n const response = await resilientFetch(this.endpoint, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ projectName, deleteAll: true }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete all feedbacks: ${response.status}`);\n }\n }\n}\n","type Listener = (...args: any[]) => void;\n\n/**\n * Lightweight typed EventEmitter — zero dependencies.\n */\nexport class EventBus<E extends { [K in keyof E]: unknown[] }> {\n private listeners = new Map<keyof E, Set<Listener>>();\n\n on<K extends keyof E>(event: K, listener: (...args: E[K]) => void): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n const set = this.listeners.get(event)!;\n set.add(listener as Listener);\n\n return () => {\n set.delete(listener as Listener);\n };\n }\n\n emit<K extends keyof E>(event: K, ...args: E[K]): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const fn of set) {\n try {\n fn(...args);\n } catch (err) {\n // Isolate listener errors — one bad listener must not kill others\n console.error(`[siteping] Error in event listener for \"${String(event)}\":`, err);\n }\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Widget event types\n// ---------------------------------------------------------------------------\n\nexport interface WidgetEvents {\n open: [];\n close: [];\n \"feedback:sent\": [import(\"@siteping/core\").FeedbackResponse];\n \"feedback:deleted\": [string];\n \"feedback:all-deleted\": [];\n \"feedback:error\": [Error];\n \"annotation:start\": [];\n \"annotation:end\": [];\n \"annotation:complete\": [import(\"./annotator.js\").AnnotationComplete];\n \"annotations:toggle\": [boolean];\n \"panel:toggle\": [boolean];\n}\n","import type { SitepingConfig } from \"@siteping/core\";\nimport { parseSvg, setText } from \"./dom-utils.js\";\nimport type { EventBus, WidgetEvents } from \"./events.js\";\nimport { ICON_ANNOTATE, ICON_CHAT, ICON_CLOSE, ICON_EYE, ICON_EYE_OFF, ICON_SITEPING } from \"./icons.js\";\n\ninterface RadialItem {\n id: string;\n icon: string;\n iconAlt?: string;\n label: string;\n}\n\nconst ITEM_GAP = 54;\n\n/**\n * Floating Action Button with radial menu and notification badge.\n *\n * Glassmorphism: gradient background, glow shadow, glass radial items.\n * Badge shows unresolved feedback count.\n */\nexport class Fab {\n private root: HTMLElement;\n private fab: HTMLButtonElement;\n private radialContainer: HTMLElement;\n private badgeEl: HTMLElement | null = null;\n private isOpen = false;\n private annotationsVisible = true;\n private items: RadialItem[];\n\n constructor(\n shadowRoot: ShadowRoot,\n config: SitepingConfig,\n private readonly bus: EventBus<WidgetEvents>,\n ) {\n const position = config.position ?? \"bottom-right\";\n const isRight = position === \"bottom-right\";\n\n // Vertical stack above the FAB\n this.items = [\n { id: \"chat\", icon: ICON_CHAT, label: \"Messages\" },\n { id: \"annotate\", icon: ICON_ANNOTATE, label: \"Annoter\" },\n { id: \"toggle-annotations\", icon: ICON_EYE, iconAlt: ICON_EYE_OFF, label: \"Annotations\" },\n ];\n\n // FAB button — needs position:relative for badge positioning\n this.fab = document.createElement(\"button\");\n this.fab.className = `sp-fab sp-fab--${position} sp-anim-fab-in`;\n this.fab.style.position = \"fixed\"; // ensure fixed even with relative children\n this.fab.appendChild(parseSvg(ICON_SITEPING));\n this.fab.setAttribute(\"aria-label\", \"Siteping — Menu feedback\");\n this.fab.setAttribute(\"aria-expanded\", \"false\");\n this.fab.addEventListener(\"click\", () => this.toggle());\n\n // Radial container\n this.radialContainer = document.createElement(\"div\");\n this.radialContainer.className = `sp-radial sp-radial--${position}`;\n this.radialContainer.setAttribute(\"role\", \"menu\");\n\n for (let i = 0; i < this.items.length; i++) {\n const item = this.items[i];\n const btn = document.createElement(\"button\");\n btn.className = \"sp-radial-item\";\n btn.style.setProperty(\"--sp-i\", String(i));\n btn.appendChild(parseSvg(item.icon));\n btn.setAttribute(\"role\", \"menuitem\");\n btn.setAttribute(\"aria-label\", item.label);\n btn.dataset.itemId = item.id;\n\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.handleItemClick(item.id);\n });\n\n const label = document.createElement(\"span\");\n label.className = \"sp-radial-label\";\n label.textContent = item.label;\n label.style.cssText = isRight\n ? \"position:absolute; right:54px; top:50%; transform:translateY(-50%); white-space:nowrap;\"\n : \"position:absolute; left:54px; top:50%; transform:translateY(-50%); white-space:nowrap;\";\n btn.appendChild(label);\n\n this.radialContainer.appendChild(btn);\n }\n\n this.root = document.createElement(\"div\");\n this.root.appendChild(this.radialContainer);\n this.root.appendChild(this.fab);\n shadowRoot.appendChild(this.root);\n\n // Close radial menu on click outside.\n const host = shadowRoot.host;\n this.onDocumentClick = (e: MouseEvent) => {\n if (this.isOpen && !e.composedPath().includes(host)) {\n this.close();\n }\n };\n document.addEventListener(\"click\", this.onDocumentClick);\n\n this.fab.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\" && this.isOpen) this.close();\n });\n }\n\n private onDocumentClick: (e: MouseEvent) => void;\n\n /** Update the badge count. Pass 0 to hide. */\n updateBadge(count: number): void {\n if (count <= 0) {\n this.badgeEl?.remove();\n this.badgeEl = null;\n return;\n }\n\n if (!this.badgeEl) {\n this.badgeEl = document.createElement(\"span\");\n this.badgeEl.className = \"sp-fab-badge\";\n this.fab.appendChild(this.badgeEl);\n }\n\n setText(this.badgeEl, count > 99 ? \"99+\" : String(count));\n }\n\n private toggle(): void {\n this.isOpen ? this.close() : this.open();\n }\n\n private open(): void {\n this.isOpen = true;\n this.setFabIcon(ICON_CLOSE);\n this.fab.setAttribute(\"aria-expanded\", \"true\");\n\n const buttons = this.radialContainer.querySelectorAll<HTMLButtonElement>(\".sp-radial-item\");\n buttons.forEach((btn, i) => {\n // Stack vertically above the FAB with initial offset + gap\n const y = -(16 + ITEM_GAP * (i + 1));\n btn.style.transform = `translate(0px, ${y}px) scale(1)`;\n btn.classList.add(\"sp-radial-item--open\");\n });\n }\n\n private close(): void {\n this.isOpen = false;\n this.setFabIcon(ICON_SITEPING);\n this.fab.setAttribute(\"aria-expanded\", \"false\");\n\n const buttons = this.radialContainer.querySelectorAll<HTMLButtonElement>(\".sp-radial-item\");\n buttons.forEach((btn) => {\n btn.style.transform = \"translate(0, 0) scale(0.8)\";\n btn.classList.remove(\"sp-radial-item--open\");\n });\n }\n\n private setFabIcon(svgStr: string): void {\n const badge = this.badgeEl;\n this.fab.replaceChildren(parseSvg(svgStr));\n // Re-append badge after icon swap\n if (badge) this.fab.appendChild(badge);\n }\n\n private handleItemClick(id: string): void {\n this.close();\n\n switch (id) {\n case \"chat\":\n this.bus.emit(\"panel:toggle\", true);\n break;\n case \"annotate\":\n this.bus.emit(\"annotation:start\");\n break;\n case \"toggle-annotations\": {\n this.annotationsVisible = !this.annotationsVisible;\n this.bus.emit(\"annotations:toggle\", this.annotationsVisible);\n const btn = this.radialContainer.querySelector('[data-item-id=\"toggle-annotations\"]');\n if (btn) {\n btn.replaceChildren(parseSvg(this.annotationsVisible ? ICON_EYE : ICON_EYE_OFF));\n }\n break;\n }\n }\n }\n\n destroy(): void {\n document.removeEventListener(\"click\", this.onDocumentClick);\n this.root.remove();\n }\n}\n","const STORAGE_KEY = \"siteping_identity\";\n\nexport interface Identity {\n name: string;\n email: string;\n}\n\nexport function getIdentity(): Identity | null {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as Identity;\n if (parsed.name && parsed.email) return parsed;\n return null;\n } catch {\n return null;\n }\n}\n\nexport function saveIdentity(identity: Identity): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(identity));\n } catch {\n // Quota exceeded or localStorage disabled — identity works for this session only\n }\n}\n","/**\n * Lightweight fuzzy text matching for DOM re-anchoring.\n * Zero dependencies — bundled into the widget.\n * Uses Levenshtein distance, optimized for short strings (~50 chars).\n */\n\n/**\n * Levenshtein edit distance.\n * O(n*m) time, O(min(n,m)) space.\n */\nexport function editDistance(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n // Ensure `a` is the shorter string for space optimization\n if (a.length > b.length) {\n const t = a;\n a = b;\n b = t;\n }\n\n const aLen = a.length;\n const bLen = b.length;\n let prev = new Array<number>(aLen + 1);\n for (let k = 0; k <= aLen; k++) prev[k] = k;\n let curr = new Array<number>(aLen + 1);\n\n for (let j = 1; j <= bLen; j++) {\n curr[0] = j;\n for (let i = 1; i <= aLen; i++) {\n curr[i] = a[i - 1] === b[j - 1] ? prev[i - 1] : 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);\n }\n const tmp = prev;\n prev = curr;\n curr = tmp;\n }\n\n return prev[aLen];\n}\n\n/**\n * Normalized similarity score (0–1, where 1 = identical).\n */\nexport function similarity(a: string, b: string): number {\n if (a === b) return 1;\n const maxLen = Math.max(a.length, b.length);\n if (maxLen === 0) return 1;\n return 1 - editDistance(a, b) / maxLen;\n}\n\n/**\n * Fuzzy substring search — checks if `needle` approximately exists in `haystack`.\n * Slides a window of `needle.length` over the haystack and returns the best\n * similarity score found. Returns 0 if below `minScore`.\n */\nexport function fuzzyIncludes(haystack: string, needle: string, minScore = 0.6): number {\n if (!needle || !haystack) return 0;\n if (haystack.includes(needle)) return 1;\n\n const nLen = needle.length;\n\n // If needle is longer than haystack, compare directly\n if (nLen > haystack.length) {\n const score = similarity(haystack, needle);\n return score >= minScore ? score : 0;\n }\n\n let best = 0;\n\n // Cap haystack to avoid O(n²) on huge text nodes\n const capped = haystack.length > 500 ? haystack.slice(0, 500) : haystack;\n const limit = capped.length - nLen;\n\n for (let i = 0; i <= limit; i++) {\n const window = capped.slice(i, i + nLen);\n const score = similarity(window, needle);\n if (score > best) best = score;\n if (best >= 0.95) break;\n }\n\n return best >= minScore ? best : 0;\n}\n","import type { AnchorData, RectData } from \"@siteping/core\";\nimport { scoreFingerprint } from \"./fingerprint.js\";\nimport { fuzzyIncludes, similarity } from \"./fuzzy.js\";\nimport { adjacentText, neighborText } from \"./text-context.js\";\n\nexport type ResolutionStrategy = \"id\" | \"css\" | \"xpath\" | \"scan\";\n\nexport interface AnchorResolution {\n element: Element;\n confidence: number;\n strategy: ResolutionStrategy;\n}\n\nexport interface ResolvedAnnotation {\n element: Element;\n rect: DOMRect;\n confidence: number;\n strategy: ResolutionStrategy;\n}\n\n/** Max elements to scan during smart fallback. */\nconst MAX_SCAN_CANDIDATES = 300;\n\n/** Minimum fuzzy text match score for CSS/XPath verification. */\nconst TEXT_MATCH_THRESHOLD = 0.3;\n\n/**\n * Verify that a resolved element's text content matches the stored snippet.\n * If no snippet is stored, returns true (no verification possible).\n * Uses fuzzy matching to tolerate minor text changes.\n */\nfunction textMatches(el: Element, anchor: AnchorData): boolean {\n if (!anchor.textSnippet) return true;\n const text = (el.textContent?.trim() ?? \"\").slice(0, 500);\n return fuzzyIncludes(text, anchor.textSnippet, 0.5) > TEXT_MATCH_THRESHOLD;\n}\n\n/**\n * Re-anchor an annotation using a multi-level fallback strategy\n * with text verification and confidence scoring.\n *\n * Resolution order:\n * 1. getElementById + text verification — confidence 1.0\n * 2. CSS selector + text verification — confidence 0.95\n * 3. XPath + text verification — confidence 0.9\n * 4. Smart scan (fingerprint + text + prefix/suffix + neighbor) — up to 0.85\n *\n * Text verification prevents false matches when DOM elements are reordered.\n * Returns null if all strategies fail (annotation is orphaned).\n */\nexport function resolveAnchor(anchor: AnchorData): AnchorResolution | null {\n // Level 1: Element ID (most stable, still verify text)\n if (anchor.elementId) {\n const el = document.getElementById(anchor.elementId);\n if (el && el.tagName === anchor.elementTag && textMatches(el, anchor)) {\n return { element: el, confidence: 1.0, strategy: \"id\" };\n }\n }\n\n // Level 2: CSS Selector (with text verification)\n try {\n const el = document.querySelector(anchor.cssSelector);\n if (el && el.tagName === anchor.elementTag && textMatches(el, anchor)) {\n return { element: el, confidence: 0.95, strategy: \"css\" };\n }\n } catch {\n // Invalid selector — skip\n }\n\n // Level 3: XPath (with text verification)\n try {\n const result = document.evaluate(anchor.xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);\n const el = result.singleNodeValue;\n if (el instanceof Element && el.tagName === anchor.elementTag && textMatches(el, anchor)) {\n return { element: el, confidence: 0.9, strategy: \"xpath\" };\n }\n } catch {\n // Invalid XPath — skip\n }\n\n // Level 4: Smart scan — combine all available signals\n return smartScan(anchor);\n}\n\n/**\n * Scan DOM elements by tag and score each candidate using multiple signals:\n * fingerprint, text similarity, prefix/suffix context, neighbor text.\n *\n * Returns the best candidate above a 0.4 threshold, capped at 0.85 confidence\n * (smart scan is never 100% certain).\n */\nfunction smartScan(anchor: AnchorData): AnchorResolution | null {\n const tag = anchor.elementTag.toLowerCase();\n const candidates = document.querySelectorAll(tag);\n if (candidates.length === 0) return null;\n\n let bestElement: Element | null = null;\n let bestScore = 0;\n\n const limit = Math.min(candidates.length, MAX_SCAN_CANDIDATES);\n\n for (let i = 0; i < limit; i++) {\n const el = candidates[i];\n const score = scoreCandidate(el, anchor);\n if (score > bestScore) {\n bestScore = score;\n bestElement = el;\n if (bestScore >= 0.85) break;\n }\n }\n\n if (!bestElement || bestScore < 0.4) return null;\n\n return {\n element: bestElement,\n confidence: Math.min(bestScore, 0.85),\n strategy: \"scan\",\n };\n}\n\n/**\n * Score a candidate element against all stored anchor signals.\n *\n * Dynamic weighting — only active signals contribute, then normalized:\n * - Text snippet (fuzzy substring match): weight 40 (most reliable for reordering)\n * - Fingerprint (structural match): weight 20\n * - Prefix/suffix context: weight 20\n * - Neighbor text: weight 20\n */\nfunction scoreCandidate(candidate: Element, anchor: AnchorData): number {\n let score = 0;\n let totalWeight = 0;\n\n // Truncate to avoid O(n*m) explosion on huge text nodes\n const candidateText = (candidate.textContent?.trim() ?? \"\").slice(0, 500);\n\n // --- Text snippet (weight 40 — most important for reordered elements) ---\n if (anchor.textSnippet) {\n totalWeight += 40;\n score += fuzzyIncludes(candidateText, anchor.textSnippet, 0.5) * 40;\n }\n\n // --- Fingerprint (weight 20) ---\n if (anchor.fingerprint) {\n totalWeight += 20;\n score += scoreFingerprint(candidate, anchor.fingerprint) * 20;\n }\n\n // --- Prefix/suffix context (weight 20) ---\n if (anchor.textPrefix || anchor.textSuffix) {\n totalWeight += 20;\n let contextScore = 0;\n let contextParts = 0;\n\n if (anchor.textPrefix) {\n const prevText = adjacentText(candidate, \"before\");\n contextScore += prevText ? similarity(prevText, anchor.textPrefix) : 0;\n contextParts++;\n }\n\n if (anchor.textSuffix) {\n const nextText = adjacentText(candidate, \"after\");\n contextScore += nextText ? similarity(nextText, anchor.textSuffix) : 0;\n contextParts++;\n }\n\n if (contextParts > 0) {\n score += (contextScore / contextParts) * 20;\n }\n }\n\n // --- Neighbor text (weight 20) ---\n if (anchor.neighborText) {\n totalWeight += 20;\n const candidateNeighbor = neighborText(candidate);\n score += candidateNeighbor ? similarity(candidateNeighbor, anchor.neighborText) * 20 : 0;\n }\n\n return totalWeight > 0 ? score / totalWeight : 0;\n}\n\n/**\n * Resolve an annotation's position on the page.\n * Converts stored percentage-based rect back to absolute coordinates\n * using the current bounding box of the resolved anchor element.\n */\nexport function resolveAnnotation(anchor: AnchorData, rect: RectData): ResolvedAnnotation | null {\n const resolution = resolveAnchor(anchor);\n\n if (!resolution) return null;\n\n const bounds = resolution.element.getBoundingClientRect();\n const absoluteRect = new DOMRect(\n bounds.x + rect.xPct * bounds.width,\n bounds.y + rect.yPct * bounds.height,\n rect.wPct * bounds.width,\n rect.hPct * bounds.height,\n );\n\n return {\n element: resolution.element,\n rect: absoluteRect,\n confidence: resolution.confidence,\n strategy: resolution.strategy,\n };\n}\n","import type { AnchorData, FeedbackResponse, RectData } from \"@siteping/core\";\nimport { resolveAnnotation } from \"./dom/resolver.js\";\nimport { el, setText } from \"./dom-utils.js\";\nimport type { EventBus, WidgetEvents } from \"./events.js\";\nimport { getTypeColor, type ThemeColors } from \"./styles/theme.js\";\nimport type { Tooltip } from \"./tooltip.js\";\n\ntype Annotation = FeedbackResponse[\"annotations\"][number];\n\nfunction toAnchorData(a: Annotation): AnchorData {\n return {\n cssSelector: a.cssSelector,\n xpath: a.xpath,\n textSnippet: a.textSnippet,\n elementTag: a.elementTag,\n elementId: a.elementId ?? undefined,\n textPrefix: a.textPrefix,\n textSuffix: a.textSuffix,\n fingerprint: a.fingerprint,\n neighborText: a.neighborText,\n };\n}\n\nfunction toRectData(a: Annotation): RectData {\n return { xPct: a.xPct, yPct: a.yPct, wPct: a.wPct, hPct: a.hPct };\n}\n\n/** Half of the 26px marker diameter — used for centering on anchor corner. */\nconst MARKER_OFFSET = 13;\n\n/** Convert a resolved rect to document-absolute marker position. */\nfunction markerPosition(rect: DOMRect): { top: number; left: number } {\n return {\n top: rect.top + window.scrollY - MARKER_OFFSET,\n left: rect.right + window.scrollX - MARKER_OFFSET,\n };\n}\n\ninterface MarkerEntry {\n feedback: FeedbackResponse;\n elements: HTMLElement[];\n baseTop: number;\n baseLeft: number;\n}\n\ninterface Cluster {\n entries: MarkerEntry[];\n elementIndices: number[];\n expanded: boolean;\n}\n\n/** Get the i-th marker element from a cluster. */\nfunction clusterMarker(cluster: Cluster, i: number): HTMLElement | undefined {\n return cluster.entries[i].elements[cluster.elementIndices[i]];\n}\n\nconst HIGHLIGHT_FADE = 300;\nconst REPOSITION_DEBOUNCE = 200;\nconst LOW_CONFIDENCE_THRESHOLD = 0.7;\nconst CLUSTER_DISTANCE = 28;\nconst FAN_SPACING = 32;\n\n/**\n * Numbered markers on the page for each feedback annotation.\n *\n * Cluster system: click-to-expand (same pattern as Google Maps / Spiderfier).\n * Hover is only used for tooltip/scale on individual markers — never for expansion.\n */\nexport class MarkerManager {\n private container: HTMLElement;\n private entries: MarkerEntry[] = [];\n private highlightElements: HTMLElement[] = [];\n private pinnedFeedback: FeedbackResponse | null = null;\n private onDocumentClick: ((e: MouseEvent) => void) | null = null;\n private repositionTimer: ReturnType<typeof setTimeout> | null = null;\n private mutationObserver: MutationObserver | null = null;\n private resizeHandler: (() => void) | null = null;\n private clusters: Cluster[] = [];\n private onDocumentClickForClusters: ((e: MouseEvent) => void) | null = null;\n\n get count(): number {\n return this.entries.length;\n }\n\n constructor(\n private readonly colors: ThemeColors,\n private readonly tooltip: Tooltip,\n private readonly bus: EventBus<WidgetEvents>,\n ) {\n this.container = el(\"div\", {\n style: \"position:absolute;top:0;left:0;pointer-events:none;z-index:2147483646;\",\n });\n this.container.id = \"siteping-markers\";\n document.body.appendChild(this.container);\n\n this.bus.on(\"annotations:toggle\", (visible) => {\n this.container.style.display = visible ? \"block\" : \"none\";\n });\n\n this.resizeHandler = () => this.scheduleReposition();\n window.addEventListener(\"resize\", this.resizeHandler, { passive: true });\n\n // Re-resolve after DOM changes (SPA, lazy-load).\n // Filter out mutations from our own container and the tooltip to avoid feedback loops.\n this.mutationObserver = new MutationObserver((mutations) => {\n const isWidgetMutation = mutations.every(\n (m) => this.container.contains(m.target) || this.tooltip.contains(m.target),\n );\n if (!isWidgetMutation) this.scheduleReposition();\n });\n this.mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: false,\n characterData: false,\n });\n\n this.onDocumentClickForClusters = (e: MouseEvent) => {\n if (this.container.contains(e.target as Node)) return;\n this.collapseAllClusters();\n };\n document.addEventListener(\"click\", this.onDocumentClickForClusters);\n }\n\n private scheduleReposition(): void {\n if (this.repositionTimer) return;\n this.repositionTimer = setTimeout(() => {\n this.repositionTimer = null;\n this.repositionAll();\n }, REPOSITION_DEBOUNCE);\n }\n\n private repositionAll(): void {\n for (const entry of this.entries) {\n for (let i = 0; i < entry.feedback.annotations.length; i++) {\n const markerEl = entry.elements[i];\n if (!markerEl) continue;\n\n const annotation = entry.feedback.annotations[i];\n const resolved = resolveAnnotation(toAnchorData(annotation), toRectData(annotation));\n if (!resolved) {\n markerEl.style.display = \"none\";\n continue;\n }\n\n const pos = markerPosition(resolved.rect);\n entry.baseTop = pos.top;\n entry.baseLeft = pos.left;\n markerEl.style.display = \"flex\";\n this.applyConfidenceStyle(markerEl, resolved.confidence, entry.feedback);\n }\n }\n this.applyClusterPositions();\n }\n\n private applyClusterPositions(): void {\n for (const cluster of this.clusters) {\n if (cluster.expanded) {\n this.applyFanPositions(cluster);\n } else {\n this.applyStackPositions(cluster);\n }\n }\n }\n\n render(feedbacks: FeedbackResponse[]): void {\n this.clear();\n feedbacks.forEach((feedback, i) => {\n const entry = this.buildEntry(feedback, i + 1);\n this.entries.push(entry);\n });\n this.buildClusters();\n }\n\n addFeedback(feedback: FeedbackResponse, index: number): void {\n const entry = this.buildEntry(feedback, index);\n for (const m of entry.elements) {\n m.style.animation = \"sp-marker-in 0.35s cubic-bezier(0.34,1.56,0.64,1) both\";\n }\n this.entries.push(entry);\n this.buildClusters();\n }\n\n private buildEntry(feedback: FeedbackResponse, index: number): MarkerEntry {\n const entry: MarkerEntry = { feedback, elements: [], baseTop: 0, baseLeft: 0 };\n for (const annotation of feedback.annotations) {\n const resolved = resolveAnnotation(toAnchorData(annotation), toRectData(annotation));\n if (!resolved) continue;\n const pos = markerPosition(resolved.rect);\n entry.baseTop = pos.top;\n entry.baseLeft = pos.left;\n const marker = this.createMarker(index, feedback, pos);\n this.applyConfidenceStyle(marker, resolved.confidence, feedback);\n this.container.appendChild(marker);\n entry.elements.push(marker);\n }\n return entry;\n }\n\n private buildClusters(): void {\n for (const badge of this.container.querySelectorAll<HTMLElement>(\".sp-cluster-badge\")) {\n badge.remove();\n }\n\n const allItems: { entry: MarkerEntry; elIdx: number }[] = [];\n for (const entry of this.entries) {\n for (let i = 0; i < entry.elements.length; i++) {\n allItems.push({ entry, elIdx: i });\n }\n }\n\n const used = new Set<number>();\n this.clusters = [];\n\n for (let i = 0; i < allItems.length; i++) {\n if (used.has(i)) continue;\n const cluster: Cluster = {\n entries: [allItems[i].entry],\n elementIndices: [allItems[i].elIdx],\n expanded: false,\n };\n used.add(i);\n\n for (let j = i + 1; j < allItems.length; j++) {\n if (used.has(j)) continue;\n const a = allItems[i].entry;\n const b = allItems[j].entry;\n const dist = Math.sqrt((a.baseLeft - b.baseLeft) ** 2 + (a.baseTop - b.baseTop) ** 2);\n if (dist < CLUSTER_DISTANCE) {\n cluster.entries.push(b);\n cluster.elementIndices.push(allItems[j].elIdx);\n used.add(j);\n }\n }\n\n this.clusters.push(cluster);\n }\n\n for (const cluster of this.clusters) {\n if (cluster.entries.length <= 1) continue;\n this.applyStackPositions(cluster);\n this.addClusterBadge(cluster);\n }\n }\n\n private applyStackPositions(cluster: Cluster): void {\n const { baseTop, baseLeft } = cluster.entries[0];\n const isSolo = cluster.entries.length <= 1;\n for (let i = 0; i < cluster.entries.length; i++) {\n const m = clusterMarker(cluster, i);\n if (!m) continue;\n m.style.top = `${baseTop + (isSolo ? 0 : i * 3)}px`;\n m.style.left = `${baseLeft + (isSolo ? 0 : i * 3)}px`;\n m.style.zIndex = String(i + 1);\n }\n }\n\n private applyFanPositions(cluster: Cluster): void {\n const { baseTop, baseLeft } = cluster.entries[0];\n const count = cluster.entries.length;\n const totalWidth = (count - 1) * FAN_SPACING;\n const startLeft = baseLeft - totalWidth / 2;\n\n for (let i = 0; i < count; i++) {\n const m = clusterMarker(cluster, i);\n if (!m) continue;\n m.style.top = `${baseTop}px`;\n m.style.left = `${startLeft + i * FAN_SPACING}px`;\n m.style.zIndex = String(10 + i);\n }\n }\n\n private addClusterBadge(cluster: Cluster): void {\n const topMarker = clusterMarker(cluster, cluster.entries.length - 1);\n if (!topMarker) return;\n const badge = el(\"div\", {\n class: \"sp-cluster-badge\",\n style: `\n position:absolute;top:-6px;right:-6px;\n min-width:16px;height:16px;padding:0 4px;\n border-radius:9999px;\n background:${this.colors.accent};color:#fff;\n font-size:10px;font-weight:700;\n display:flex;align-items:center;justify-content:center;\n border:1.5px solid #fff;\n pointer-events:none;\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n line-height:1;\n `,\n });\n setText(badge, String(cluster.entries.length));\n topMarker.appendChild(badge);\n }\n\n private setBadgesVisible(cluster: Cluster, visible: boolean): void {\n for (let i = 0; i < cluster.entries.length; i++) {\n const badge = clusterMarker(cluster, i)?.querySelector(\".sp-cluster-badge\") as HTMLElement | null;\n if (badge) badge.style.display = visible ? \"flex\" : \"none\";\n }\n }\n\n private findCluster(marker: HTMLElement): Cluster | null {\n for (const cluster of this.clusters) {\n if (cluster.entries.length <= 1) continue;\n for (let i = 0; i < cluster.entries.length; i++) {\n if (clusterMarker(cluster, i) === marker) return cluster;\n }\n }\n return null;\n }\n\n private handleClusterClick(marker: HTMLElement, e: MouseEvent): boolean {\n const cluster = this.findCluster(marker);\n if (!cluster) return false;\n if (!cluster.expanded) {\n e.stopPropagation();\n this.collapseAllClusters();\n cluster.expanded = true;\n this.applyFanPositions(cluster);\n this.setBadgesVisible(cluster, false);\n return true;\n }\n return false;\n }\n\n private collapseCluster(cluster: Cluster): void {\n if (!cluster.expanded) return;\n cluster.expanded = false;\n this.applyStackPositions(cluster);\n this.setBadgesVisible(cluster, true);\n }\n\n private collapseAllClusters(): void {\n for (const cluster of this.clusters) {\n this.collapseCluster(cluster);\n }\n }\n\n private applyConfidenceStyle(marker: HTMLElement, confidence: number, feedback: FeedbackResponse): void {\n const isResolved = feedback.status === \"resolved\";\n if (confidence < LOW_CONFIDENCE_THRESHOLD && !isResolved) {\n marker.style.borderStyle = \"dashed\";\n marker.style.opacity = \"0.7\";\n marker.title = `Position approximative (confiance : ${Math.round(confidence * 100)}%)`;\n } else {\n marker.style.borderStyle = \"solid\";\n marker.style.opacity = \"1\";\n marker.title = \"\";\n }\n }\n\n private createMarker(number: number, feedback: FeedbackResponse, pos: { top: number; left: number }): HTMLElement {\n const typeColor = getTypeColor(feedback.type, this.colors);\n const isResolved = feedback.status === \"resolved\";\n\n const marker = el(\"div\", {\n style: `\n position:absolute;\n top:${pos.top}px;\n left:${pos.left}px;\n width:26px;height:26px;\n border-radius:50%;\n background:${isResolved ? \"rgba(241,245,249,0.9)\" : \"rgba(255,255,255,0.92)\"};\n backdrop-filter:blur(12px);\n -webkit-backdrop-filter:blur(12px);\n border:2px solid ${isResolved ? \"#cbd5e1\" : typeColor};\n display:flex;align-items:center;justify-content:center;\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n font-size:11px;font-weight:700;\n color:${isResolved ? \"#94a3b8\" : typeColor};\n cursor:pointer;pointer-events:auto;\n box-shadow:${isResolved ? \"0 2px 8px rgba(0,0,0,0.06)\" : `0 2px 12px ${typeColor}25, 0 2px 6px rgba(0,0,0,0.06)`};\n transition:top 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), left 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.15s ease, box-shadow 0.15s ease;\n user-select:none;\n -webkit-font-smoothing:antialiased;\n `,\n });\n marker.dataset.feedbackId = feedback.id;\n setText(marker, isResolved ? \"\\u2713\" : String(number));\n\n marker.addEventListener(\"mouseenter\", () => {\n marker.style.transform = \"scale(1.2)\";\n marker.style.boxShadow = isResolved\n ? \"0 4px 16px rgba(0,0,0,0.1)\"\n : `0 4px 20px ${typeColor}35, 0 4px 12px rgba(0,0,0,0.08)`;\n this.tooltip.show(feedback, marker.getBoundingClientRect());\n if (!this.pinnedFeedback) this.showHighlight(feedback);\n });\n\n marker.addEventListener(\"mouseleave\", () => {\n marker.style.transform = \"scale(1)\";\n marker.style.boxShadow = isResolved\n ? \"0 2px 8px rgba(0,0,0,0.06)\"\n : `0 2px 12px ${typeColor}25, 0 2px 6px rgba(0,0,0,0.06)`;\n this.tooltip.scheduleHide();\n if (!this.pinnedFeedback) this.clearHighlight();\n });\n\n marker.addEventListener(\"click\", (e) => {\n if (this.handleClusterClick(marker, e)) return;\n this.pinHighlight(feedback);\n this.bus.emit(\"panel:toggle\", true);\n marker.dispatchEvent(\n new CustomEvent(\"sp-marker-click\", {\n detail: { feedbackId: feedback.id },\n bubbles: true,\n }),\n );\n });\n\n return marker;\n }\n\n highlight(feedbackId: string): void {\n for (const entry of this.entries) {\n if (entry.feedback.id === feedbackId) {\n for (const markerEl of entry.elements) {\n markerEl.style.animation = \"sp-pulse-ring 0.7s ease-out\";\n markerEl.addEventListener(\n \"animationend\",\n () => {\n markerEl.style.animation = \"\";\n },\n { once: true },\n );\n }\n }\n }\n }\n\n showHighlight(feedback: FeedbackResponse): void {\n this.removeHighlightElements();\n for (const annotation of feedback.annotations) {\n const resolved = resolveAnnotation(toAnchorData(annotation), toRectData(annotation));\n if (!resolved) continue;\n\n const typeColor = getTypeColor(feedback.type, this.colors);\n const rect = resolved.rect;\n const highlight = el(\"div\", {\n style: `\n position:absolute;\n top:${rect.top + window.scrollY}px;\n left:${rect.left + window.scrollX}px;\n width:${rect.width}px;height:${rect.height}px;\n border:2px solid ${typeColor};\n background:${typeColor}0c;\n border-radius:8px;\n pointer-events:none;z-index:-1;\n opacity:0;\n box-shadow:0 0 16px ${typeColor}20;\n transition:opacity ${HIGHLIGHT_FADE}ms ease;\n `,\n });\n this.container.appendChild(highlight);\n this.highlightElements.push(highlight);\n highlight.offsetHeight;\n highlight.style.opacity = \"1\";\n }\n }\n\n pinHighlight(feedback: FeedbackResponse): void {\n this.unpinHighlight();\n this.showHighlight(feedback);\n this.pinnedFeedback = feedback;\n this.onDocumentClick = (e: MouseEvent) => {\n if (this.container.contains(e.target as Node)) return;\n this.unpinHighlight();\n };\n document.addEventListener(\"click\", this.onDocumentClick, { capture: true });\n }\n\n private unpinHighlight(): void {\n if (this.onDocumentClick) {\n document.removeEventListener(\"click\", this.onDocumentClick, { capture: true });\n this.onDocumentClick = null;\n }\n this.pinnedFeedback = null;\n this.clearHighlight();\n }\n\n private clearHighlight(): void {\n for (const h of this.highlightElements) {\n h.style.opacity = \"0\";\n setTimeout(() => h.remove(), HIGHLIGHT_FADE);\n }\n this.highlightElements = [];\n }\n\n private removeHighlightElements(): void {\n for (const h of this.highlightElements) h.remove();\n this.highlightElements = [];\n }\n\n clear(): void {\n this.unpinHighlight();\n this.container.replaceChildren();\n this.entries = [];\n this.clusters = [];\n }\n\n destroy(): void {\n this.unpinHighlight();\n if (this.repositionTimer) clearTimeout(this.repositionTimer);\n if (this.resizeHandler) window.removeEventListener(\"resize\", this.resizeHandler);\n if (this.onDocumentClickForClusters) document.removeEventListener(\"click\", this.onDocumentClickForClusters);\n this.mutationObserver?.disconnect();\n this.container.remove();\n }\n}\n","import type { FeedbackResponse, FeedbackType } from \"@siteping/core\";\nimport type { ApiClient } from \"./api-client.js\";\nimport { el, formatRelativeDate, parseSvg, setText } from \"./dom-utils.js\";\nimport type { EventBus, WidgetEvents } from \"./events.js\";\nimport { ICON_CHECK, ICON_CLOSE, ICON_SEARCH, ICON_TRASH, ICON_UNDO } from \"./icons.js\";\nimport type { MarkerManager } from \"./markers.js\";\nimport { getTypeBgColor, getTypeColor, type ThemeColors } from \"./styles/theme.js\";\n\nconst TYPE_LABELS: Record<string, string> = {\n question: \"Question\",\n changement: \"Changement\",\n bug: \"Bug\",\n autre: \"Autre\",\n};\n\n/**\n * Side panel (400px) with feedback history, filters, and search.\n *\n * Lives inside the Shadow DOM.\n * Glassmorphism: glass background, staggered card animations,\n * loading states, resolve feedback with disabled state.\n */\nexport class Panel {\n private root: HTMLElement;\n private listContainer: HTMLElement;\n private searchInput: HTMLInputElement;\n private deleteAllBtn: HTMLButtonElement;\n private activeFilters = new Set<string>([\"all\"]);\n private feedbacks: FeedbackResponse[] = [];\n private isOpen = false;\n private searchTimeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n shadowRoot: ShadowRoot,\n private readonly colors: ThemeColors,\n private readonly bus: EventBus<WidgetEvents>,\n private readonly apiClient: ApiClient,\n private readonly projectName: string,\n private readonly markers: MarkerManager,\n ) {\n this.root = el(\"div\", { class: \"sp-panel\" });\n\n // Header\n const header = el(\"div\", { class: \"sp-panel-header\" });\n const title = el(\"span\", { class: \"sp-panel-title\" });\n setText(title, \"Feedbacks\");\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.className = \"sp-panel-close\";\n closeBtn.setAttribute(\"aria-label\", \"Fermer le panneau\");\n closeBtn.appendChild(parseSvg(ICON_CLOSE));\n closeBtn.addEventListener(\"click\", () => this.close());\n\n this.deleteAllBtn = document.createElement(\"button\");\n this.deleteAllBtn.className = \"sp-btn-delete-all\";\n this.deleteAllBtn.setAttribute(\"aria-label\", \"Tout supprimer\");\n this.deleteAllBtn.appendChild(parseSvg(ICON_TRASH));\n const deleteAllLabel = document.createElement(\"span\");\n setText(deleteAllLabel, \" Tout supprimer\");\n this.deleteAllBtn.appendChild(deleteAllLabel);\n this.deleteAllBtn.addEventListener(\"click\", () => this.confirmDeleteAll());\n\n const headerRight = el(\"div\", { class: \"sp-panel-header-right\" });\n headerRight.appendChild(this.deleteAllBtn);\n headerRight.appendChild(closeBtn);\n\n header.appendChild(title);\n header.appendChild(headerRight);\n\n // Filters\n const filters = el(\"div\", { class: \"sp-filters\" });\n\n // Search\n const searchWrap = el(\"div\", { class: \"sp-search-wrap\" });\n const searchIcon = parseSvg(ICON_SEARCH);\n searchIcon.setAttribute(\"class\", \"sp-search-icon\");\n this.searchInput = document.createElement(\"input\");\n this.searchInput.type = \"text\";\n this.searchInput.className = \"sp-search\";\n this.searchInput.placeholder = \"Rechercher...\";\n this.searchInput.setAttribute(\"aria-label\", \"Rechercher dans les feedbacks\");\n this.searchInput.addEventListener(\"input\", () => {\n if (this.searchTimeout) clearTimeout(this.searchTimeout);\n this.searchTimeout = setTimeout(() => this.loadFeedbacks(), 200);\n });\n searchWrap.appendChild(searchIcon);\n searchWrap.appendChild(this.searchInput);\n\n // Chips\n const chips = el(\"div\", { class: \"sp-chips\" });\n const chipOptions = [\n { value: \"all\", label: \"Tous\" },\n { value: \"question\", label: \"Question\" },\n { value: \"changement\", label: \"Changement\" },\n { value: \"bug\", label: \"Bug\" },\n { value: \"autre\", label: \"Autre\" },\n ];\n\n for (const option of chipOptions) {\n const chip = document.createElement(\"button\");\n chip.className = `sp-chip ${option.value === \"all\" ? \"sp-chip--active\" : \"\"}`;\n if (option.value !== \"all\") {\n chip.style.borderColor = getTypeColor(option.value, this.colors);\n }\n setText(chip, option.label);\n chip.dataset.filter = option.value;\n chip.addEventListener(\"click\", () => this.toggleFilter(option.value, chips));\n chips.appendChild(chip);\n }\n\n filters.appendChild(searchWrap);\n filters.appendChild(chips);\n\n // List\n this.listContainer = el(\"div\", { class: \"sp-list\" });\n\n this.root.appendChild(header);\n this.root.appendChild(filters);\n this.root.appendChild(this.listContainer);\n shadowRoot.appendChild(this.root);\n\n // Events\n this.bus.on(\"panel:toggle\", (open) => {\n open ? this.open() : this.close();\n });\n\n // Escape to close\n shadowRoot.addEventListener(\"keydown\", (e) => {\n if ((e as KeyboardEvent).key === \"Escape\" && this.isOpen) this.close();\n });\n\n // Listen for marker clicks\n this.onMarkerClick = ((e: CustomEvent) => {\n this.scrollToFeedback(e.detail.feedbackId);\n }) as EventListener;\n document.addEventListener(\"sp-marker-click\", this.onMarkerClick);\n }\n\n private onMarkerClick: EventListener;\n\n async open(): Promise<void> {\n if (this.isOpen) return;\n this.isOpen = true;\n this.root.classList.add(\"sp-panel--open\");\n this.bus.emit(\"open\");\n await this.loadFeedbacks();\n }\n\n close(): void {\n if (!this.isOpen) return;\n this.isOpen = false;\n this.root.classList.remove(\"sp-panel--open\");\n this.bus.emit(\"close\");\n }\n\n private showLoading(): void {\n this.listContainer.replaceChildren();\n const loading = el(\"div\", { class: \"sp-loading\" });\n const spinner = el(\"div\", { class: \"sp-spinner\" });\n loading.appendChild(spinner);\n this.listContainer.appendChild(loading);\n }\n\n private showError(): void {\n this.listContainer.replaceChildren();\n const empty = el(\"div\", { class: \"sp-empty\" });\n const text = el(\"div\", { class: \"sp-empty-text\" });\n setText(text, \"Erreur de chargement\");\n const retryBtn = document.createElement(\"button\");\n retryBtn.className = \"sp-btn-ghost\";\n retryBtn.style.marginTop = \"8px\";\n setText(retryBtn, \"Réessayer\");\n retryBtn.addEventListener(\"click\", () => this.loadFeedbacks());\n empty.appendChild(text);\n empty.appendChild(retryBtn);\n this.listContainer.appendChild(empty);\n }\n\n private async loadFeedbacks(): Promise<void> {\n const search = this.searchInput.value.trim() || undefined;\n const typeFilter = this.activeFilters.has(\"all\") ? undefined : (Array.from(this.activeFilters)[0] as FeedbackType);\n\n const options: { limit: number; type?: FeedbackType; search?: string } = { limit: 50 };\n if (typeFilter) options.type = typeFilter;\n if (search) options.search = search;\n\n // Only show spinner on first load (empty list) — otherwise keep current content visible\n const hasContent = this.feedbacks.length > 0;\n if (!hasContent) this.showLoading();\n\n try {\n const { feedbacks } = await this.apiClient.getFeedbacks(this.projectName, options);\n this.feedbacks = feedbacks;\n this.renderList();\n this.markers.render(feedbacks);\n } catch (error) {\n if (!hasContent) this.showError();\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private renderList(): void {\n this.listContainer.replaceChildren();\n\n if (this.feedbacks.length === 0) {\n const empty = el(\"div\", { class: \"sp-empty\" });\n const emptyText = el(\"div\", { class: \"sp-empty-text\" });\n setText(emptyText, \"Aucun feedback pour le moment\");\n empty.appendChild(emptyText);\n this.listContainer.appendChild(empty);\n return;\n }\n\n this.feedbacks.forEach((feedback, index) => {\n const card = this.createCard(feedback, index + 1);\n // Stagger animation via CSS custom property\n card.style.setProperty(\"--sp-card-i\", String(index));\n this.listContainer.appendChild(card);\n });\n }\n\n private createCard(feedback: FeedbackResponse, number: number): HTMLElement {\n const isResolved = feedback.status === \"resolved\";\n const typeColor = getTypeColor(feedback.type, this.colors);\n\n const card = el(\"div\", {\n class: `sp-card ${isResolved ? \"sp-card--resolved\" : \"\"}`,\n });\n card.dataset.feedbackId = feedback.id;\n\n // Color bar\n const bar = el(\"div\", { class: \"sp-card-bar\" });\n bar.style.background = isResolved ? \"#9ca3af\" : typeColor;\n\n // Body\n const body = el(\"div\", { class: \"sp-card-body\" });\n\n // Header: #number + badge + date\n const header = el(\"div\", { class: \"sp-card-header\" });\n\n const num = el(\"span\", { class: \"sp-card-number\" });\n setText(num, `#${number}`);\n\n const badge = el(\"span\", { class: \"sp-badge\" });\n const typeBg = getTypeBgColor(feedback.type, this.colors);\n badge.style.background = typeBg;\n badge.style.color = typeColor;\n setText(badge, TYPE_LABELS[feedback.type] ?? feedback.type);\n\n const date = el(\"span\", { class: \"sp-card-date\" });\n setText(date, formatRelativeDate(feedback.createdAt));\n\n header.appendChild(num);\n header.appendChild(badge);\n header.appendChild(date);\n\n // Message\n const message = el(\"div\", { class: \"sp-card-message\" });\n setText(message, feedback.message);\n\n // Expand button\n const expandBtn = document.createElement(\"button\");\n expandBtn.className = \"sp-card-expand\";\n setText(expandBtn, \"Voir plus\");\n expandBtn.style.display = \"none\";\n expandBtn.setAttribute(\"aria-expanded\", \"false\");\n expandBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n const isExpanded = message.classList.toggle(\"sp-card-message--expanded\");\n setText(expandBtn, isExpanded ? \"Voir moins\" : \"Voir plus\");\n expandBtn.setAttribute(\"aria-expanded\", String(isExpanded));\n });\n\n // Check if text is clamped (after render)\n requestAnimationFrame(() => {\n if (message.scrollHeight > message.clientHeight) {\n expandBtn.style.display = \"block\";\n }\n });\n\n // Footer: resolve button\n const footer = el(\"div\", { class: \"sp-card-footer\" });\n\n const resolveBtn = document.createElement(\"button\");\n resolveBtn.className = \"sp-btn-resolve\";\n if (isResolved) {\n resolveBtn.appendChild(parseSvg(ICON_UNDO));\n const span = document.createElement(\"span\");\n setText(span, \" Rouvrir\");\n resolveBtn.appendChild(span);\n } else {\n resolveBtn.appendChild(parseSvg(ICON_CHECK));\n const span = document.createElement(\"span\");\n setText(span, \" Résoudre\");\n resolveBtn.appendChild(span);\n }\n resolveBtn.addEventListener(\"click\", async (e) => {\n e.stopPropagation();\n await this.toggleResolve(feedback, resolveBtn);\n });\n\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.className = \"sp-btn-delete\";\n deleteBtn.appendChild(parseSvg(ICON_TRASH));\n const deleteLabel = document.createElement(\"span\");\n setText(deleteLabel, \" Supprimer\");\n deleteBtn.appendChild(deleteLabel);\n deleteBtn.addEventListener(\"click\", async (e) => {\n e.stopPropagation();\n await this.deleteFeedback(feedback, deleteBtn);\n });\n\n footer.appendChild(resolveBtn);\n footer.appendChild(deleteBtn);\n\n body.appendChild(header);\n body.appendChild(message);\n body.appendChild(expandBtn);\n body.appendChild(footer);\n\n card.appendChild(bar);\n card.appendChild(body);\n\n // Hover: highlight corresponding marker\n card.addEventListener(\"mouseenter\", () => {\n this.markers.highlight(feedback.id);\n });\n\n // Click: scroll page to annotation + show highlight\n card.addEventListener(\"click\", () => {\n if (feedback.annotations.length > 0) {\n const ann = feedback.annotations[0];\n window.scrollTo({ left: ann.scrollX, top: ann.scrollY, behavior: \"smooth\" });\n this.markers.pinHighlight(feedback);\n }\n });\n\n return card;\n }\n\n private async deleteFeedback(feedback: FeedbackResponse, btn: HTMLButtonElement): Promise<void> {\n btn.disabled = true;\n try {\n await this.apiClient.deleteFeedback(feedback.id);\n this.bus.emit(\"feedback:deleted\", feedback.id);\n await this.loadFeedbacks();\n } catch (error) {\n btn.disabled = false;\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private async confirmDeleteAll(): Promise<void> {\n const confirmed = await this.showConfirmDialog(\n \"Tout supprimer\",\n \"Supprimer tous les feedbacks de ce projet ? Cette action est irréversible.\",\n );\n if (!confirmed) return;\n\n this.deleteAllBtn.disabled = true;\n try {\n await this.apiClient.deleteAllFeedbacks(this.projectName);\n this.bus.emit(\"feedback:all-deleted\");\n await this.loadFeedbacks();\n } catch (error) {\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n } finally {\n this.deleteAllBtn.disabled = false;\n }\n }\n\n private showConfirmDialog(title: string, message: string): Promise<boolean> {\n return new Promise((resolve) => {\n const backdrop = el(\"div\", { class: \"sp-confirm-backdrop\" });\n\n const titleId = `sp-confirm-title-${Date.now()}`;\n const messageId = `sp-confirm-msg-${Date.now()}`;\n\n const dialog = el(\"div\", { class: \"sp-confirm-dialog\" });\n dialog.setAttribute(\"role\", \"alertdialog\");\n dialog.setAttribute(\"aria-modal\", \"true\");\n dialog.setAttribute(\"aria-labelledby\", titleId);\n dialog.setAttribute(\"aria-describedby\", messageId);\n\n const titleEl = el(\"div\", { class: \"sp-confirm-title\" });\n titleEl.id = titleId;\n setText(titleEl, title);\n\n const messageEl = el(\"div\", { class: \"sp-confirm-message\" });\n messageEl.id = messageId;\n setText(messageEl, message);\n\n const btnRow = el(\"div\", { class: \"sp-confirm-actions\" });\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.type = \"button\";\n cancelBtn.className = \"sp-btn-ghost\";\n setText(cancelBtn, \"Annuler\");\n\n const confirmBtn = document.createElement(\"button\");\n confirmBtn.type = \"button\";\n confirmBtn.className = \"sp-btn-danger\";\n setText(confirmBtn, \"Supprimer\");\n\n let closed = false;\n const close = (result: boolean) => {\n if (closed) return;\n closed = true;\n backdrop.removeEventListener(\"keydown\", onKeydown);\n backdrop.style.opacity = \"0\";\n dialog.style.transform = \"translateY(8px) scale(0.97)\";\n setTimeout(() => {\n backdrop.remove();\n resolve(result);\n }, 200);\n };\n\n // Focus trap: Tab cycles between cancel and confirm\n const onKeydown = (e: Event) => {\n const ke = e as KeyboardEvent;\n if (ke.key === \"Escape\") {\n close(false);\n return;\n }\n if (ke.key === \"Tab\") {\n ke.preventDefault();\n const active = (backdrop.getRootNode() as ShadowRoot).activeElement;\n if (active === cancelBtn) {\n confirmBtn.focus();\n } else {\n cancelBtn.focus();\n }\n }\n };\n backdrop.addEventListener(\"keydown\", onKeydown);\n\n cancelBtn.addEventListener(\"click\", () => close(false));\n confirmBtn.addEventListener(\"click\", () => close(true));\n backdrop.addEventListener(\"click\", (e) => {\n if (e.target === backdrop) close(false);\n });\n\n btnRow.appendChild(cancelBtn);\n btnRow.appendChild(confirmBtn);\n dialog.appendChild(titleEl);\n dialog.appendChild(messageEl);\n dialog.appendChild(btnRow);\n backdrop.appendChild(dialog);\n\n this.root.getRootNode() instanceof ShadowRoot\n ? (this.root.getRootNode() as ShadowRoot).appendChild(backdrop)\n : this.root.appendChild(backdrop);\n\n requestAnimationFrame(() => {\n backdrop.style.opacity = \"1\";\n dialog.style.transform = \"translateY(0) scale(1)\";\n cancelBtn.focus();\n });\n });\n }\n\n private async toggleResolve(feedback: FeedbackResponse, btn: HTMLButtonElement): Promise<void> {\n // Disable button during async operation\n btn.disabled = true;\n try {\n const newResolved = feedback.status !== \"resolved\";\n await this.apiClient.resolveFeedback(feedback.id, newResolved);\n await this.loadFeedbacks();\n } catch (error) {\n btn.disabled = false;\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private toggleFilter(value: string, container: HTMLElement): void {\n // Single-select: only one filter active at a time\n this.activeFilters.clear();\n this.activeFilters.add(value);\n\n // Update chip styles\n const chips = container.querySelectorAll<HTMLButtonElement>(\".sp-chip\");\n for (const chip of chips) {\n const isActive = this.activeFilters.has(chip.dataset.filter ?? \"\");\n chip.classList.toggle(\"sp-chip--active\", isActive);\n }\n\n this.loadFeedbacks();\n }\n\n scrollToFeedback(feedbackId: string): void {\n const escapedId = CSS.escape(feedbackId);\n const card = this.listContainer.querySelector<HTMLElement>(`[data-feedback-id=\"${escapedId}\"]`);\n if (card) {\n card.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n card.classList.add(\"sp-anim-flash\");\n card.addEventListener(\n \"animationend\",\n () => {\n card.classList.remove(\"sp-anim-flash\");\n },\n { once: true },\n );\n }\n }\n\n /** Refresh the panel after a new feedback is submitted */\n async refresh(): Promise<void> {\n if (this.isOpen) {\n await this.loadFeedbacks();\n }\n }\n\n destroy(): void {\n if (this.searchTimeout) clearTimeout(this.searchTimeout);\n document.removeEventListener(\"sp-marker-click\", this.onMarkerClick);\n this.root.remove();\n }\n}\n","/**\n * CSS keyframes and animation utilities — Glassmorphism edition.\n *\n * Uses CSS-only spring animations via linear() timing function\n * and refined easing curves for premium motion design.\n */\n\n// Spring easing — computed from a spring simulation (damping: 15, stiffness: 100)\nconst SPRING_LINEAR = `linear(0, 0.006, 0.025, 0.06, 0.11, 0.17, 0.25, 0.34, 0.45, 0.56, 0.67, 0.78, 0.88, 0.95, 1.01, 1.04, 1.05, 1.04, 1.02, 1, 0.99, 1)`;\n\n// Ease-out-expo — fast start, smooth deceleration\nconst EASE_OUT_EXPO = `cubic-bezier(0.16, 1, 0.3, 1)`;\n\n// Spring overshoot — bouncy entrance\nconst SPRING_OVERSHOOT = `cubic-bezier(0.34, 1.56, 0.64, 1)`;\n\n// Smooth decel — for glass transitions\nconst EASE_OUT_QUART = `cubic-bezier(0.25, 1, 0.5, 1)`;\n\nexport const ANIMATION_CSS = `\n /* ---- Keyframes ---- */\n\n @keyframes sp-fab-in {\n from {\n transform: scale(0) rotate(-180deg);\n opacity: 0;\n }\n to {\n transform: scale(1) rotate(0deg);\n opacity: 1;\n }\n }\n\n @keyframes sp-fab-glow {\n 0%, 100% { box-shadow: 0 4px 20px var(--sp-accent-glow), 0 2px 8px rgba(0, 0, 0, 0.08); }\n 50% { box-shadow: 0 4px 28px var(--sp-accent-glow), 0 2px 12px rgba(0, 0, 0, 0.1); }\n }\n\n @keyframes sp-marker-in {\n 0% {\n transform: scale(0);\n opacity: 0;\n }\n 60% {\n transform: scale(1.2);\n opacity: 1;\n }\n 100% {\n transform: scale(1);\n }\n }\n\n @keyframes sp-pulse-ring {\n 0% {\n box-shadow: 0 0 0 0 var(--sp-accent-glow);\n }\n 70% {\n box-shadow: 0 0 0 8px transparent;\n }\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n }\n\n @keyframes sp-flash-bg {\n 0% { background-color: var(--sp-accent-light); }\n 100% { background-color: transparent; }\n }\n\n @keyframes sp-slide-up {\n from {\n transform: translateY(8px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n }\n\n @keyframes sp-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes sp-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n }\n\n /* ---- Animation classes ---- */\n\n .sp-anim-fab-in {\n animation: sp-fab-in 0.5s ${SPRING_LINEAR} both;\n }\n\n .sp-anim-marker-in {\n animation: sp-marker-in 0.35s ${SPRING_OVERSHOOT} both;\n }\n\n .sp-anim-pulse {\n animation: sp-pulse-ring 0.7s ease-out;\n }\n\n .sp-anim-flash {\n animation: sp-flash-bg 0.5s ${EASE_OUT_QUART};\n }\n\n .sp-anim-slide-up {\n animation: sp-slide-up 0.3s ${EASE_OUT_EXPO} both;\n }\n\n .sp-anim-fade-in {\n animation: sp-fade-in 0.2s ease-out both;\n }\n\n /* ---- Transition utilities ---- */\n\n .sp-panel {\n transform: translateX(110%);\n transition: transform 0.4s ${EASE_OUT_EXPO};\n }\n\n .sp-panel.sp-panel--open {\n transform: translateX(0);\n }\n\n .sp-radial-item {\n opacity: 0;\n pointer-events: none;\n transform: translate(0, 0) scale(0.8);\n transition:\n transform 0.35s ${SPRING_OVERSHOOT},\n opacity 0.2s ease,\n background 0.2s ease,\n border-color 0.2s ease,\n box-shadow 0.2s ease;\n }\n\n .sp-radial-item.sp-radial-item--open {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* Stagger delay via CSS custom property --sp-i */\n .sp-radial-item {\n transition-delay: calc(var(--sp-i, 0) * 50ms);\n }\n\n /* ---- Card stagger animation ---- */\n\n @keyframes sp-card-in {\n from {\n transform: translateY(12px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n }\n\n .sp-card {\n animation: sp-card-in 0.35s ${EASE_OUT_EXPO} both;\n animation-delay: calc(var(--sp-card-i, 0) * 40ms);\n }\n\n /* ---- Loading spinner ---- */\n\n @keyframes sp-spin {\n to { transform: rotate(360deg); }\n }\n\n .sp-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid var(--sp-border);\n border-top-color: var(--sp-accent);\n border-radius: 50%;\n animation: sp-spin 0.6s linear infinite;\n }\n\n /* ---- Badge bounce ---- */\n\n @keyframes sp-badge-in {\n 0% { transform: scale(0); }\n 60% { transform: scale(1.3); }\n 100% { transform: scale(1); }\n }\n\n .sp-fab-badge {\n animation: sp-badge-in 0.4s ${SPRING_OVERSHOOT} both;\n }\n\n /* ---- Reduced motion ---- */\n\n @media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n }\n\n`;\n","import { ANIMATION_CSS } from \"./animations.js\";\nimport { cssVariables, type ThemeColors } from \"./theme.js\";\n\n/**\n * Build the complete CSS stylesheet for the Shadow DOM.\n *\n * Design: Glassmorphism — frosted glass surfaces, soft depth,\n * accent gradients, premium micro-interactions.\n *\n * Principles:\n * - :host uses `all: initial` to block inherited styles\n * - All classes prefixed with sp- (defense in depth)\n * - CSS custom properties for theming\n * - No external fonts — system-ui stack (Inter if available)\n * - :focus-visible on all interactive elements\n * - prefers-reduced-motion support\n */\nexport function buildStyles(colors: ThemeColors): string {\n return `\n :host {\n all: initial;\n position: fixed;\n z-index: 2147483647;\n font-family: var(--sp-font);\n font-size: 14px;\n line-height: 1.5;\n color: var(--sp-text);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n ${cssVariables(colors)}\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* ============================\n Focus visible (accessibility)\n ============================ */\n\n :focus-visible {\n outline: 2px solid var(--sp-accent);\n outline-offset: 2px;\n }\n\n /* ============================\n FAB (Floating Action Button)\n ============================ */\n\n .sp-fab {\n position: fixed;\n width: 52px;\n height: 52px;\n border-radius: var(--sp-radius-full);\n background: var(--sp-accent-gradient);\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow:\n 0 4px 20px var(--sp-accent-glow),\n 0 2px 8px rgba(0, 0, 0, 0.08);\n transition:\n transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),\n box-shadow 0.3s ease;\n outline: none;\n }\n\n .sp-fab:focus-visible {\n outline: 2px solid #fff;\n outline-offset: 3px;\n }\n\n .sp-fab:hover {\n transform: translateY(-2px) scale(1.05);\n box-shadow:\n 0 8px 28px var(--sp-accent-glow),\n 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n\n .sp-fab:active {\n transform: translateY(0) scale(0.95);\n transition-duration: 0.1s;\n }\n\n .sp-fab--bottom-right {\n bottom: 24px;\n right: 24px;\n }\n\n .sp-fab--bottom-left {\n bottom: 24px;\n left: 24px;\n }\n\n .sp-fab svg {\n width: 22px;\n height: 22px;\n fill: currentColor;\n transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n /* ---- FAB Badge ---- */\n\n .sp-fab-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 20px;\n height: 20px;\n padding: 0 6px;\n border-radius: var(--sp-radius-full);\n background: #ef4444;\n color: #fff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid #fff;\n pointer-events: none;\n font-family: var(--sp-font);\n line-height: 1;\n }\n\n /* ============================\n Radial Menu\n ============================ */\n\n .sp-radial {\n position: fixed;\n pointer-events: none;\n width: 52px;\n height: 52px;\n }\n\n .sp-radial--bottom-right {\n bottom: 24px;\n right: 24px;\n }\n\n .sp-radial--bottom-left {\n bottom: 24px;\n left: 24px;\n }\n\n .sp-radial-item {\n position: absolute;\n left: 4px;\n bottom: 4px;\n width: 44px;\n height: 44px;\n border-radius: var(--sp-radius-full);\n background: var(--sp-glass-bg-heavy);\n backdrop-filter: blur(var(--sp-blur));\n -webkit-backdrop-filter: blur(var(--sp-blur));\n color: var(--sp-text);\n border: 1px solid var(--sp-glass-border);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: var(--sp-shadow-md);\n font-size: 12px;\n font-weight: 600;\n }\n\n .sp-radial-item:hover,\n .sp-radial-item:focus-visible {\n background: rgba(255, 255, 255, 0.95);\n border-color: var(--sp-accent);\n color: var(--sp-accent);\n box-shadow:\n var(--sp-shadow-md),\n 0 0 0 3px var(--sp-accent-light);\n outline: none;\n }\n\n .sp-radial-item svg {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n stroke: currentColor;\n fill: none;\n }\n\n .sp-radial-label {\n white-space: nowrap;\n font-size: 12px;\n font-weight: 500;\n color: var(--sp-text);\n pointer-events: none;\n opacity: 0;\n padding: 4px 12px;\n border-radius: var(--sp-radius);\n background: var(--sp-glass-bg-heavy);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid var(--sp-glass-border);\n box-shadow: var(--sp-shadow-sm);\n transform: translateX(4px);\n transition: opacity 0.2s ease, transform 0.2s ease;\n }\n\n .sp-radial-item:hover .sp-radial-label,\n .sp-radial-item:focus-visible .sp-radial-label {\n opacity: 1;\n transform: translateX(0);\n }\n\n /* ============================\n Panel (Side drawer)\n ============================ */\n\n .sp-panel {\n position: fixed;\n top: 0;\n right: 0;\n width: 400px;\n max-width: 100vw;\n height: 100vh;\n background: var(--sp-glass-bg);\n backdrop-filter: blur(var(--sp-blur-heavy));\n -webkit-backdrop-filter: blur(var(--sp-blur-heavy));\n border-left: 1px solid var(--sp-glass-border);\n box-shadow: var(--sp-shadow-xl);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n @media (max-width: 480px) {\n .sp-panel {\n width: 100vw;\n border-left: none;\n }\n }\n\n .sp-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n border-bottom: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n backdrop-filter: blur(var(--sp-blur));\n -webkit-backdrop-filter: blur(var(--sp-blur));\n }\n\n .sp-panel-title {\n font-size: 17px;\n font-weight: 700;\n color: var(--sp-text);\n letter-spacing: -0.02em;\n }\n\n .sp-panel-close {\n width: 32px;\n height: 32px;\n border-radius: var(--sp-radius);\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--sp-text-tertiary);\n transition: all 0.2s ease;\n }\n\n .sp-panel-close:hover {\n background: var(--sp-bg-hover);\n color: var(--sp-text);\n }\n\n .sp-panel-close svg {\n width: 16px;\n height: 16px;\n }\n\n /* ============================\n Filters & Search\n ============================ */\n\n .sp-filters {\n padding: 16px 24px;\n border-bottom: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n backdrop-filter: blur(var(--sp-blur));\n -webkit-backdrop-filter: blur(var(--sp-blur));\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n .sp-search-wrap {\n position: relative;\n margin-bottom: 12px;\n }\n\n .sp-search {\n width: 100%;\n height: 40px;\n padding: 0 12px 0 38px;\n border-radius: var(--sp-radius);\n border: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n color: var(--sp-text);\n font-family: var(--sp-font);\n font-size: 13px;\n outline: none;\n transition: all 0.2s ease;\n }\n\n .sp-search::placeholder {\n color: var(--sp-text-tertiary);\n }\n\n .sp-search:focus {\n border-color: var(--sp-accent);\n box-shadow: 0 0 0 3px var(--sp-accent-light);\n background: #fff;\n }\n\n .sp-search-icon {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--sp-text-tertiary);\n width: 16px;\n height: 16px;\n transition: color 0.2s ease;\n }\n\n .sp-search:focus ~ .sp-search-icon,\n .sp-search-wrap:focus-within .sp-search-icon {\n color: var(--sp-accent);\n }\n\n .sp-chips {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n }\n\n .sp-chip {\n padding: 5px 14px;\n border-radius: var(--sp-radius-full);\n border: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n color: var(--sp-text-secondary);\n font-family: var(--sp-font);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n white-space: nowrap;\n letter-spacing: 0.01em;\n }\n\n .sp-chip:hover {\n border-color: var(--sp-accent);\n color: var(--sp-accent);\n background: var(--sp-accent-light);\n }\n\n .sp-chip--active {\n background: var(--sp-accent-gradient);\n border-color: transparent;\n color: #fff;\n box-shadow: 0 2px 8px var(--sp-accent-glow);\n }\n\n .sp-chip--active:hover {\n background: var(--sp-accent-gradient);\n border-color: transparent;\n color: #fff;\n }\n\n /* ============================\n Feedback Cards\n ============================ */\n\n .sp-list {\n flex: 1;\n overflow-y: auto;\n padding: 8px 12px;\n }\n\n .sp-list::-webkit-scrollbar {\n width: 6px;\n }\n\n .sp-list::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .sp-list::-webkit-scrollbar-thumb {\n background: var(--sp-border);\n border-radius: var(--sp-radius-full);\n }\n\n .sp-list::-webkit-scrollbar-thumb:hover {\n background: var(--sp-text-tertiary);\n }\n\n .sp-card {\n display: flex;\n padding: 14px 16px;\n margin-bottom: 6px;\n cursor: pointer;\n border-radius: var(--sp-radius);\n background: var(--sp-glass-bg-heavy);\n border: 1px solid var(--sp-glass-border);\n transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .sp-card:hover {\n background: #fff;\n border-color: var(--sp-border);\n box-shadow: var(--sp-shadow-md);\n transform: translateY(-2px);\n }\n\n .sp-card:active {\n transform: translateY(0) scale(0.99);\n transition-duration: 0.1s;\n }\n\n .sp-card-bar {\n width: 3px;\n border-radius: var(--sp-radius-full);\n margin-right: 14px;\n flex-shrink: 0;\n }\n\n .sp-card-body {\n flex: 1;\n min-width: 0;\n }\n\n .sp-card-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n }\n\n .sp-card-number {\n font-size: 12px;\n font-weight: 700;\n color: var(--sp-text-tertiary);\n font-variant-numeric: tabular-nums;\n }\n\n .sp-badge {\n padding: 2px 10px;\n border-radius: var(--sp-radius-full);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n }\n\n .sp-card-date {\n font-size: 11px;\n color: var(--sp-text-tertiary);\n margin-left: auto;\n }\n\n .sp-card-message {\n font-size: 13px;\n line-height: 1.5;\n color: var(--sp-text);\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .sp-card-message--expanded {\n -webkit-line-clamp: unset;\n }\n\n .sp-card-expand {\n font-size: 12px;\n font-weight: 500;\n color: var(--sp-accent);\n cursor: pointer;\n background: none;\n border: none;\n padding: 4px 0;\n font-family: var(--sp-font);\n transition: opacity 0.15s ease;\n }\n\n .sp-card-expand:hover {\n opacity: 0.8;\n }\n\n .sp-card-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 6px;\n margin-top: 10px;\n }\n\n .sp-btn-resolve,\n .sp-btn-delete {\n padding: 5px 14px;\n border-radius: var(--sp-radius-full);\n border: 1px solid var(--sp-border);\n background: transparent;\n color: var(--sp-text-secondary);\n font-family: var(--sp-font);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n transition: all 0.2s ease;\n }\n\n .sp-btn-resolve svg,\n .sp-btn-delete svg {\n width: 14px;\n height: 14px;\n }\n\n .sp-btn-resolve:hover {\n border-color: #22c55e;\n color: #22c55e;\n background: rgba(34, 197, 94, 0.06);\n }\n\n .sp-btn-delete:hover {\n border-color: #ef4444;\n color: #ef4444;\n background: rgba(239, 68, 68, 0.06);\n }\n\n .sp-btn-resolve:disabled,\n .sp-btn-delete:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n /* ---- Delete All (header) ---- */\n\n .sp-panel-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .sp-btn-delete-all {\n padding: 5px 12px;\n border-radius: var(--sp-radius-full);\n border: 1px solid var(--sp-border);\n background: transparent;\n color: var(--sp-text-tertiary);\n font-family: var(--sp-font);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n transition: all 0.2s ease;\n }\n\n .sp-btn-delete-all svg {\n width: 13px;\n height: 13px;\n }\n\n .sp-btn-delete-all:hover {\n border-color: #ef4444;\n color: #ef4444;\n background: rgba(239, 68, 68, 0.06);\n }\n\n .sp-btn-delete-all:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n }\n\n /* ---- Confirm Dialog ---- */\n\n .sp-confirm-backdrop {\n position: fixed;\n inset: 0;\n background: var(--sp-backdrop, rgba(15, 23, 42, 0.2));\n backdrop-filter: blur(var(--sp-blur));\n -webkit-backdrop-filter: blur(var(--sp-blur));\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 2147483647;\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n\n .sp-confirm-dialog {\n width: 340px;\n padding: 28px;\n border-radius: 20px;\n background: var(--sp-glass-bg-heavy);\n backdrop-filter: blur(var(--sp-blur-heavy));\n -webkit-backdrop-filter: blur(var(--sp-blur-heavy));\n border: 1px solid var(--sp-glass-border);\n box-shadow: var(--sp-shadow-xl);\n font-family: var(--sp-font);\n transform: translateY(8px) scale(0.97);\n transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n .sp-confirm-title {\n font-size: 17px;\n font-weight: 700;\n color: var(--sp-text);\n letter-spacing: -0.02em;\n margin-bottom: 8px;\n }\n\n .sp-confirm-message {\n font-size: 14px;\n color: var(--sp-text-secondary);\n line-height: 1.5;\n margin-bottom: 20px;\n }\n\n .sp-confirm-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .sp-btn-danger {\n height: 40px;\n padding: 0 22px;\n border-radius: var(--sp-radius);\n border: none;\n background: #ef4444;\n color: #fff;\n font-family: var(--sp-font);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(239, 68, 68, 0.25);\n }\n\n .sp-btn-danger:hover {\n background: #dc2626;\n box-shadow: 0 4px 16px rgba(239, 68, 68, 0.3);\n transform: translateY(-1px);\n }\n\n .sp-btn-danger:active {\n transform: translateY(0) scale(0.98);\n transition-duration: 0.1s;\n }\n\n .sp-card--resolved {\n opacity: 0.5;\n }\n\n .sp-card--resolved .sp-card-message {\n text-decoration: line-through;\n text-decoration-color: var(--sp-text-tertiary);\n }\n\n /* ============================\n Loading State\n ============================ */\n\n .sp-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n }\n\n /* ============================\n Identity Form\n ============================ */\n\n .sp-identity-title {\n font-size: 17px;\n font-weight: 700;\n color: var(--sp-text);\n letter-spacing: -0.02em;\n }\n\n .sp-input {\n width: 100%;\n height: 42px;\n padding: 0 14px;\n border-radius: var(--sp-radius);\n border: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n color: var(--sp-text);\n font-family: var(--sp-font);\n font-size: 14px;\n outline: none;\n transition: all 0.2s ease;\n }\n\n .sp-input::placeholder {\n color: var(--sp-text-tertiary);\n }\n\n .sp-input:focus {\n border-color: var(--sp-accent);\n box-shadow: 0 0 0 3px var(--sp-accent-light);\n background: #fff;\n }\n\n .sp-input-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--sp-text-secondary);\n margin-bottom: 6px;\n display: block;\n }\n\n /* ============================\n Buttons\n ============================ */\n\n .sp-btn-primary {\n height: 40px;\n padding: 0 22px;\n border-radius: var(--sp-radius);\n border: none;\n background: var(--sp-accent-gradient);\n color: #fff;\n font-family: var(--sp-font);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px var(--sp-accent-glow);\n }\n\n .sp-btn-primary:hover {\n box-shadow: 0 4px 16px var(--sp-accent-glow);\n transform: translateY(-1px);\n }\n\n .sp-btn-primary:active {\n transform: translateY(0) scale(0.98);\n transition-duration: 0.1s;\n }\n\n .sp-btn-primary:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n }\n\n .sp-btn-ghost {\n height: 40px;\n padding: 0 22px;\n border-radius: var(--sp-radius);\n border: 1px solid var(--sp-border);\n background: var(--sp-glass-bg-heavy);\n color: var(--sp-text-secondary);\n font-family: var(--sp-font);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .sp-btn-ghost:hover {\n border-color: var(--sp-accent);\n color: var(--sp-accent);\n background: var(--sp-accent-light);\n }\n\n /* ============================\n Empty State\n ============================ */\n\n .sp-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 56px 24px;\n color: var(--sp-text-tertiary);\n text-align: center;\n gap: 8px;\n animation: sp-fade-in 0.3s ease-out both;\n }\n\n .sp-empty-text {\n font-size: 14px;\n font-weight: 500;\n }\n\n ${ANIMATION_CSS}\n `;\n}\n","import type { FeedbackResponse } from \"@siteping/core\";\nimport { el, formatRelativeDate, setText } from \"./dom-utils.js\";\nimport { getTypeBgColor, getTypeColor, type ThemeColors } from \"./styles/theme.js\";\n\nconst SHOW_DELAY = 120;\nconst HIDE_DELAY = 80;\n\n/**\n * Tooltip shown on annotation marker hover.\n *\n * Glassmorphism design: frosted glass with pastel badge,\n * smooth entrance animation, directional arrow.\n * Lives outside Shadow DOM.\n */\nexport class Tooltip {\n private root: HTMLElement;\n private arrow: HTMLElement;\n private showTimer: ReturnType<typeof setTimeout> | null = null;\n private hideTimer: ReturnType<typeof setTimeout> | null = null;\n private currentFeedbackId: string | null = null;\n\n constructor(private readonly colors: ThemeColors) {\n this.root = el(\"div\", {\n style: `\n position: fixed;\n z-index: 2147483647;\n max-width: 280px;\n padding: 12px 14px;\n border-radius: 14px;\n background: rgba(255, 255, 255, 0.88);\n backdrop-filter: blur(24px);\n -webkit-backdrop-filter: blur(24px);\n border: 1px solid rgba(255, 255, 255, 0.35);\n box-shadow: 0 8px 32px rgba(0,0,0,0.1), 0 2px 8px rgba(0,0,0,0.04);\n font-family: \"Inter\", system-ui, -apple-system, sans-serif;\n pointer-events: auto;\n opacity: 0;\n transform: translateY(6px) scale(0.97);\n transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1), transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n visibility: hidden;\n -webkit-font-smoothing: antialiased;\n `,\n });\n\n // Arrow element\n this.arrow = el(\"div\", {\n style: `\n position: absolute;\n width: 12px;\n height: 12px;\n background: rgba(255, 255, 255, 0.88);\n border: 1px solid rgba(255, 255, 255, 0.35);\n transform: rotate(45deg);\n pointer-events: none;\n `,\n });\n this.root.appendChild(this.arrow);\n\n this.root.addEventListener(\"mouseenter\", () => this.cancelHide());\n this.root.addEventListener(\"mouseleave\", () => this.scheduleHide());\n document.body.appendChild(this.root);\n }\n\n show(feedback: FeedbackResponse, anchorRect: DOMRect): void {\n if (this.currentFeedbackId === feedback.id) return;\n this.cancelHide();\n this.cancelShow();\n\n this.showTimer = setTimeout(() => {\n this.currentFeedbackId = feedback.id;\n this.render(feedback);\n this.position(anchorRect);\n this.root.style.visibility = \"visible\";\n this.root.style.opacity = \"1\";\n this.root.style.transform = \"translateY(0) scale(1)\";\n }, SHOW_DELAY);\n }\n\n scheduleHide(): void {\n this.cancelHide();\n this.hideTimer = setTimeout(() => this.hide(), HIDE_DELAY);\n }\n\n hide(): void {\n this.cancelShow();\n this.currentFeedbackId = null;\n this.root.style.opacity = \"0\";\n this.root.style.transform = \"translateY(6px) scale(0.97)\";\n setTimeout(() => {\n if (!this.currentFeedbackId) {\n this.root.style.visibility = \"hidden\";\n }\n }, 200);\n }\n\n private cancelShow(): void {\n if (this.showTimer) {\n clearTimeout(this.showTimer);\n this.showTimer = null;\n }\n }\n\n private cancelHide(): void {\n if (this.hideTimer) {\n clearTimeout(this.hideTimer);\n this.hideTimer = null;\n }\n }\n\n private render(feedback: FeedbackResponse): void {\n // Clear previous content safely (except arrow)\n const children = Array.from(this.root.children);\n for (const child of children) {\n if (child !== this.arrow) child.remove();\n }\n\n const typeColor = getTypeColor(feedback.type, this.colors);\n const typeBg = getTypeBgColor(feedback.type, this.colors);\n const typeLabel = feedback.type.charAt(0).toUpperCase() + feedback.type.slice(1);\n\n // Header row: badge + date\n const header = el(\"div\", { style: \"display:flex;align-items:center;gap:8px;margin-bottom:8px;\" });\n\n const badge = el(\"span\", {\n style: `\n padding:3px 10px;border-radius:9999px;\n font-size:11px;font-weight:600;\n color:${typeColor};background:${typeBg};\n letter-spacing:0.02em;\n `,\n });\n setText(badge, typeLabel);\n\n const date = el(\"span\", { style: \"font-size:11px;color:#64748b;margin-left:auto;\" });\n setText(date, formatRelativeDate(feedback.createdAt));\n\n header.appendChild(badge);\n header.appendChild(date);\n\n // Message body (safe — textContent only)\n const body = el(\"div\", {\n style:\n \"font-size:13px;line-height:1.55;color:#0f172a;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;\",\n });\n setText(body, feedback.message);\n\n // Insert content before arrow\n this.root.insertBefore(header, this.arrow);\n this.root.insertBefore(body, this.arrow);\n }\n\n private position(anchorRect: DOMRect): void {\n const tooltipRect = this.root.getBoundingClientRect();\n const gap = 10;\n\n let top = anchorRect.top - tooltipRect.height - gap;\n let left = anchorRect.left + anchorRect.width / 2 - tooltipRect.width / 2;\n let isAbove = true;\n\n // Flip below if not enough space above\n if (top < 8) {\n top = anchorRect.bottom + gap;\n isAbove = false;\n }\n\n left = Math.max(8, Math.min(left, window.innerWidth - tooltipRect.width - 8));\n\n this.root.style.top = `${top}px`;\n this.root.style.left = `${left}px`;\n\n // Position arrow\n const arrowLeft = Math.max(16, Math.min(anchorRect.left + anchorRect.width / 2 - left - 6, tooltipRect.width - 22));\n\n if (isAbove) {\n // Arrow at bottom, pointing down\n this.arrow.style.cssText = `\n position:absolute;\n width:12px;height:12px;\n background:rgba(255, 255, 255, 0.88);\n border-right:1px solid rgba(255, 255, 255, 0.35);\n border-bottom:1px solid rgba(255, 255, 255, 0.35);\n transform:rotate(45deg);\n pointer-events:none;\n bottom:-6px;\n left:${arrowLeft}px;\n `;\n } else {\n // Arrow at top, pointing up\n this.arrow.style.cssText = `\n position:absolute;\n width:12px;height:12px;\n background:rgba(255, 255, 255, 0.88);\n border-left:1px solid rgba(255, 255, 255, 0.35);\n border-top:1px solid rgba(255, 255, 255, 0.35);\n transform:rotate(45deg);\n pointer-events:none;\n top:-6px;\n left:${arrowLeft}px;\n `;\n }\n }\n\n /** Check if a DOM node belongs to this tooltip (for MutationObserver filtering). */\n contains(node: Node): boolean {\n return this.root.contains(node);\n }\n\n destroy(): void {\n this.cancelShow();\n this.cancelHide();\n this.root.remove();\n }\n}\n","import type { FeedbackPayload, SitepingConfig, SitepingInstance } from \"@siteping/core\";\nimport { Annotator } from \"./annotator.js\";\nimport { ApiClient, flushRetryQueue } from \"./api-client.js\";\nimport { EventBus, type WidgetEvents } from \"./events.js\";\nimport { Fab } from \"./fab.js\";\nimport { getIdentity, type Identity, saveIdentity } from \"./identity.js\";\nimport { MarkerManager } from \"./markers.js\";\nimport { Panel } from \"./panel.js\";\nimport { buildStyles } from \"./styles/base.js\";\nimport { buildThemeColors } from \"./styles/theme.js\";\nimport { Tooltip } from \"./tooltip.js\";\n\n/**\n * Main widget launcher — orchestrates all components.\n *\n * Architecture:\n * - Creates a <siteping-widget> custom element in the document\n * - Attaches a closed Shadow DOM for CSS isolation\n * - FAB + Panel live inside the Shadow DOM\n * - Overlay, markers, tooltips live outside (appended to document.body)\n */\nexport function launch(config: SitepingConfig): SitepingInstance {\n // Guard: only show in development (forceShow bypasses)\n if (!config.forceShow) {\n try {\n const meta = import.meta as unknown as { env?: { MODE?: string } };\n const proc = (globalThis as unknown as { process?: { env?: { NODE_ENV?: string } } }).process;\n const mode = meta.env?.MODE ?? proc?.env?.NODE_ENV;\n if (mode === \"production\") {\n return { destroy: () => {} };\n }\n } catch {\n // import.meta access may throw in non-ESM contexts — ignore\n }\n }\n\n // Guard: desktop only (< 768px = hidden)\n if (window.innerWidth < 768) {\n return { destroy: () => {} };\n }\n\n const colors = buildThemeColors(config.accentColor);\n const bus = new EventBus<WidgetEvents>();\n const apiClient = new ApiClient(config.endpoint);\n\n // Wire config callbacks to event bus\n if (config.onOpen) bus.on(\"open\", config.onOpen);\n if (config.onClose) bus.on(\"close\", config.onClose);\n if (config.onFeedbackSent) bus.on(\"feedback:sent\", config.onFeedbackSent);\n if (config.onError) bus.on(\"feedback:error\", config.onError);\n if (config.onAnnotationStart) bus.on(\"annotation:start\", config.onAnnotationStart);\n if (config.onAnnotationEnd) bus.on(\"annotation:end\", config.onAnnotationEnd);\n\n // Create host element + Shadow DOM\n const host = document.createElement(\"siteping-widget\");\n host.style.cssText = \"position:fixed;z-index:2147483647;\";\n // Use open mode only for testing — closed in production for CSS isolation\n const shadowMode = (config as unknown as Record<string, unknown>).__testMode\n ? (\"open\" as const)\n : (\"closed\" as const);\n const shadow = host.attachShadow({ mode: shadowMode });\n\n // Inject styles into Shadow DOM via adoptedStyleSheets\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(buildStyles(colors));\n shadow.adoptedStyleSheets = [sheet];\n\n document.body.appendChild(host);\n\n // Components outside Shadow DOM\n const tooltip = new Tooltip(colors);\n const markers = new MarkerManager(colors, tooltip, bus);\n\n // Components inside Shadow DOM\n const fab = new Fab(shadow, config, bus);\n const panel = new Panel(shadow, colors, bus, apiClient, config.projectName, markers);\n const annotator = new Annotator(config, colors, bus);\n\n // Handle annotation completion via event bus (not DOM events)\n const unsubAnnotation = bus.on(\"annotation:complete\", async (data) => {\n const { annotation, type, message } = data;\n\n // Ensure identity\n let identity = getIdentity();\n if (!identity) {\n identity = await promptIdentity(shadow);\n if (!identity) return; // User cancelled\n saveIdentity(identity);\n }\n\n const payload: FeedbackPayload = {\n projectName: config.projectName,\n type,\n message,\n url: window.location.href,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n authorName: identity.name,\n authorEmail: identity.email,\n annotations: [annotation],\n clientId: crypto.randomUUID(),\n };\n\n try {\n const response = await apiClient.sendFeedback(payload);\n bus.emit(\"feedback:sent\", response);\n markers.addFeedback(response, markers.count + 1);\n await panel.refresh();\n } catch (error) {\n bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n // Load markers immediately on page load\n apiClient\n .getFeedbacks(config.projectName, { limit: 50 })\n .then(({ feedbacks }) => {\n markers.render(feedbacks);\n })\n .catch(() => {\n // Silently fail — markers will load when panel opens\n });\n\n // Flush retry queue on load\n flushRetryQueue(config.endpoint);\n\n return {\n destroy: () => {\n unsubAnnotation();\n fab.destroy();\n panel.destroy();\n annotator.destroy();\n markers.destroy();\n tooltip.destroy();\n bus.removeAll();\n host.remove();\n },\n };\n}\n\n/**\n * Show a modal identity form inside the Shadow DOM.\n * Glassmorphism: frosted backdrop, glass modal, gradient CTA.\n * Returns null if the user cancels.\n */\nfunction promptIdentity(shadowRoot: ShadowRoot): Promise<Identity | null> {\n return new Promise((resolve) => {\n const backdrop = document.createElement(\"div\");\n backdrop.style.cssText = `\n position:fixed;inset:0;\n background:rgba(15, 23, 42, 0.2);\n backdrop-filter:blur(8px);\n -webkit-backdrop-filter:blur(8px);\n display:flex;align-items:center;justify-content:center;\n z-index:2147483647;\n opacity:0;transition:opacity 0.25s ease;\n `;\n\n const modal = document.createElement(\"div\");\n modal.style.cssText = `\n width:340px;padding:28px;border-radius:20px;\n background:rgba(255, 255, 255, 0.85);\n backdrop-filter:blur(32px);\n -webkit-backdrop-filter:blur(32px);\n border:1px solid rgba(255, 255, 255, 0.35);\n box-shadow:0 16px 48px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.06);\n font-family:\"Inter\",system-ui,-apple-system,sans-serif;\n transform:translateY(12px) scale(0.97);\n transition:transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n -webkit-font-smoothing:antialiased;\n `;\n\n const title = document.createElement(\"div\");\n title.className = \"sp-identity-title\";\n title.textContent = \"Identifiez-vous\";\n title.style.marginBottom = \"20px\";\n\n const nameLabel = document.createElement(\"label\");\n nameLabel.className = \"sp-input-label\";\n nameLabel.textContent = \"Nom\";\n const nameInput = document.createElement(\"input\");\n nameInput.className = \"sp-input\";\n nameInput.type = \"text\";\n nameInput.placeholder = \"Votre nom\";\n nameInput.style.marginBottom = \"14px\";\n\n const emailLabel = document.createElement(\"label\");\n emailLabel.className = \"sp-input-label\";\n emailLabel.textContent = \"Email\";\n const emailInput = document.createElement(\"input\");\n emailInput.className = \"sp-input\";\n emailInput.type = \"email\";\n emailInput.placeholder = \"votre@email.com\";\n\n const btnRow = document.createElement(\"div\");\n btnRow.style.cssText = \"display:flex;gap:8px;justify-content:flex-end;margin-top:20px;\";\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.className = \"sp-btn-ghost\";\n cancelBtn.textContent = \"Annuler\";\n cancelBtn.addEventListener(\"click\", () => {\n backdrop.style.opacity = \"0\";\n modal.style.transform = \"translateY(12px) scale(0.97)\";\n setTimeout(() => {\n backdrop.remove();\n resolve(null);\n }, 250);\n });\n\n const submitBtn = document.createElement(\"button\");\n submitBtn.className = \"sp-btn-primary\";\n submitBtn.textContent = \"Continuer\";\n submitBtn.addEventListener(\"click\", () => {\n const name = nameInput.value.trim();\n const email = emailInput.value.trim();\n if (!name || !email) return;\n backdrop.style.opacity = \"0\";\n modal.style.transform = \"translateY(12px) scale(0.97)\";\n setTimeout(() => {\n backdrop.remove();\n resolve({ name, email });\n }, 250);\n });\n\n btnRow.appendChild(cancelBtn);\n btnRow.appendChild(submitBtn);\n\n modal.appendChild(title);\n modal.appendChild(nameLabel);\n modal.appendChild(nameInput);\n modal.appendChild(emailLabel);\n modal.appendChild(emailInput);\n modal.appendChild(btnRow);\n backdrop.appendChild(modal);\n\n shadowRoot.appendChild(backdrop);\n\n // Animate in\n requestAnimationFrame(() => {\n backdrop.style.opacity = \"1\";\n modal.style.transform = \"translateY(0) scale(1)\";\n nameInput.focus();\n });\n });\n}\n","import type { SitepingConfig, SitepingInstance } from \"@siteping/core\";\nimport { launch } from \"./launcher.js\";\n\nexport type {\n AnchorData,\n AnnotationPayload,\n AnnotationResponse,\n FeedbackPayload,\n FeedbackResponse,\n FeedbackStatus,\n FeedbackType,\n RectData,\n SitepingConfig,\n SitepingInstance,\n} from \"@siteping/core\";\n\n/**\n * Initialize the Siteping feedback widget.\n *\n * @example\n * ```ts\n * import { initSiteping } from '@siteping/widget'\n *\n * const { destroy } = initSiteping({\n * endpoint: '/api/siteping',\n * projectName: 'my-project',\n * })\n * ```\n */\nexport function initSiteping(config: SitepingConfig): SitepingInstance {\n return launch(config);\n}\n"],"mappings":";AAGA,IAAI;AACJ,IAAI;AACJ,IAAI;AACG,SAAS,OAAO,OAAO,SAAS;AACnC,UAAQ,oBAAI,KAAK;AACjB,MAAI,MAAM,aAAa,KAAK,cAAc;AACtC,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC5E;AACA,MAAI,WAAW,MAAM,QAAQ,YAAY,GAAG;AACxC,WAAO;AAAA,EACX;AACA,QAAM,WAAW;AAAA,IACb,MAAM,SAAS;AAAA,IACf,QAAQ,CAAC,SAAS;AAAA,IAClB,WAAW,CAAC,SAAS;AAAA,IACrB,SAAS,CAAC,SAAS;AAAA,IACnB,MAAM,CAAC,MAAM,UAAU;AAAA,IACvB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,WAAW;AAAA,EACf;AACA,WAAS,EAAE,GAAG,UAAU,GAAG,QAAQ;AACnC,iBAAe,iBAAiB,OAAO,MAAM,QAAQ;AACrD,MAAI,OAAO,eAAe,OAAO,OAAO,MAAM,eAAe,OAAO,OAAO,MAAM,eAAe,OAAO,OAAO,MAAM,eAAe,OAAO,MAAM,CAAC,CAAC,CAAC;AACnJ,MAAI,MAAM;AACN,UAAM,YAAY,KAAK,SAAS,MAAM,KAAK,CAAC;AAC5C,QAAI,UAAU,SAAS,GAAG;AACtB,aAAO,UAAU,CAAC;AAAA,IACtB;AACA,WAAO,SAAS,IAAI;AAAA,EACxB,OACK;AACD,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC7C;AACJ;AACA,SAAS,iBAAiB,UAAU,UAAU;AAC1C,MAAI,SAAS,aAAa,KAAK,eAAe;AAC1C,WAAO;AAAA,EACX;AACA,MAAI,aAAa,SAAS,MAAM;AAC5B,WAAO,SAAS;AAAA,EACpB;AACA,SAAO;AACX;AACA,SAAS,eAAe,OAAO,OAAO,UAAU;AAC5C,MAAI,OAAO;AACX,MAAI,QAAQ,CAAC;AACb,MAAI,UAAU;AACd,MAAI,IAAI;AACR,SAAO,SAAS;AACZ,UAAM,eAAc,oBAAI,KAAK,GAAE,QAAQ,IAAI,MAAM,QAAQ;AACzD,QAAI,OAAO,cAAc,UAAa,cAAc,OAAO,WAAW;AAClE,YAAM,IAAI,MAAM,+CAA+C,WAAW,IAAI;AAAA,IAClF;AACA,QAAI,QAAQ,MAAM,GAAG,OAAO,CAAC,KACzB,MAAM,GAAG,KAAK,OAAO,CAAC,KACtB,MAAM,GAAG,WAAW,OAAO,CAAC,KAC5B,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;AACrC,UAAM,MAAM,MAAM,OAAO;AACzB,QAAI,SAAS,OAAO;AAChB,UAAI,KAAK;AACL,gBAAQ,MAAM,OAAO,MAAM,OAAO,cAAc,EAAE,IAAI,CAAC,SAAS,SAAS,MAAM,GAAG,CAAC,CAAC;AAAA,MACxF;AAAA,IACJ,WACS,SAAS,OAAO;AACrB,cAAQ,MAAM,MAAM,GAAG,CAAC;AACxB,UAAI,KAAK;AACL,gBAAQ,MAAM,OAAO,MAAM,OAAO,cAAc,EAAE,IAAI,CAAC,SAAS,SAAS,MAAM,GAAG,CAAC,CAAC;AAAA,MACxF;AAAA,IACJ,WACS,SAAS,OAAO;AACrB,YAAM,CAAC,IAAI,IAAK,QAAQ,MAAM,MAAM,GAAG,CAAC;AACxC,UAAI,OAAO,eAAe,IAAI,GAAG;AAC7B,gBAAQ,CAAC,SAAS,MAAM,GAAG,CAAC;AAAA,MAChC;AAAA,IACJ,WACS,SAAS,QAAQ;AACtB,cAAQ,CAAC,IAAI,CAAC;AACd,UAAI,KAAK;AACL,gBAAQ,CAAC,SAAS,MAAM,CAAC,GAAG,GAAG,CAAC;AAAA,MACpC;AAAA,IACJ;AACA,aAAS,QAAQ,OAAO;AACpB,WAAK,QAAQ;AAAA,IACjB;AACA,UAAM,KAAK,KAAK;AAChB,QAAI,MAAM,UAAU,OAAO,eAAe;AACtC,aAAO,eAAe,OAAO,QAAQ;AACrC,UAAI,MAAM;AACN;AAAA,MACJ;AAAA,IACJ;AACA,cAAU,QAAQ;AAClB;AAAA,EACJ;AACA,MAAI,CAAC,MAAM;AACP,WAAO,eAAe,OAAO,QAAQ;AAAA,EACzC;AACA,MAAI,CAAC,QAAQ,UAAU;AACnB,WAAO,SAAS;AAAA,EACpB;AACA,SAAO;AACX;AACA,SAAS,eAAe,OAAO,UAAU;AACrC,QAAM,QAAQ,KAAK,aAAa,KAAK,CAAC;AACtC,MAAI,MAAM,SAAS,OAAO,WAAW;AACjC,WAAO,WAAW,SAAS,IAAI;AAAA,EACnC;AACA,WAAS,aAAa,OAAO;AACzB,QAAI,OAAO,SAAS,GAAG;AACnB,aAAO;AAAA,IACX;AAAA,EACJ;AACA,SAAO;AACX;AACA,SAAS,SAAS,MAAM;AACpB,MAAI,OAAO,KAAK,CAAC;AACjB,MAAI,QAAQ,KAAK;AACjB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAClC,UAAM,QAAQ,KAAK,CAAC,EAAE,SAAS;AAC/B,QAAI,KAAK,UAAU,QAAQ,GAAG;AAC1B,cAAQ,GAAG,KAAK,CAAC,EAAE,IAAI,MAAM,KAAK;AAAA,IACtC,OACK;AACD,cAAQ,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,KAAK;AAAA,IACpC;AACA,WAAO,KAAK,CAAC;AAAA,EACjB;AACA,SAAO;AACX;AACA,SAAS,QAAQ,MAAM;AACnB,SAAO,KAAK,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,GAAG,CAAC;AACzE;AACA,SAAS,OAAO,MAAM;AAClB,QAAM,MAAM,SAAS,IAAI;AACzB,UAAQ,aAAa,iBAAiB,GAAG,EAAE,QAAQ;AAAA,IAC/C,KAAK;AACD,YAAM,IAAI,MAAM,6CAA6C,GAAG,EAAE;AAAA,IACtE,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;AACA,SAAS,GAAG,OAAO;AACf,QAAM,YAAY,MAAM,aAAa,IAAI;AACzC,MAAI,aAAa,OAAO,OAAO,SAAS,GAAG;AACvC,WAAO;AAAA,MACH,MAAM,MAAM,IAAI,OAAO,SAAS;AAAA,MAChC,SAAS;AAAA,IACb;AAAA,EACJ;AACA,SAAO;AACX;AACA,SAAS,KAAK,OAAO;AACjB,QAAM,QAAQ,MAAM,KAAK,MAAM,UAAU,EAAE,OAAO,CAACA,UAAS,OAAO,KAAKA,MAAK,MAAMA,MAAK,KAAK,CAAC;AAC9F,SAAO,MAAM,IAAI,CAACA,WAAU;AAAA,IACxB,MAAM,IAAI,IAAI,OAAOA,MAAK,IAAI,CAAC,KAAK,IAAI,OAAOA,MAAK,KAAK,CAAC;AAAA,IAC1D,SAAS;AAAA,EACb,EAAE;AACN;AACA,SAAS,WAAW,OAAO;AACvB,QAAM,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAE,OAAO,OAAO,SAAS;AACjE,SAAO,MAAM,IAAI,CAAC,UAAU;AAAA,IACxB,MAAM,MAAM,IAAI,OAAO,IAAI;AAAA,IAC3B,SAAS;AAAA,EACb,EAAE;AACN;AACA,SAAS,QAAQ,OAAO;AACpB,QAAM,OAAO,MAAM,QAAQ,YAAY;AACvC,MAAI,OAAO,QAAQ,IAAI,GAAG;AACtB,WAAO;AAAA,MACH;AAAA,MACA,SAAS;AAAA,IACb;AAAA,EACJ;AACA,SAAO;AACX;AACA,SAAS,MAAM;AACX,SAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS;AAAA,EACb;AACJ;AACA,SAAS,MAAM,OAAO;AAClB,QAAM,SAAS,MAAM;AACrB,MAAI,CAAC,QAAQ;AACT,WAAO;AAAA,EACX;AACA,MAAI,QAAQ,OAAO;AACnB,MAAI,CAAC,OAAO;AACR,WAAO;AAAA,EACX;AACA,MAAI,IAAI;AACR,SAAO,OAAO;AACV,QAAI,MAAM,aAAa,KAAK,cAAc;AACtC;AAAA,IACJ;AACA,QAAI,UAAU,OAAO;AACjB;AAAA,IACJ;AACA,YAAQ,MAAM;AAAA,EAClB;AACA,SAAO;AACX;AACA,SAAS,SAAS,MAAM,GAAG;AACvB,SAAO;AAAA,IACH,MAAM,KAAK,OAAO,cAAc,CAAC;AAAA,IACjC,SAAS,KAAK,UAAU;AAAA,EAC5B;AACJ;AACA,SAAS,eAAe,MAAM;AAC1B,SAAO,KAAK,SAAS,UAAU,CAAC,KAAK,KAAK,WAAW,GAAG;AAC5D;AACA,SAAS,SAAS,OAAO;AACrB,QAAM,OAAO,MAAM,OAAO,QAAQ;AAClC,MAAI,KAAK,SAAS,GAAG;AACjB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AACA,SAAS,SAAS,OAAO;AACrB,SAAO,UAAU,QAAQ,UAAU;AACvC;AACA,UAAU,aAAa,OAAO,OAAO,CAAC,GAAG;AACrC,MAAI,MAAM,SAAS,GAAG;AAClB,aAAS,QAAQ,MAAM,CAAC,GAAG;AACvB,aAAO,aAAa,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,CAAC;AAAA,IACvE;AAAA,EACJ,OACK;AACD,UAAM;AAAA,EACV;AACJ;AACA,SAAS,KAAK,OAAO;AACjB,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;AAC5D;AACA,UAAU,SAAS,MAAM,OAAO,QAAQ;AAAA,EACpC,SAAS;AAAA,EACT,SAAS,oBAAI,IAAI;AACrB,GAAG;AACC,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,OAAO,oBAAoB;AAC5D,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACtC,UAAI,MAAM,UAAU,OAAO,kBAAkB;AACzC;AAAA,MACJ;AACA,YAAM,WAAW;AACjB,YAAM,UAAU,CAAC,GAAG,IAAI;AACxB,cAAQ,OAAO,GAAG,CAAC;AACnB,YAAM,aAAa,SAAS,OAAO;AACnC,UAAI,MAAM,QAAQ,IAAI,UAAU,GAAG;AAC/B;AAAA,MACJ;AACA,UAAI,OAAO,OAAO,KAAK,KAAK,SAAS,KAAK,GAAG;AACzC,cAAM;AACN,cAAM,QAAQ,IAAI,YAAY,IAAI;AAClC,eAAO,SAAS,SAAS,OAAO,KAAK;AAAA,MACzC;AAAA,IACJ;AAAA,EACJ;AACJ;AACA,SAAS,KAAK,MAAM,OAAO;AACvB,SAAO,aAAa,cAAc,SAAS,IAAI,CAAC,MAAM;AAC1D;;;ACpQA,IAAM,eAAe,CAAC,QAAQ,cAAc,QAAQ,QAAQ,QAAQ,OAAO,eAAe,SAAS;AAGnG,SAAS,KAAK,KAAqB;AACjC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,YAAS,QAAQ,KAAK,OAAO,IAAI,WAAW,CAAC,IAAK;AAAA,EACpD;AACA,UAAQ,SAAS,GAAG,SAAS,EAAE;AACjC;AAYO,SAAS,oBAAoB,SAA0B;AAC5D,QAAM,aAAa,QAAQ,SAAS;AAGpC,MAAI,aAAa;AACjB,QAAM,SAAS,QAAQ;AACvB,MAAI,QAAQ;AACV,eAAW,SAAS,OAAO,UAAU;AACnC,UAAI,UAAU,QAAS;AACvB,UAAI,MAAM,YAAY,QAAQ,QAAS;AAAA,IACzC;AAAA,EACF;AAGA,QAAM,QAAkB,CAAC;AACzB,aAAWC,SAAQ,cAAc;AAC/B,UAAM,MAAM,QAAQ,aAAaA,KAAI;AACrC,QAAI,IAAK,OAAM,KAAK,GAAGA,KAAI,IAAI,GAAG,EAAE;AAAA,EACtC;AACA,QAAM,WAAW,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,IAAI;AAE5D,SAAO,GAAG,UAAU,IAAI,UAAU,IAAI,QAAQ;AAChD;AAWO,SAAS,iBAAiB,WAAoB,mBAAmC;AACtF,QAAM,QAAQ,kBAAkB,MAAM,GAAG;AACzC,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,CAAC,gBAAgB,cAAc,cAAc,IAAI;AACvD,QAAM,mBAAmB,OAAO,cAAc;AAC9C,QAAM,iBAAiB,OAAO,YAAY;AAC1C,MAAI,OAAO,MAAM,gBAAgB,KAAK,OAAO,MAAM,cAAc,EAAG,QAAO;AAE3E,QAAM,cAAc,oBAAoB,SAAS;AACjD,QAAM,CAAC,cAAc,YAAY,YAAY,IAAI,YAAY,MAAM,GAAG;AAEtE,MAAI,QAAQ;AAGZ,QAAM,YAAY,KAAK,IAAI,OAAO,YAAY,IAAI,gBAAgB;AAClE,MAAI,cAAc,EAAG,UAAS;AAAA,WACrB,aAAa,EAAG,UAAS;AAAA,WACzB,aAAa,EAAG,UAAS;AAGlC,QAAM,UAAU,KAAK,IAAI,OAAO,UAAU,IAAI,cAAc;AAC5D,MAAI,YAAY,EAAG,UAAS;AAAA,WACnB,YAAY,EAAG,UAAS;AAAA,WACxB,WAAW,EAAG,UAAS;AAGhC,MAAI,iBAAiB,eAAgB,UAAS;AAE9C,SAAO;AACT;;;ACnFO,SAAS,aAAa,SAAkB,WAAuC;AACpF,QAAM,OAAO,cAAc,WAAW,2BAA2B;AACjE,MAAI,UAA0B,QAAQ,IAAI;AAC1C,MAAI,WAAW;AAEf,SAAO,WAAW,WAAW,GAAG;AAC9B,UAAM,OAAO,QAAQ,aAAa,KAAK;AACvC,QAAI,MAAM;AACR,aAAO,cAAc,WAAW,KAAK,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE;AAAA,IACpE;AACA,cAAU,QAAQ,IAAI;AACtB;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,aAAa,SAA0B;AACrD,QAAM,OAAO,QAAQ,wBAAwB,aAAa,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK;AACjF,QAAM,OAAO,QAAQ,oBAAoB,aAAa,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK;AAC7E,SAAO,CAAC,MAAM,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK;AAChD;;;ACtBO,SAAS,cAAc,SAA0B;AACtD,MAAI,QAAQ,IAAI;AACd,UAAM,SAAS,QAAQ,GAAG,SAAS,GAAG,IAAI,WAAW,QAAQ,GAAG,QAAQ,MAAM,SAAW,CAAC,OAAO,IAAI,QAAQ,EAAE;AAC/G,WAAO,KAAK,QAAQ,SAAS,QAAQ,MAAM;AAAA,EAC7C;AAEA,QAAM,WAAqB,CAAC;AAC5B,MAAI,UAA0B;AAE9B,SAAO,WAAW,YAAY,SAAS,QAAQ,SAAS,SAAS,GAAG;AAClE,UAAM,MAAM,QAAQ;AACpB,UAAM,SAAyB,QAAQ;AAEvC,QAAI,QAAQ,IAAI;AACd,YAAM,SAAS,QAAQ,GAAG,SAAS,GAAG,IAClC,WAAW,QAAQ,GAAG,QAAQ,MAAM,SAAW,CAAC,OAChD,IAAI,QAAQ,EAAE;AAClB,eAAS,QAAQ,IAAI,GAAG,QAAQ,MAAM,GAAG;AACzC,aAAO,MAAM,SAAS,KAAK,EAAE;AAAA,IAC/B;AAGA,QAAI,WAAW;AACf,QAAI,QAAQ;AACV,iBAAW,WAAW,OAAO,UAAU;AACrC,YAAI,YAAY,QAAS;AACzB,YAAI,QAAQ,cAAc,IAAK;AAAA,MACjC;AAAA,IACF;AAEA,aAAS,QAAQ,IAAI,GAAG,IAAI,QAAQ,GAAG;AACvC,cAAU;AAAA,EACZ;AAEA,SAAO,eAAe,SAAS,KAAK,EAAE;AACxC;;;AC9BO,SAAS,eAAe,SAA8B;AAC3D,QAAM,cAAc,OAAO,SAAS;AAAA;AAAA,IAElC,WAAW,CAAC,SAAiB,CAAC,4BAA4B,KAAK,IAAI,KAAK,CAAC,+BAA+B,KAAK,IAAI;AAAA;AAAA,IAEjH,MAAM,CAAC,SAAiB,CAAC,eAAe,WAAW,QAAQ,YAAY,EAAE,SAAS,IAAI;AAAA;AAAA,IAEtF,QAAQ,CAAC,SAAiB,CAAC,KAAK,WAAW,QAAQ,KAAK,CAAC,cAAc,KAAK,IAAI;AAAA,IAChF,eAAe;AAAA,IACf,oBAAoB;AAAA,EACtB,CAAC;AAED,QAAM,QAAQ,cAAc,OAAO;AAEnC,QAAM,UAAU,QAAQ,aAAa,KAAK,KAAK;AAC/C,QAAM,cAAc,QAAQ,MAAM,GAAG,GAAG;AAExC,QAAM,aAAa,aAAa,SAAS,QAAQ;AACjD,QAAM,aAAa,aAAa,SAAS,OAAO;AAChD,QAAM,cAAc,oBAAoB,OAAO;AAC/C,QAAM,WAAW,aAAa,OAAO;AAErC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,YAAY,QAAQ;AAAA,IACpB,WAAW,QAAQ,MAAM;AAAA,EAC3B;AACF;AAMO,SAAS,kBAAkB,MAAe,OAAgB,SAAS,iBAA0B;AAClG,QAAM,UAAU,KAAK,IAAI,KAAK,QAAQ;AACtC,QAAM,UAAU,KAAK,IAAI,KAAK,SAAS;AAGvC,QAAM,kBAAkB,SAAS,iBAAiB,SAAS,OAAO;AAClE,MAAI,CAAC,mBAAmB,oBAAoB,KAAM,QAAO,SAAS;AAGlE,MAAI,YAAqB;AACzB,MAAI,UAA0B;AAE9B,SAAO,WAAW,YAAY,SAAS,MAAM;AAC3C,UAAM,SAAS,QAAQ,sBAAsB;AAC7C,QACE,OAAO,QAAQ,KAAK,KACpB,OAAO,OAAO,KAAK,KACnB,OAAO,SAAS,KAAK,IAAI,KAAK,SAC9B,OAAO,UAAU,KAAK,IAAI,KAAK,QAC/B;AACA,kBAAY;AACZ;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,MAAe,cAAiC;AAEhF,MAAI,aAAa,SAAS,KAAK,aAAa,UAAU,GAAG;AACvD,WAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,EAC9C;AACA,SAAO;AAAA,IACL,OAAO,KAAK,IAAI,aAAa,KAAK,aAAa;AAAA,IAC/C,OAAO,KAAK,IAAI,aAAa,KAAK,aAAa;AAAA,IAC/C,MAAM,KAAK,QAAQ,aAAa;AAAA,IAChC,MAAM,KAAK,SAAS,aAAa;AAAA,EACnC;AACF;;;ACrFO,SAAS,SAAS,WAAkC;AACzD,QAAM,QAAQ,SAAS,YAAY;AACnC,QAAM,WAAW,MAAM,yBAAyB,SAAS;AACzD,QAAM,MAAM,SAAS;AACrB,MAAI,CAAC,OAAO,IAAI,SAAS,YAAY,MAAM,OAAO;AAChD,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AACA,SAAO;AACT;AAGO,SAAS,GAAG,KAAa,OAA6C;AAC3E,QAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,MAAI,OAAO;AACT,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,UAAI,QAAQ,SAAS;AACnB,gBAAQ,YAAY;AAAA,MACtB,WAAW,QAAQ,SAAS;AAC1B,gBAAQ,MAAM,UAAU;AAAA,MAC1B,OAAO;AACL,gBAAQ,aAAa,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,QAAQ,SAAmC,MAAoB;AAC7E,UAAQ,cAAc;AACxB;AAGO,SAAS,mBAAmB,WAA2B;AAC5D,QAAM,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,QAAQ;AACtD,QAAM,UAAU,KAAK,MAAM,OAAO,GAAM;AACxC,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,GAAI,QAAO,UAAU,OAAO;AAC1C,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,GAAI,QAAO,UAAU,KAAK;AACtC,QAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,MAAI,OAAO,EAAG,QAAO,UAAU,IAAI;AACnC,SAAO,IAAI,KAAK,SAAS,EAAE,mBAAmB,OAAO;AACvD;;;ACrDO,IAAM,gBAAgB;AAEtB,IAAM,YAAY;AAElB,IAAM,gBAAgB;AAEtB,IAAM,WAAW;AAEjB,IAAM,eAAe;AAErB,IAAM,aAAa;AAEnB,IAAM,cAAc;AAEpB,IAAM,aAAa;AAEnB,IAAM,gBAAgB;AAEtB,IAAM,cAAc;AAEpB,IAAM,WAAW;AAEjB,IAAM,aAAa;AAEnB,IAAM,YAAY;AAElB,IAAM,aAAa;;;ACG1B,IAAM,iBAAiB;AACvB,IAAM,UAAU;AAChB,IAAM,UAAU;AAChB,IAAM,UAAU;AAGhB,SAAS,aAAa,OAAuB;AAC3C,MAAI,QAAQ,KAAK,KAAK,EAAG,QAAO;AAChC,QAAM,QAAQ,QAAQ,KAAK,KAAK,IAAI,MAAM,MAAM,OAAO,IAAI;AAC3D,MAAI,MAAO,QAAO,IAAI,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AACrF,MAAI,QAAQ,KAAK,KAAK,EAAG,QAAO,MAAM,MAAM,GAAG,CAAC;AAChD,SAAO;AACT;AAGA,SAAS,UAAU,KAAa,QAAwB;AACtD,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,OAAO,CAAC;AAC9E,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,OAAO,CAAC;AAC9E,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,OAAO,CAAC;AAC9E,SAAO,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAChH;AAEO,SAAS,iBAAiB,SAAiB,gBAA6B;AAC7E,QAAM,MAAM,aAAa,MAAM;AAC/B,QAAM,OAAO,UAAU,KAAK,IAAI;AAChC,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa,MAAM;AAAA;AAAA,IACnB,YAAY;AAAA,IACZ,YAAY,MAAM;AAAA;AAAA,IAClB,gBAAgB,2BAA2B,GAAG,KAAK,IAAI;AAAA,IACvD,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,MAAM;AAAA,IACN,eAAe;AAAA,IACf,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA;AAAA,IAER,SAAS;AAAA,IACT,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA;AAAA,IAEnB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IAEX,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AACF;AAEO,SAAS,aAAa,MAAc,QAA6B;AACtE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO;AAAA,IAChB,KAAK;AACH,aAAO,OAAO;AAAA,IAChB,KAAK;AACH,aAAO,OAAO;AAAA,IAChB;AACE,aAAO,OAAO;AAAA,EAClB;AACF;AAEO,SAAS,eAAe,MAAc,QAA6B;AACxE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO;AAAA,IAChB,KAAK;AACH,aAAO,OAAO;AAAA,IAChB,KAAK;AACH,aAAO,OAAO;AAAA,IAChB;AACE,aAAO,OAAO;AAAA,EAClB;AACF;AAEO,SAAS,aAAa,QAA6B;AACxD,SAAO;AAAA,mBACU,OAAO,MAAM;AAAA,yBACP,OAAO,WAAW;AAAA,wBACnB,OAAO,UAAU;AAAA,wBACjB,OAAO,UAAU;AAAA,4BACb,OAAO,cAAc;AAAA,eAClC,OAAO,EAAE;AAAA,qBACH,OAAO,OAAO;AAAA,iBAClB,OAAO,IAAI;AAAA,2BACD,OAAO,aAAa;AAAA,0BACrB,OAAO,YAAY;AAAA,mBAC1B,OAAO,MAAM;AAAA,mBACb,OAAO,MAAM;AAAA,qBACX,OAAO,OAAO;AAAA,2BACR,OAAO,YAAY;AAAA,yBACrB,OAAO,WAAW;AAAA,gCACX,OAAO,iBAAiB;AAAA,0BAC9B,OAAO,YAAY;AAAA,4BACjB,OAAO,cAAc;AAAA,qBAC5B,OAAO,OAAO;AAAA,uBACZ,OAAO,SAAS;AAAA,6BACV,OAAO,cAAc;AAAA,+BACnB,OAAO,gBAAgB;AAAA,wBAC9B,OAAO,SAAS;AAAA,0BACd,OAAO,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc5C;;;ACxIA,IAAM,eAA6B;AAAA,EACjC,EAAE,MAAM,YAAY,OAAO,YAAY,MAAM,cAAc;AAAA,EAC3D,EAAE,MAAM,cAAc,OAAO,cAAc,MAAM,YAAY;AAAA,EAC7D,EAAE,MAAM,OAAO,OAAO,OAAO,MAAM,SAAS;AAAA,EAC5C,EAAE,MAAM,SAAS,OAAO,SAAS,MAAM,WAAW;AACpD;AASO,IAAM,QAAN,MAAY;AAAA,EAOjB,YAA6B,QAAqB;AAArB;AAC3B,SAAK,OAAO,GAAG,OAAO;AAAA,MACpB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBT,CAAC;AAGD,UAAM,UAAU,GAAG,OAAO,EAAE,OAAO,yEAAyE,CAAC;AAC7G,eAAW,UAAU,cAAc;AACjC,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUpB,YAAM,OAAO,SAAS,OAAO,IAAI;AACjC,WAAK,aAAa,SAAS,uCAAuC;AAClE,UAAI,YAAY,IAAI;AACpB,YAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,cAAQ,WAAW,OAAO,KAAK;AAC/B,UAAI,YAAY,SAAS;AACzB,UAAI,QAAQ,OAAO,OAAO;AAE1B,UAAI,iBAAiB,SAAS,MAAM;AAClC,aAAK,WAAW,OAAO,MAAM,OAAO;AAAA,MACtC,CAAC;AAED,UAAI,iBAAiB,cAAc,MAAM;AACvC,YAAI,IAAI,QAAQ,SAAS,KAAK,cAAc;AAC1C,gBAAM,UAAU,eAAe,IAAI,QAAQ,QAAQ,IAAI,KAAK,MAAM;AAClE,cAAI,MAAM,aAAa;AACvB,cAAI,MAAM,cAAc,aAAa,IAAI,QAAQ,QAAQ,IAAI,KAAK,MAAM,IAAI;AAAA,QAC9E;AAAA,MACF,CAAC;AAED,UAAI,iBAAiB,cAAc,MAAM;AACvC,YAAI,IAAI,QAAQ,SAAS,KAAK,cAAc;AAC1C,cAAI,MAAM,aAAa;AACvB,cAAI,MAAM,cAAc;AAAA,QAC1B;AAAA,MACF,CAAC;AAED,cAAQ,YAAY,GAAG;AAAA,IACzB;AAGA,SAAK,WAAW,SAAS,cAAc,UAAU;AACjD,SAAK,SAAS,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU9B,SAAK,SAAS,cAAc;AAC5B,SAAK,SAAS,aAAa,cAAc,qBAAqB;AAG9D,UAAM,OAAO,GAAG,OAAO;AAAA,MACrB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMT,CAAC;AACD,UAAM,QAAQ,UAAU,SAAS,SAAS,KAAK;AAC/C,YAAQ,MAAM,QAAQ,kCAAoC,6BAA+B;AAEzF,SAAK,SAAS,iBAAiB,SAAS,MAAM;AAC5C,WAAK,SAAS,MAAM,cAAc,KAAK,OAAO;AAC9C,WAAK,SAAS,MAAM,YAAY,aAAa,KAAK,OAAO,MAAM;AAC/D,WAAK,SAAS,MAAM,aAAa;AAAA,IACnC,CAAC;AACD,SAAK,SAAS,iBAAiB,QAAQ,MAAM;AAC3C,WAAK,SAAS,MAAM,cAAc;AAClC,WAAK,SAAS,MAAM,YAAY;AAChC,WAAK,SAAS,MAAM,aAAa;AAAA,IACnC,CAAC;AACD,SAAK,SAAS,iBAAiB,SAAS,MAAM;AAC5C,WAAK,kBAAkB;AAAA,IACzB,CAAC;AACD,SAAK,SAAS,iBAAiB,WAAW,CAAC,MAAM;AAC/C,UAAI,EAAE,QAAQ,YAAY,EAAE,WAAW,EAAE,UAAU;AACjD,UAAE,eAAe;AACjB,aAAK,OAAO;AAAA,MACd;AACA,UAAI,EAAE,QAAQ,UAAU;AACtB,aAAK,OAAO;AAAA,MACd;AAAA,IACF,CAAC;AAGD,UAAM,SAAS,GAAG,OAAO,EAAE,OAAO,iEAAiE,CAAC;AAEpG,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ1B,YAAQ,WAAW,SAAS;AAC5B,cAAU,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AACvD,cAAU,iBAAiB,cAAc,MAAM;AAC7C,gBAAU,MAAM,cAAc,KAAK,OAAO;AAC1C,gBAAU,MAAM,QAAQ,KAAK,OAAO;AAAA,IACtC,CAAC;AACD,cAAU,iBAAiB,cAAc,MAAM;AAC7C,gBAAU,MAAM,cAAc;AAC9B,gBAAU,MAAM,QAAQ;AAAA,IAC1B,CAAC;AAED,SAAK,YAAY,SAAS,cAAc,QAAQ;AAChD,SAAK,UAAU,MAAM,UAAU;AAAA;AAAA,+BAEJ,KAAK,OAAO,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,6BAK5B,KAAK,OAAO,UAAU;AAAA;AAE/C,YAAQ,KAAK,WAAW,SAAS;AACjC,SAAK,UAAU,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AAE5D,WAAO,YAAY,SAAS;AAC5B,WAAO,YAAY,KAAK,SAAS;AAEjC,SAAK,KAAK,YAAY,OAAO;AAC7B,SAAK,KAAK,YAAY,KAAK,QAAQ;AACnC,SAAK,KAAK,YAAY,IAAI;AAC1B,SAAK,KAAK,YAAY,MAAM;AAC5B,aAAS,KAAK,YAAY,KAAK,IAAI;AAAA,EACrC;AAAA,EAhK6B;AAAA,EANrB;AAAA,EACA,eAAoC;AAAA,EACpC;AAAA,EACA;AAAA,EACA,UAAyD;AAAA;AAAA;AAAA;AAAA;AAAA,EAwKjE,KAAK,YAAkD;AACrD,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAK,UAAU;AACf,WAAK,eAAe;AACpB,WAAK,SAAS,QAAQ;AACtB,WAAK,kBAAkB;AACvB,WAAK,iBAAiB;AAGtB,UAAI,MAAM,WAAW,SAAS;AAC9B,UAAI,OAAO,WAAW;AAGtB,UAAI,MAAM,MAAM,OAAO,aAAa;AAClC,cAAM,WAAW,MAAM,MAAM;AAAA,MAC/B;AAEA,UAAI,OAAO,MAAM,OAAO,YAAY;AAClC,eAAO,WAAW,QAAQ;AAAA,MAC5B;AACA,aAAO,KAAK,IAAI,GAAG,IAAI;AACvB,YAAM,KAAK,IAAI,GAAG,GAAG;AAErB,WAAK,KAAK,MAAM,MAAM,GAAG,GAAG;AAC5B,WAAK,KAAK,MAAM,OAAO,GAAG,IAAI;AAC9B,WAAK,KAAK,MAAM,UAAU;AAG1B,4BAAsB,MAAM;AAC1B,aAAK,KAAK,MAAM,UAAU;AAC1B,aAAK,KAAK,MAAM,YAAY;AAC5B,aAAK,SAAS,MAAM;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,WAAW,MAAoB,WAA8B;AACnE,SAAK,eAAe;AACpB,UAAM,UAAU,UAAU,iBAAoC,QAAQ;AACtE,eAAW,OAAO,SAAS;AACzB,YAAM,WAAW,IAAI,QAAQ,SAAS;AACtC,YAAM,QAAQ,aAAa,IAAI,QAAQ,QAAQ,IAAI,KAAK,MAAM;AAC9D,YAAM,UAAU,eAAe,IAAI,QAAQ,QAAQ,IAAI,KAAK,MAAM;AAClE,UAAI,MAAM,aAAa,WAAW,UAAU;AAC5C,UAAI,MAAM,cAAc,WAAW,QAAQ,OAAO;AAClD,UAAI,MAAM,QAAQ,WAAW,QAAQ;AACrC,UAAI,MAAM,aAAa,WAAW,QAAQ;AAAA,IAC5C;AACA,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,mBAAyB;AAC/B,UAAM,UAAU,KAAK,KAAK,iBAAoC,mBAAmB;AACjF,eAAW,OAAO,SAAS;AACzB,UAAI,MAAM,aAAa;AACvB,UAAI,MAAM,cAAc;AACxB,UAAI,MAAM,QAAQ;AAClB,UAAI,MAAM,aAAa;AAAA,IACzB;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,UAAM,UAAU,KAAK,iBAAiB,QAAQ,KAAK,SAAS,MAAM,KAAK,EAAE,SAAS;AAClF,SAAK,UAAU,MAAM,UAAU,UAAU,MAAM;AAC/C,SAAK,UAAU,MAAM,gBAAgB,UAAU,SAAS;AAAA,EAC1D;AAAA,EAEQ,SAAe;AACrB,QAAI,CAAC,KAAK,gBAAgB,CAAC,KAAK,SAAS,MAAM,KAAK,EAAG;AACvD,SAAK,UAAU,EAAE,MAAM,KAAK,cAAc,SAAS,KAAK,SAAS,MAAM,KAAK,EAAE,CAAC;AAC/E,SAAK,UAAU;AACf,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,SAAe;AACrB,SAAK,UAAU,IAAI;AACnB,SAAK,UAAU;AACf,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,cAAoB;AAC1B,SAAK,KAAK,MAAM,UAAU;AAC1B,SAAK,KAAK,MAAM,YAAY;AAC5B,eAAW,MAAM;AACf,WAAK,KAAK,MAAM,UAAU;AAAA,IAC5B,GAAG,GAAG;AAAA,EACR;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK,OAAO;AAAA,EACnB;AACF;;;ACjRO,IAAM,YAAN,MAAgB;AAAA,EAWrB,YACmBC,SACA,QACA,KACjB;AAHiB,kBAAAA;AACA;AACA;AAEjB,SAAK,QAAQ,IAAI,MAAM,MAAM;AAE7B,SAAK,IAAI,GAAG,oBAAoB,MAAM,KAAK,SAAS,CAAC;AAAA,EACvD;AAAA,EAPmB;AAAA,EACA;AAAA,EACA;AAAA,EAbX,UAA8B;AAAA,EAC9B,UAA8B;AAAA,EAC9B,cAAkC;AAAA,EAClC,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AAAA,EACX;AAAA,EACA,gBAAgB;AAAA,EAYhB,WAAiB;AACvB,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,OAAO,oBAAoB;AAGhC,SAAK,gBAAgB,SAAS,KAAK,MAAM;AACzC,aAAS,KAAK,MAAM,WAAW;AAG/B,SAAK,UAAU,GAAG,OAAO;AAAA,MACvB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMT,CAAC;AAGD,SAAK,UAAU,GAAG,OAAO;AAAA,MACvB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcT,CAAC;AAED,UAAM,MAAM,GAAG,QAAQ;AAAA,MACrB,OAAO;AAAA;AAAA,qBAEQ,KAAK,OAAO,MAAM;AAAA,6BACV,KAAK,OAAO,UAAU;AAAA;AAAA;AAAA,IAG/C,CAAC;AAGD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,cAAc;AACpB,SAAK,QAAQ,YAAY,KAAK;AAE9B,UAAM,cAAc,GAAG,QAAQ,EAAE,OAAO,0CAA0C,CAAC;AACnF,YAAQ,aAAa,gDAAkD;AAEvE,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ1B,YAAQ,WAAW,SAAS;AAC5B,cAAU,iBAAiB,SAAS,MAAM,KAAK,WAAW,CAAC;AAC3D,cAAU,iBAAiB,cAAc,MAAM;AAC7C,gBAAU,MAAM,cAAc;AAC9B,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,aAAa;AAAA,IAC/B,CAAC;AACD,cAAU,iBAAiB,cAAc,MAAM;AAC7C,gBAAU,MAAM,cAAc;AAC9B,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,aAAa;AAAA,IAC/B,CAAC;AAED,SAAK,QAAQ,YAAY,GAAG;AAC5B,SAAK,QAAQ,YAAY,WAAW;AACpC,SAAK,QAAQ,YAAY,SAAS;AAGlC,SAAK,QAAQ,iBAAiB,aAAa,KAAK,WAAW;AAC3D,SAAK,QAAQ,iBAAiB,aAAa,KAAK,WAAW;AAC3D,SAAK,QAAQ,iBAAiB,WAAW,KAAK,SAAS;AAGvD,aAAS,iBAAiB,WAAW,KAAK,SAAS;AAEnD,aAAS,KAAK,YAAY,KAAK,OAAO;AACtC,aAAS,KAAK,YAAY,KAAK,OAAO;AAAA,EACxC;AAAA,EAEQ,aAAmB;AACzB,QAAI,CAAC,KAAK,SAAU;AACpB,SAAK,WAAW;AAChB,SAAK,YAAY;AAEjB,aAAS,KAAK,MAAM,WAAW,KAAK;AACpC,aAAS,oBAAoB,WAAW,KAAK,SAAS;AAEtD,SAAK,SAAS,OAAO;AACrB,SAAK,SAAS,OAAO;AACrB,SAAK,aAAa,OAAO;AACzB,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,cAAc;AAEnB,SAAK,OAAO,kBAAkB;AAC9B,SAAK,IAAI,KAAK,gBAAgB;AAAA,EAChC;AAAA,EAEQ,YAAY,CAAC,MAA2B;AAC9C,QAAI,EAAE,QAAQ,SAAU,MAAK,WAAW;AAAA,EAC1C;AAAA,EAEQ,cAAc,CAAC,MAAwB;AAC7C,SAAK,YAAY;AACjB,SAAK,SAAS,EAAE;AAChB,SAAK,SAAS,EAAE;AAEhB,SAAK,aAAa,OAAO;AACzB,SAAK,cAAc,GAAG,OAAO;AAAA,MAC3B,OAAO;AAAA;AAAA,2BAEc,KAAK,OAAO,MAAM;AAAA,qBACxB,KAAK,OAAO,MAAM;AAAA;AAAA;AAAA,8BAGT,KAAK,OAAO,UAAU;AAAA;AAAA;AAAA,IAGhD,CAAC;AACD,SAAK,SAAS,YAAY,KAAK,WAAW;AAAA,EAC5C;AAAA,EAEQ,cAAc,CAAC,MAAwB;AAC7C,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,YAAa;AAE1C,UAAM,IAAI,KAAK,IAAI,EAAE,SAAS,KAAK,MAAM;AACzC,UAAM,IAAI,KAAK,IAAI,EAAE,SAAS,KAAK,MAAM;AACzC,UAAM,IAAI,KAAK,IAAI,EAAE,UAAU,KAAK,MAAM;AAC1C,UAAM,IAAI,KAAK,IAAI,EAAE,UAAU,KAAK,MAAM;AAE1C,SAAK,YAAY,MAAM,OAAO,GAAG,CAAC;AAClC,SAAK,YAAY,MAAM,MAAM,GAAG,CAAC;AACjC,SAAK,YAAY,MAAM,QAAQ,GAAG,CAAC;AACnC,SAAK,YAAY,MAAM,SAAS,GAAG,CAAC;AAAA,EACtC;AAAA,EAEQ,YAAY,OAAO,MAAiC;AAC1D,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,YAAa;AAC1C,SAAK,YAAY;AAEjB,UAAM,IAAI,KAAK,IAAI,EAAE,SAAS,KAAK,MAAM;AACzC,UAAM,IAAI,KAAK,IAAI,EAAE,SAAS,KAAK,MAAM;AACzC,UAAM,IAAI,KAAK,IAAI,EAAE,UAAU,KAAK,MAAM;AAC1C,UAAM,IAAI,KAAK,IAAI,EAAE,UAAU,KAAK,MAAM;AAG1C,QAAI,IAAI,MAAM,IAAI,IAAI;AACpB,WAAK,YAAY,OAAO;AACxB,WAAK,cAAc;AACnB;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,QAAQ,GAAG,GAAG,GAAG,CAAC;AAGzC,UAAM,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU;AAE/C,QAAI,CAAC,QAAQ;AACX,WAAK,aAAa,OAAO;AACzB,WAAK,cAAc;AACnB;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,gBAAgB,UAAU;AAClD,SAAK,aAAa,OAAO;AACzB,SAAK,cAAc;AACnB,SAAK,WAAW;AAGhB,SAAK,IAAI,KAAK,uBAAuB;AAAA,MACnC;AAAA,MACA,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,YAAwC;AAE9D,QAAI,KAAK,QAAS,MAAK,QAAQ,MAAM,gBAAgB;AACrD,UAAM,gBAAgB,kBAAkB,UAAU;AAClD,QAAI,KAAK,QAAS,MAAK,QAAQ,MAAM,gBAAgB;AAErD,UAAM,SAAS,eAAe,aAAa;AAC3C,UAAM,eAAe,cAAc,sBAAsB;AACzD,UAAM,OAAO,kBAAkB,YAAY,YAAY;AAEvD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO;AAAA,MAClB,WAAW,OAAO;AAAA,MAClB,kBAAkB,OAAO;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,UAAgB;AACd,SAAK,WAAW;AAChB,SAAK,MAAM,QAAQ;AAAA,EACrB;AACF;;;AClQA,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,kBAAkB;AAMxB,eAAe,eAAe,KAAa,MAAmB,UAAU,aAAgC;AACtG,WAAS,UAAU,GAAG,WAAW,SAAS,WAAW;AACnD,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,UAAU;AAE/D,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,GAAG;AAAA,QACH,QAAQ,WAAW;AAAA,MACrB,CAAC;AACD,mBAAa,OAAO;AAGpB,UAAI,SAAS,MAAO,SAAS,UAAU,OAAO,SAAS,SAAS,KAAM;AACpE,eAAO;AAAA,MACT;AAEA,UAAI,YAAY,QAAS,QAAO;AAAA,IAClC,SAAS,OAAO;AACd,mBAAa,OAAO;AACpB,UAAI,YAAY,QAAS,OAAM;AAAA,IACjC;AAGA,UAAM,YAAY,MAAO,KAAK;AAC9B,UAAM,SAAS,KAAK,OAAO,IAAI,MAAO;AACtC,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,YAAY,MAAM,CAAC;AAAA,EAC5D;AAEA,QAAM,IAAI,MAAM,sBAAsB;AACxC;AAMA,SAAS,cAAc,UAAkB,SAAgC;AACvE,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ,eAAe;AAChD,UAAM,QAA+D,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAC9F,UAAM,KAAK,EAAE,UAAU,QAAQ,CAAC;AAChC,iBAAa,QAAQ,iBAAiB,KAAK,UAAU,KAAK,CAAC;AAAA,EAC7D,QAAQ;AAAA,EAER;AACF;AAEA,eAAsB,gBAAgB,UAAiC;AACrE,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ,eAAe;AAChD,QAAI,CAAC,IAAK;AAEV,UAAM,QAA+D,KAAK,MAAM,GAAG;AAEnF,UAAM,UAAU,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ;AAC3D,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAM,SAAgE,CAAC;AAEvE,eAAW,SAAS,SAAS;AAC3B,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,UAAU;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,MAAM,OAAO;AAAA,QACpC,CAAC;AACD,YAAI,CAAC,IAAI,GAAI,QAAO,KAAK,KAAK;AAAA,MAChC,QAAQ;AACN,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ,EAAE,OAAO,MAAM;AAC5E,QAAI,UAAU,SAAS,GAAG;AACxB,mBAAa,QAAQ,iBAAiB,KAAK,UAAU,SAAS,CAAC;AAAA,IACjE,OAAO;AACL,mBAAa,WAAW,eAAe;AAAA,IACzC;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAMO,IAAM,YAAN,MAAgB;AAAA,EACrB,YAA6B,UAAkB;AAAlB;AAAA,EAAmB;AAAA,EAAnB;AAAA,EAE7B,MAAM,aAAa,SAAqD;AACtE,QAAI;AACF,YAAM,WAAW,MAAM,eAAe,KAAK,UAAU;AAAA,QACnD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,MAC9B,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,eAAe;AAC9D,cAAM,IAAI,MAAM,4BAA4B,SAAS,MAAM,IAAI,IAAI,EAAE;AAAA,MACvE;AAEA,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,SAAS,OAAO;AACd,oBAAc,KAAK,UAAU,OAAO;AACpC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,aACJ,aACA,SAO2D;AAC3D,UAAM,SAAS,IAAI,gBAAgB,EAAE,YAAY,CAAC;AAClD,QAAI,SAAS,KAAM,QAAO,IAAI,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAC1D,QAAI,SAAS,MAAO,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC7D,QAAI,SAAS,KAAM,QAAO,IAAI,QAAQ,QAAQ,IAAI;AAClD,QAAI,SAAS,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACxD,QAAI,SAAS,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AAExD,UAAM,WAAW,MAAM,eAAe,GAAG,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,IAAI,EAAE,QAAQ,MAAM,CAAC;AAEhG,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE;AAAA,IACjE;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAM,gBAAgBC,KAAY,UAA8C;AAC9E,UAAM,WAAW,MAAM,eAAe,KAAK,UAAU;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,IAAAA,KAAI,QAAQ,WAAW,aAAa,OAAO,CAAC;AAAA,IACrE,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE;AAAA,IACjE;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAM,eAAeA,KAA2B;AAC9C,UAAM,WAAW,MAAM,eAAe,KAAK,UAAU;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,IAAAA,IAAG,CAAC;AAAA,IAC7B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,MAAM,mBAAmB,aAAoC;AAC3D,UAAM,WAAW,MAAM,eAAe,KAAK,UAAU;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,aAAa,WAAW,KAAK,CAAC;AAAA,IACvD,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mCAAmC,SAAS,MAAM,EAAE;AAAA,IACtE;AAAA,EACF;AACF;;;ACnLO,IAAM,WAAN,MAAwD;AAAA,EACrD,YAAY,oBAAI,IAA4B;AAAA,EAEpD,GAAsB,OAAU,UAA+C;AAC7E,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACrC;AACA,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,IAAI,QAAoB;AAE5B,WAAO,MAAM;AACX,UAAI,OAAO,QAAoB;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,KAAwB,UAAa,MAAkB;AACrD,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,CAAC,IAAK;AACV,eAAW,MAAM,KAAK;AACpB,UAAI;AACF,WAAG,GAAG,IAAI;AAAA,MACZ,SAAS,KAAK;AAEZ,gBAAQ,MAAM,2CAA2C,OAAO,KAAK,CAAC,MAAM,GAAG;AAAA,MACjF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;ACxBA,IAAM,WAAW;AAQV,IAAM,MAAN,MAAU;AAAA,EASf,YACE,YACAC,SACiB,KACjB;AADiB;AAEjB,UAAM,WAAWA,QAAO,YAAY;AACpC,UAAM,UAAU,aAAa;AAG7B,SAAK,QAAQ;AAAA,MACX,EAAE,IAAI,QAAQ,MAAM,WAAW,OAAO,WAAW;AAAA,MACjD,EAAE,IAAI,YAAY,MAAM,eAAe,OAAO,UAAU;AAAA,MACxD,EAAE,IAAI,sBAAsB,MAAM,UAAU,SAAS,cAAc,OAAO,cAAc;AAAA,IAC1F;AAGA,SAAK,MAAM,SAAS,cAAc,QAAQ;AAC1C,SAAK,IAAI,YAAY,kBAAkB,QAAQ;AAC/C,SAAK,IAAI,MAAM,WAAW;AAC1B,SAAK,IAAI,YAAY,SAAS,aAAa,CAAC;AAC5C,SAAK,IAAI,aAAa,cAAc,+BAA0B;AAC9D,SAAK,IAAI,aAAa,iBAAiB,OAAO;AAC9C,SAAK,IAAI,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AAGtD,SAAK,kBAAkB,SAAS,cAAc,KAAK;AACnD,SAAK,gBAAgB,YAAY,wBAAwB,QAAQ;AACjE,SAAK,gBAAgB,aAAa,QAAQ,MAAM;AAEhD,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,YAAM,OAAO,KAAK,MAAM,CAAC;AACzB,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,YAAY;AAChB,UAAI,MAAM,YAAY,UAAU,OAAO,CAAC,CAAC;AACzC,UAAI,YAAY,SAAS,KAAK,IAAI,CAAC;AACnC,UAAI,aAAa,QAAQ,UAAU;AACnC,UAAI,aAAa,cAAc,KAAK,KAAK;AACzC,UAAI,QAAQ,SAAS,KAAK;AAE1B,UAAI,iBAAiB,SAAS,CAAC,MAAM;AACnC,UAAE,gBAAgB;AAClB,aAAK,gBAAgB,KAAK,EAAE;AAAA,MAC9B,CAAC;AAED,YAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,YAAM,YAAY;AAClB,YAAM,cAAc,KAAK;AACzB,YAAM,MAAM,UAAU,UAClB,4FACA;AACJ,UAAI,YAAY,KAAK;AAErB,WAAK,gBAAgB,YAAY,GAAG;AAAA,IACtC;AAEA,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,KAAK,YAAY,KAAK,eAAe;AAC1C,SAAK,KAAK,YAAY,KAAK,GAAG;AAC9B,eAAW,YAAY,KAAK,IAAI;AAGhC,UAAM,OAAO,WAAW;AACxB,SAAK,kBAAkB,CAAC,MAAkB;AACxC,UAAI,KAAK,UAAU,CAAC,EAAE,aAAa,EAAE,SAAS,IAAI,GAAG;AACnD,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AACA,aAAS,iBAAiB,SAAS,KAAK,eAAe;AAEvD,SAAK,IAAI,iBAAiB,WAAW,CAAC,MAAM;AAC1C,UAAI,EAAE,QAAQ,YAAY,KAAK,OAAQ,MAAK,MAAM;AAAA,IACpD,CAAC;AAAA,EACH;AAAA,EArEmB;AAAA,EAXX;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAA8B;AAAA,EAC9B,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB;AAAA,EA4EA;AAAA;AAAA,EAGR,YAAY,OAAqB;AAC/B,QAAI,SAAS,GAAG;AACd,WAAK,SAAS,OAAO;AACrB,WAAK,UAAU;AACf;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,UAAU,SAAS,cAAc,MAAM;AAC5C,WAAK,QAAQ,YAAY;AACzB,WAAK,IAAI,YAAY,KAAK,OAAO;AAAA,IACnC;AAEA,YAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,EAC1D;AAAA,EAEQ,SAAe;AACrB,SAAK,SAAS,KAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EACzC;AAAA,EAEQ,OAAa;AACnB,SAAK,SAAS;AACd,SAAK,WAAW,UAAU;AAC1B,SAAK,IAAI,aAAa,iBAAiB,MAAM;AAE7C,UAAM,UAAU,KAAK,gBAAgB,iBAAoC,iBAAiB;AAC1F,YAAQ,QAAQ,CAAC,KAAK,MAAM;AAE1B,YAAM,IAAI,EAAE,KAAK,YAAY,IAAI;AACjC,UAAI,MAAM,YAAY,kBAAkB,CAAC;AACzC,UAAI,UAAU,IAAI,sBAAsB;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEQ,QAAc;AACpB,SAAK,SAAS;AACd,SAAK,WAAW,aAAa;AAC7B,SAAK,IAAI,aAAa,iBAAiB,OAAO;AAE9C,UAAM,UAAU,KAAK,gBAAgB,iBAAoC,iBAAiB;AAC1F,YAAQ,QAAQ,CAAC,QAAQ;AACvB,UAAI,MAAM,YAAY;AACtB,UAAI,UAAU,OAAO,sBAAsB;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA,EAEQ,WAAW,QAAsB;AACvC,UAAM,QAAQ,KAAK;AACnB,SAAK,IAAI,gBAAgB,SAAS,MAAM,CAAC;AAEzC,QAAI,MAAO,MAAK,IAAI,YAAY,KAAK;AAAA,EACvC;AAAA,EAEQ,gBAAgBC,KAAkB;AACxC,SAAK,MAAM;AAEX,YAAQA,KAAI;AAAA,MACV,KAAK;AACH,aAAK,IAAI,KAAK,gBAAgB,IAAI;AAClC;AAAA,MACF,KAAK;AACH,aAAK,IAAI,KAAK,kBAAkB;AAChC;AAAA,MACF,KAAK,sBAAsB;AACzB,aAAK,qBAAqB,CAAC,KAAK;AAChC,aAAK,IAAI,KAAK,sBAAsB,KAAK,kBAAkB;AAC3D,cAAM,MAAM,KAAK,gBAAgB,cAAc,qCAAqC;AACpF,YAAI,KAAK;AACP,cAAI,gBAAgB,SAAS,KAAK,qBAAqB,WAAW,YAAY,CAAC;AAAA,QACjF;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,aAAS,oBAAoB,SAAS,KAAK,eAAe;AAC1D,SAAK,KAAK,OAAO;AAAA,EACnB;AACF;;;ACzLA,IAAM,cAAc;AAOb,SAAS,cAA+B;AAC7C,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ,WAAW;AAC5C,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,QAAQ,OAAO,MAAO,QAAO;AACxC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,aAAa,UAA0B;AACrD,MAAI;AACF,iBAAa,QAAQ,aAAa,KAAK,UAAU,QAAQ,CAAC;AAAA,EAC5D,QAAQ;AAAA,EAER;AACF;;;ACfO,SAAS,aAAa,GAAW,GAAmB;AACzD,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,WAAW,EAAG,QAAO,EAAE;AAC7B,MAAI,EAAE,WAAW,EAAG,QAAO,EAAE;AAG7B,MAAI,EAAE,SAAS,EAAE,QAAQ;AACvB,UAAM,IAAI;AACV,QAAI;AACJ,QAAI;AAAA,EACN;AAEA,QAAM,OAAO,EAAE;AACf,QAAM,OAAO,EAAE;AACf,MAAI,OAAO,IAAI,MAAc,OAAO,CAAC;AACrC,WAAS,IAAI,GAAG,KAAK,MAAM,IAAK,MAAK,CAAC,IAAI;AAC1C,MAAI,OAAO,IAAI,MAAc,OAAO,CAAC;AAErC,WAAS,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,SAAK,CAAC,IAAI;AACV,aAAS,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,WAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AAAA,IAChG;AACA,UAAM,MAAM;AACZ,WAAO;AACP,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI;AAClB;AAKO,SAAS,WAAW,GAAW,GAAmB;AACvD,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AAC1C,MAAI,WAAW,EAAG,QAAO;AACzB,SAAO,IAAI,aAAa,GAAG,CAAC,IAAI;AAClC;AAOO,SAAS,cAAc,UAAkB,QAAgB,WAAW,KAAa;AACtF,MAAI,CAAC,UAAU,CAAC,SAAU,QAAO;AACjC,MAAI,SAAS,SAAS,MAAM,EAAG,QAAO;AAEtC,QAAM,OAAO,OAAO;AAGpB,MAAI,OAAO,SAAS,QAAQ;AAC1B,UAAM,QAAQ,WAAW,UAAU,MAAM;AACzC,WAAO,SAAS,WAAW,QAAQ;AAAA,EACrC;AAEA,MAAI,OAAO;AAGX,QAAM,SAAS,SAAS,SAAS,MAAM,SAAS,MAAM,GAAG,GAAG,IAAI;AAChE,QAAM,QAAQ,OAAO,SAAS;AAE9B,WAAS,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,UAAMC,UAAS,OAAO,MAAM,GAAG,IAAI,IAAI;AACvC,UAAM,QAAQ,WAAWA,SAAQ,MAAM;AACvC,QAAI,QAAQ,KAAM,QAAO;AACzB,QAAI,QAAQ,KAAM;AAAA,EACpB;AAEA,SAAO,QAAQ,WAAW,OAAO;AACnC;;;AC7DA,IAAM,sBAAsB;AAG5B,IAAM,uBAAuB;AAO7B,SAAS,YAAYC,KAAa,QAA6B;AAC7D,MAAI,CAAC,OAAO,YAAa,QAAO;AAChC,QAAM,QAAQA,IAAG,aAAa,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG;AACxD,SAAO,cAAc,MAAM,OAAO,aAAa,GAAG,IAAI;AACxD;AAeO,SAAS,cAAc,QAA6C;AAEzE,MAAI,OAAO,WAAW;AACpB,UAAMA,MAAK,SAAS,eAAe,OAAO,SAAS;AACnD,QAAIA,OAAMA,IAAG,YAAY,OAAO,cAAc,YAAYA,KAAI,MAAM,GAAG;AACrE,aAAO,EAAE,SAASA,KAAI,YAAY,GAAK,UAAU,KAAK;AAAA,IACxD;AAAA,EACF;AAGA,MAAI;AACF,UAAMA,MAAK,SAAS,cAAc,OAAO,WAAW;AACpD,QAAIA,OAAMA,IAAG,YAAY,OAAO,cAAc,YAAYA,KAAI,MAAM,GAAG;AACrE,aAAO,EAAE,SAASA,KAAI,YAAY,MAAM,UAAU,MAAM;AAAA,IAC1D;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI;AACF,UAAM,SAAS,SAAS,SAAS,OAAO,OAAO,UAAU,MAAM,YAAY,yBAAyB,IAAI;AACxG,UAAMA,MAAK,OAAO;AAClB,QAAIA,eAAc,WAAWA,IAAG,YAAY,OAAO,cAAc,YAAYA,KAAI,MAAM,GAAG;AACxF,aAAO,EAAE,SAASA,KAAI,YAAY,KAAK,UAAU,QAAQ;AAAA,IAC3D;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,SAAO,UAAU,MAAM;AACzB;AASA,SAAS,UAAU,QAA6C;AAC9D,QAAM,MAAM,OAAO,WAAW,YAAY;AAC1C,QAAM,aAAa,SAAS,iBAAiB,GAAG;AAChD,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,MAAI,cAA8B;AAClC,MAAI,YAAY;AAEhB,QAAM,QAAQ,KAAK,IAAI,WAAW,QAAQ,mBAAmB;AAE7D,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAMA,MAAK,WAAW,CAAC;AACvB,UAAM,QAAQ,eAAeA,KAAI,MAAM;AACvC,QAAI,QAAQ,WAAW;AACrB,kBAAY;AACZ,oBAAcA;AACd,UAAI,aAAa,KAAM;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,CAAC,eAAe,YAAY,IAAK,QAAO;AAE5C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,KAAK,IAAI,WAAW,IAAI;AAAA,IACpC,UAAU;AAAA,EACZ;AACF;AAWA,SAAS,eAAe,WAAoB,QAA4B;AACtE,MAAI,QAAQ;AACZ,MAAI,cAAc;AAGlB,QAAM,iBAAiB,UAAU,aAAa,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG;AAGxE,MAAI,OAAO,aAAa;AACtB,mBAAe;AACf,aAAS,cAAc,eAAe,OAAO,aAAa,GAAG,IAAI;AAAA,EACnE;AAGA,MAAI,OAAO,aAAa;AACtB,mBAAe;AACf,aAAS,iBAAiB,WAAW,OAAO,WAAW,IAAI;AAAA,EAC7D;AAGA,MAAI,OAAO,cAAc,OAAO,YAAY;AAC1C,mBAAe;AACf,QAAI,eAAe;AACnB,QAAI,eAAe;AAEnB,QAAI,OAAO,YAAY;AACrB,YAAM,WAAW,aAAa,WAAW,QAAQ;AACjD,sBAAgB,WAAW,WAAW,UAAU,OAAO,UAAU,IAAI;AACrE;AAAA,IACF;AAEA,QAAI,OAAO,YAAY;AACrB,YAAM,WAAW,aAAa,WAAW,OAAO;AAChD,sBAAgB,WAAW,WAAW,UAAU,OAAO,UAAU,IAAI;AACrE;AAAA,IACF;AAEA,QAAI,eAAe,GAAG;AACpB,eAAU,eAAe,eAAgB;AAAA,IAC3C;AAAA,EACF;AAGA,MAAI,OAAO,cAAc;AACvB,mBAAe;AACf,UAAM,oBAAoB,aAAa,SAAS;AAChD,aAAS,oBAAoB,WAAW,mBAAmB,OAAO,YAAY,IAAI,KAAK;AAAA,EACzF;AAEA,SAAO,cAAc,IAAI,QAAQ,cAAc;AACjD;AAOO,SAAS,kBAAkB,QAAoB,MAA2C;AAC/F,QAAM,aAAa,cAAc,MAAM;AAEvC,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,SAAS,WAAW,QAAQ,sBAAsB;AACxD,QAAM,eAAe,IAAI;AAAA,IACvB,OAAO,IAAI,KAAK,OAAO,OAAO;AAAA,IAC9B,OAAO,IAAI,KAAK,OAAO,OAAO;AAAA,IAC9B,KAAK,OAAO,OAAO;AAAA,IACnB,KAAK,OAAO,OAAO;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,SAAS,WAAW;AAAA,IACpB,MAAM;AAAA,IACN,YAAY,WAAW;AAAA,IACvB,UAAU,WAAW;AAAA,EACvB;AACF;;;ACpMA,SAAS,aAAa,GAA2B;AAC/C,SAAO;AAAA,IACL,aAAa,EAAE;AAAA,IACf,OAAO,EAAE;AAAA,IACT,aAAa,EAAE;AAAA,IACf,YAAY,EAAE;AAAA,IACd,WAAW,EAAE,aAAa;AAAA,IAC1B,YAAY,EAAE;AAAA,IACd,YAAY,EAAE;AAAA,IACd,aAAa,EAAE;AAAA,IACf,cAAc,EAAE;AAAA,EAClB;AACF;AAEA,SAAS,WAAW,GAAyB;AAC3C,SAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK;AAClE;AAGA,IAAM,gBAAgB;AAGtB,SAAS,eAAe,MAA8C;AACpE,SAAO;AAAA,IACL,KAAK,KAAK,MAAM,OAAO,UAAU;AAAA,IACjC,MAAM,KAAK,QAAQ,OAAO,UAAU;AAAA,EACtC;AACF;AAgBA,SAAS,cAAc,SAAkB,GAAoC;AAC3E,SAAO,QAAQ,QAAQ,CAAC,EAAE,SAAS,QAAQ,eAAe,CAAC,CAAC;AAC9D;AAEA,IAAM,iBAAiB;AACvB,IAAM,sBAAsB;AAC5B,IAAM,2BAA2B;AACjC,IAAM,mBAAmB;AACzB,IAAM,cAAc;AAQb,IAAM,gBAAN,MAAoB;AAAA,EAgBzB,YACmB,QACA,SACA,KACjB;AAHiB;AACA;AACA;AAEjB,SAAK,YAAY,GAAG,OAAO;AAAA,MACzB,OAAO;AAAA,IACT,CAAC;AACD,SAAK,UAAU,KAAK;AACpB,aAAS,KAAK,YAAY,KAAK,SAAS;AAExC,SAAK,IAAI,GAAG,sBAAsB,CAAC,YAAY;AAC7C,WAAK,UAAU,MAAM,UAAU,UAAU,UAAU;AAAA,IACrD,CAAC;AAED,SAAK,gBAAgB,MAAM,KAAK,mBAAmB;AACnD,WAAO,iBAAiB,UAAU,KAAK,eAAe,EAAE,SAAS,KAAK,CAAC;AAIvE,SAAK,mBAAmB,IAAI,iBAAiB,CAAC,cAAc;AAC1D,YAAM,mBAAmB,UAAU;AAAA,QACjC,CAAC,MAAM,KAAK,UAAU,SAAS,EAAE,MAAM,KAAK,KAAK,QAAQ,SAAS,EAAE,MAAM;AAAA,MAC5E;AACA,UAAI,CAAC,iBAAkB,MAAK,mBAAmB;AAAA,IACjD,CAAC;AACD,SAAK,iBAAiB,QAAQ,SAAS,MAAM;AAAA,MAC3C,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,eAAe;AAAA,IACjB,CAAC;AAED,SAAK,6BAA6B,CAAC,MAAkB;AACnD,UAAI,KAAK,UAAU,SAAS,EAAE,MAAc,EAAG;AAC/C,WAAK,oBAAoB;AAAA,IAC3B;AACA,aAAS,iBAAiB,SAAS,KAAK,0BAA0B;AAAA,EACpE;AAAA,EArCmB;AAAA,EACA;AAAA,EACA;AAAA,EAlBX;AAAA,EACA,UAAyB,CAAC;AAAA,EAC1B,oBAAmC,CAAC;AAAA,EACpC,iBAA0C;AAAA,EAC1C,kBAAoD;AAAA,EACpD,kBAAwD;AAAA,EACxD,mBAA4C;AAAA,EAC5C,gBAAqC;AAAA,EACrC,WAAsB,CAAC;AAAA,EACvB,6BAA+D;AAAA,EAEvE,IAAI,QAAgB;AAClB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EA0CQ,qBAA2B;AACjC,QAAI,KAAK,gBAAiB;AAC1B,SAAK,kBAAkB,WAAW,MAAM;AACtC,WAAK,kBAAkB;AACvB,WAAK,cAAc;AAAA,IACrB,GAAG,mBAAmB;AAAA,EACxB;AAAA,EAEQ,gBAAsB;AAC5B,eAAW,SAAS,KAAK,SAAS;AAChC,eAAS,IAAI,GAAG,IAAI,MAAM,SAAS,YAAY,QAAQ,KAAK;AAC1D,cAAM,WAAW,MAAM,SAAS,CAAC;AACjC,YAAI,CAAC,SAAU;AAEf,cAAM,aAAa,MAAM,SAAS,YAAY,CAAC;AAC/C,cAAM,WAAW,kBAAkB,aAAa,UAAU,GAAG,WAAW,UAAU,CAAC;AACnF,YAAI,CAAC,UAAU;AACb,mBAAS,MAAM,UAAU;AACzB;AAAA,QACF;AAEA,cAAM,MAAM,eAAe,SAAS,IAAI;AACxC,cAAM,UAAU,IAAI;AACpB,cAAM,WAAW,IAAI;AACrB,iBAAS,MAAM,UAAU;AACzB,aAAK,qBAAqB,UAAU,SAAS,YAAY,MAAM,QAAQ;AAAA,MACzE;AAAA,IACF;AACA,SAAK,sBAAsB;AAAA,EAC7B;AAAA,EAEQ,wBAA8B;AACpC,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI,QAAQ,UAAU;AACpB,aAAK,kBAAkB,OAAO;AAAA,MAChC,OAAO;AACL,aAAK,oBAAoB,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,WAAqC;AAC1C,SAAK,MAAM;AACX,cAAU,QAAQ,CAAC,UAAU,MAAM;AACjC,YAAM,QAAQ,KAAK,WAAW,UAAU,IAAI,CAAC;AAC7C,WAAK,QAAQ,KAAK,KAAK;AAAA,IACzB,CAAC;AACD,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,YAAY,UAA4BC,QAAqB;AAC3D,UAAM,QAAQ,KAAK,WAAW,UAAUA,MAAK;AAC7C,eAAW,KAAK,MAAM,UAAU;AAC9B,QAAE,MAAM,YAAY;AAAA,IACtB;AACA,SAAK,QAAQ,KAAK,KAAK;AACvB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,WAAW,UAA4BA,QAA4B;AACzE,UAAM,QAAqB,EAAE,UAAU,UAAU,CAAC,GAAG,SAAS,GAAG,UAAU,EAAE;AAC7E,eAAW,cAAc,SAAS,aAAa;AAC7C,YAAM,WAAW,kBAAkB,aAAa,UAAU,GAAG,WAAW,UAAU,CAAC;AACnF,UAAI,CAAC,SAAU;AACf,YAAM,MAAM,eAAe,SAAS,IAAI;AACxC,YAAM,UAAU,IAAI;AACpB,YAAM,WAAW,IAAI;AACrB,YAAM,SAAS,KAAK,aAAaA,QAAO,UAAU,GAAG;AACrD,WAAK,qBAAqB,QAAQ,SAAS,YAAY,QAAQ;AAC/D,WAAK,UAAU,YAAY,MAAM;AACjC,YAAM,SAAS,KAAK,MAAM;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAsB;AAC5B,eAAW,SAAS,KAAK,UAAU,iBAA8B,mBAAmB,GAAG;AACrF,YAAM,OAAO;AAAA,IACf;AAEA,UAAM,WAAoD,CAAC;AAC3D,eAAW,SAAS,KAAK,SAAS;AAChC,eAAS,IAAI,GAAG,IAAI,MAAM,SAAS,QAAQ,KAAK;AAC9C,iBAAS,KAAK,EAAE,OAAO,OAAO,EAAE,CAAC;AAAA,MACnC;AAAA,IACF;AAEA,UAAM,OAAO,oBAAI,IAAY;AAC7B,SAAK,WAAW,CAAC;AAEjB,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAI,KAAK,IAAI,CAAC,EAAG;AACjB,YAAM,UAAmB;AAAA,QACvB,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK;AAAA,QAC3B,gBAAgB,CAAC,SAAS,CAAC,EAAE,KAAK;AAAA,QAClC,UAAU;AAAA,MACZ;AACA,WAAK,IAAI,CAAC;AAEV,eAAS,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AAC5C,YAAI,KAAK,IAAI,CAAC,EAAG;AACjB,cAAM,IAAI,SAAS,CAAC,EAAE;AACtB,cAAM,IAAI,SAAS,CAAC,EAAE;AACtB,cAAM,OAAO,KAAK,MAAM,EAAE,WAAW,EAAE,aAAa,KAAK,EAAE,UAAU,EAAE,YAAY,CAAC;AACpF,YAAI,OAAO,kBAAkB;AAC3B,kBAAQ,QAAQ,KAAK,CAAC;AACtB,kBAAQ,eAAe,KAAK,SAAS,CAAC,EAAE,KAAK;AAC7C,eAAK,IAAI,CAAC;AAAA,QACZ;AAAA,MACF;AAEA,WAAK,SAAS,KAAK,OAAO;AAAA,IAC5B;AAEA,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI,QAAQ,QAAQ,UAAU,EAAG;AACjC,WAAK,oBAAoB,OAAO;AAChC,WAAK,gBAAgB,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,oBAAoB,SAAwB;AAClD,UAAM,EAAE,SAAS,SAAS,IAAI,QAAQ,QAAQ,CAAC;AAC/C,UAAM,SAAS,QAAQ,QAAQ,UAAU;AACzC,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC/C,YAAM,IAAI,cAAc,SAAS,CAAC;AAClC,UAAI,CAAC,EAAG;AACR,QAAE,MAAM,MAAM,GAAG,WAAW,SAAS,IAAI,IAAI,EAAE;AAC/C,QAAE,MAAM,OAAO,GAAG,YAAY,SAAS,IAAI,IAAI,EAAE;AACjD,QAAE,MAAM,SAAS,OAAO,IAAI,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,kBAAkB,SAAwB;AAChD,UAAM,EAAE,SAAS,SAAS,IAAI,QAAQ,QAAQ,CAAC;AAC/C,UAAM,QAAQ,QAAQ,QAAQ;AAC9B,UAAM,cAAc,QAAQ,KAAK;AACjC,UAAM,YAAY,WAAW,aAAa;AAE1C,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,IAAI,cAAc,SAAS,CAAC;AAClC,UAAI,CAAC,EAAG;AACR,QAAE,MAAM,MAAM,GAAG,OAAO;AACxB,QAAE,MAAM,OAAO,GAAG,YAAY,IAAI,WAAW;AAC7C,QAAE,MAAM,SAAS,OAAO,KAAK,CAAC;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,gBAAgB,SAAwB;AAC9C,UAAM,YAAY,cAAc,SAAS,QAAQ,QAAQ,SAAS,CAAC;AACnE,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,GAAG,OAAO;AAAA,MACtB,OAAO;AAAA,MACP,OAAO;AAAA;AAAA;AAAA;AAAA,qBAIQ,KAAK,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQnC,CAAC;AACD,YAAQ,OAAO,OAAO,QAAQ,QAAQ,MAAM,CAAC;AAC7C,cAAU,YAAY,KAAK;AAAA,EAC7B;AAAA,EAEQ,iBAAiB,SAAkB,SAAwB;AACjE,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC/C,YAAM,QAAQ,cAAc,SAAS,CAAC,GAAG,cAAc,mBAAmB;AAC1E,UAAI,MAAO,OAAM,MAAM,UAAU,UAAU,SAAS;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,YAAY,QAAqC;AACvD,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI,QAAQ,QAAQ,UAAU,EAAG;AACjC,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC/C,YAAI,cAAc,SAAS,CAAC,MAAM,OAAQ,QAAO;AAAA,MACnD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,QAAqB,GAAwB;AACtE,UAAM,UAAU,KAAK,YAAY,MAAM;AACvC,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,CAAC,QAAQ,UAAU;AACrB,QAAE,gBAAgB;AAClB,WAAK,oBAAoB;AACzB,cAAQ,WAAW;AACnB,WAAK,kBAAkB,OAAO;AAC9B,WAAK,iBAAiB,SAAS,KAAK;AACpC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAgB,SAAwB;AAC9C,QAAI,CAAC,QAAQ,SAAU;AACvB,YAAQ,WAAW;AACnB,SAAK,oBAAoB,OAAO;AAChC,SAAK,iBAAiB,SAAS,IAAI;AAAA,EACrC;AAAA,EAEQ,sBAA4B;AAClC,eAAW,WAAW,KAAK,UAAU;AACnC,WAAK,gBAAgB,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,qBAAqB,QAAqB,YAAoB,UAAkC;AACtG,UAAM,aAAa,SAAS,WAAW;AACvC,QAAI,aAAa,4BAA4B,CAAC,YAAY;AACxD,aAAO,MAAM,cAAc;AAC3B,aAAO,MAAM,UAAU;AACvB,aAAO,QAAQ,uCAAuC,KAAK,MAAM,aAAa,GAAG,CAAC;AAAA,IACpF,OAAO;AACL,aAAO,MAAM,cAAc;AAC3B,aAAO,MAAM,UAAU;AACvB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAAA,EAEQ,aAAa,QAAgB,UAA4B,KAAiD;AAChH,UAAM,YAAY,aAAa,SAAS,MAAM,KAAK,MAAM;AACzD,UAAM,aAAa,SAAS,WAAW;AAEvC,UAAM,SAAS,GAAG,OAAO;AAAA,MACvB,OAAO;AAAA;AAAA,cAEC,IAAI,GAAG;AAAA,eACN,IAAI,IAAI;AAAA;AAAA;AAAA,qBAGF,aAAa,0BAA0B,wBAAwB;AAAA;AAAA;AAAA,2BAGzD,aAAa,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA,gBAI7C,aAAa,YAAY,SAAS;AAAA;AAAA,qBAE7B,aAAa,+BAA+B,cAAc,SAAS,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKpH,CAAC;AACD,WAAO,QAAQ,aAAa,SAAS;AACrC,YAAQ,QAAQ,aAAa,WAAW,OAAO,MAAM,CAAC;AAEtD,WAAO,iBAAiB,cAAc,MAAM;AAC1C,aAAO,MAAM,YAAY;AACzB,aAAO,MAAM,YAAY,aACrB,+BACA,cAAc,SAAS;AAC3B,WAAK,QAAQ,KAAK,UAAU,OAAO,sBAAsB,CAAC;AAC1D,UAAI,CAAC,KAAK,eAAgB,MAAK,cAAc,QAAQ;AAAA,IACvD,CAAC;AAED,WAAO,iBAAiB,cAAc,MAAM;AAC1C,aAAO,MAAM,YAAY;AACzB,aAAO,MAAM,YAAY,aACrB,+BACA,cAAc,SAAS;AAC3B,WAAK,QAAQ,aAAa;AAC1B,UAAI,CAAC,KAAK,eAAgB,MAAK,eAAe;AAAA,IAChD,CAAC;AAED,WAAO,iBAAiB,SAAS,CAAC,MAAM;AACtC,UAAI,KAAK,mBAAmB,QAAQ,CAAC,EAAG;AACxC,WAAK,aAAa,QAAQ;AAC1B,WAAK,IAAI,KAAK,gBAAgB,IAAI;AAClC,aAAO;AAAA,QACL,IAAI,YAAY,mBAAmB;AAAA,UACjC,QAAQ,EAAE,YAAY,SAAS,GAAG;AAAA,UAClC,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,YAA0B;AAClC,eAAW,SAAS,KAAK,SAAS;AAChC,UAAI,MAAM,SAAS,OAAO,YAAY;AACpC,mBAAW,YAAY,MAAM,UAAU;AACrC,mBAAS,MAAM,YAAY;AAC3B,mBAAS;AAAA,YACP;AAAA,YACA,MAAM;AACJ,uBAAS,MAAM,YAAY;AAAA,YAC7B;AAAA,YACA,EAAE,MAAM,KAAK;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,UAAkC;AAC9C,SAAK,wBAAwB;AAC7B,eAAW,cAAc,SAAS,aAAa;AAC7C,YAAM,WAAW,kBAAkB,aAAa,UAAU,GAAG,WAAW,UAAU,CAAC;AACnF,UAAI,CAAC,SAAU;AAEf,YAAM,YAAY,aAAa,SAAS,MAAM,KAAK,MAAM;AACzD,YAAM,OAAO,SAAS;AACtB,YAAM,YAAY,GAAG,OAAO;AAAA,QAC1B,OAAO;AAAA;AAAA,gBAEC,KAAK,MAAM,OAAO,OAAO;AAAA,iBACxB,KAAK,OAAO,OAAO,OAAO;AAAA,kBACzB,KAAK,KAAK,aAAa,KAAK,MAAM;AAAA,6BACvB,SAAS;AAAA,uBACf,SAAS;AAAA;AAAA;AAAA;AAAA,gCAIA,SAAS;AAAA,+BACV,cAAc;AAAA;AAAA,MAEvC,CAAC;AACD,WAAK,UAAU,YAAY,SAAS;AACpC,WAAK,kBAAkB,KAAK,SAAS;AACrC,gBAAU;AACV,gBAAU,MAAM,UAAU;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,aAAa,UAAkC;AAC7C,SAAK,eAAe;AACpB,SAAK,cAAc,QAAQ;AAC3B,SAAK,iBAAiB;AACtB,SAAK,kBAAkB,CAAC,MAAkB;AACxC,UAAI,KAAK,UAAU,SAAS,EAAE,MAAc,EAAG;AAC/C,WAAK,eAAe;AAAA,IACtB;AACA,aAAS,iBAAiB,SAAS,KAAK,iBAAiB,EAAE,SAAS,KAAK,CAAC;AAAA,EAC5E;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,iBAAiB;AACxB,eAAS,oBAAoB,SAAS,KAAK,iBAAiB,EAAE,SAAS,KAAK,CAAC;AAC7E,WAAK,kBAAkB;AAAA,IACzB;AACA,SAAK,iBAAiB;AACtB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,iBAAuB;AAC7B,eAAW,KAAK,KAAK,mBAAmB;AACtC,QAAE,MAAM,UAAU;AAClB,iBAAW,MAAM,EAAE,OAAO,GAAG,cAAc;AAAA,IAC7C;AACA,SAAK,oBAAoB,CAAC;AAAA,EAC5B;AAAA,EAEQ,0BAAgC;AACtC,eAAW,KAAK,KAAK,kBAAmB,GAAE,OAAO;AACjD,SAAK,oBAAoB,CAAC;AAAA,EAC5B;AAAA,EAEA,QAAc;AACZ,SAAK,eAAe;AACpB,SAAK,UAAU,gBAAgB;AAC/B,SAAK,UAAU,CAAC;AAChB,SAAK,WAAW,CAAC;AAAA,EACnB;AAAA,EAEA,UAAgB;AACd,SAAK,eAAe;AACpB,QAAI,KAAK,gBAAiB,cAAa,KAAK,eAAe;AAC3D,QAAI,KAAK,cAAe,QAAO,oBAAoB,UAAU,KAAK,aAAa;AAC/E,QAAI,KAAK,2BAA4B,UAAS,oBAAoB,SAAS,KAAK,0BAA0B;AAC1G,SAAK,kBAAkB,WAAW;AAClC,SAAK,UAAU,OAAO;AAAA,EACxB;AACF;;;ACpfA,IAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,OAAO;AACT;AASO,IAAM,QAAN,MAAY;AAAA,EAUjB,YACE,YACiB,QACA,KACA,WACA,aACA,SACjB;AALiB;AACA;AACA;AACA;AACA;AAEjB,SAAK,OAAO,GAAG,OAAO,EAAE,OAAO,WAAW,CAAC;AAG3C,UAAM,SAAS,GAAG,OAAO,EAAE,OAAO,kBAAkB,CAAC;AACrD,UAAM,QAAQ,GAAG,QAAQ,EAAE,OAAO,iBAAiB,CAAC;AACpD,YAAQ,OAAO,WAAW;AAE1B,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,YAAY;AACrB,aAAS,aAAa,cAAc,mBAAmB;AACvD,aAAS,YAAY,SAAS,UAAU,CAAC;AACzC,aAAS,iBAAiB,SAAS,MAAM,KAAK,MAAM,CAAC;AAErD,SAAK,eAAe,SAAS,cAAc,QAAQ;AACnD,SAAK,aAAa,YAAY;AAC9B,SAAK,aAAa,aAAa,cAAc,gBAAgB;AAC7D,SAAK,aAAa,YAAY,SAAS,UAAU,CAAC;AAClD,UAAM,iBAAiB,SAAS,cAAc,MAAM;AACpD,YAAQ,gBAAgB,iBAAiB;AACzC,SAAK,aAAa,YAAY,cAAc;AAC5C,SAAK,aAAa,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAEzE,UAAM,cAAc,GAAG,OAAO,EAAE,OAAO,wBAAwB,CAAC;AAChE,gBAAY,YAAY,KAAK,YAAY;AACzC,gBAAY,YAAY,QAAQ;AAEhC,WAAO,YAAY,KAAK;AACxB,WAAO,YAAY,WAAW;AAG9B,UAAM,UAAU,GAAG,OAAO,EAAE,OAAO,aAAa,CAAC;AAGjD,UAAM,aAAa,GAAG,OAAO,EAAE,OAAO,iBAAiB,CAAC;AACxD,UAAM,aAAa,SAAS,WAAW;AACvC,eAAW,aAAa,SAAS,gBAAgB;AACjD,SAAK,cAAc,SAAS,cAAc,OAAO;AACjD,SAAK,YAAY,OAAO;AACxB,SAAK,YAAY,YAAY;AAC7B,SAAK,YAAY,cAAc;AAC/B,SAAK,YAAY,aAAa,cAAc,+BAA+B;AAC3E,SAAK,YAAY,iBAAiB,SAAS,MAAM;AAC/C,UAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AACvD,WAAK,gBAAgB,WAAW,MAAM,KAAK,cAAc,GAAG,GAAG;AAAA,IACjE,CAAC;AACD,eAAW,YAAY,UAAU;AACjC,eAAW,YAAY,KAAK,WAAW;AAGvC,UAAM,QAAQ,GAAG,OAAO,EAAE,OAAO,WAAW,CAAC;AAC7C,UAAM,cAAc;AAAA,MAClB,EAAE,OAAO,OAAO,OAAO,OAAO;AAAA,MAC9B,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,MACvC,EAAE,OAAO,cAAc,OAAO,aAAa;AAAA,MAC3C,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,MAC7B,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,IACnC;AAEA,eAAW,UAAU,aAAa;AAChC,YAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,WAAK,YAAY,WAAW,OAAO,UAAU,QAAQ,oBAAoB,EAAE;AAC3E,UAAI,OAAO,UAAU,OAAO;AAC1B,aAAK,MAAM,cAAc,aAAa,OAAO,OAAO,KAAK,MAAM;AAAA,MACjE;AACA,cAAQ,MAAM,OAAO,KAAK;AAC1B,WAAK,QAAQ,SAAS,OAAO;AAC7B,WAAK,iBAAiB,SAAS,MAAM,KAAK,aAAa,OAAO,OAAO,KAAK,CAAC;AAC3E,YAAM,YAAY,IAAI;AAAA,IACxB;AAEA,YAAQ,YAAY,UAAU;AAC9B,YAAQ,YAAY,KAAK;AAGzB,SAAK,gBAAgB,GAAG,OAAO,EAAE,OAAO,UAAU,CAAC;AAEnD,SAAK,KAAK,YAAY,MAAM;AAC5B,SAAK,KAAK,YAAY,OAAO;AAC7B,SAAK,KAAK,YAAY,KAAK,aAAa;AACxC,eAAW,YAAY,KAAK,IAAI;AAGhC,SAAK,IAAI,GAAG,gBAAgB,CAAC,SAAS;AACpC,aAAO,KAAK,KAAK,IAAI,KAAK,MAAM;AAAA,IAClC,CAAC;AAGD,eAAW,iBAAiB,WAAW,CAAC,MAAM;AAC5C,UAAK,EAAoB,QAAQ,YAAY,KAAK,OAAQ,MAAK,MAAM;AAAA,IACvE,CAAC;AAGD,SAAK,iBAAiB,CAAC,MAAmB;AACxC,WAAK,iBAAiB,EAAE,OAAO,UAAU;AAAA,IAC3C;AACA,aAAS,iBAAiB,mBAAmB,KAAK,aAAa;AAAA,EACjE;AAAA,EAtGmB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAfX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB,oBAAI,IAAY,CAAC,KAAK,CAAC;AAAA,EACvC,YAAgC,CAAC;AAAA,EACjC,SAAS;AAAA,EACT,gBAAsD;AAAA,EA4GtD;AAAA,EAER,MAAM,OAAsB;AAC1B,QAAI,KAAK,OAAQ;AACjB,SAAK,SAAS;AACd,SAAK,KAAK,UAAU,IAAI,gBAAgB;AACxC,SAAK,IAAI,KAAK,MAAM;AACpB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAAA,EAEA,QAAc;AACZ,QAAI,CAAC,KAAK,OAAQ;AAClB,SAAK,SAAS;AACd,SAAK,KAAK,UAAU,OAAO,gBAAgB;AAC3C,SAAK,IAAI,KAAK,OAAO;AAAA,EACvB;AAAA,EAEQ,cAAoB;AAC1B,SAAK,cAAc,gBAAgB;AACnC,UAAM,UAAU,GAAG,OAAO,EAAE,OAAO,aAAa,CAAC;AACjD,UAAM,UAAU,GAAG,OAAO,EAAE,OAAO,aAAa,CAAC;AACjD,YAAQ,YAAY,OAAO;AAC3B,SAAK,cAAc,YAAY,OAAO;AAAA,EACxC;AAAA,EAEQ,YAAkB;AACxB,SAAK,cAAc,gBAAgB;AACnC,UAAM,QAAQ,GAAG,OAAO,EAAE,OAAO,WAAW,CAAC;AAC7C,UAAM,OAAO,GAAG,OAAO,EAAE,OAAO,gBAAgB,CAAC;AACjD,YAAQ,MAAM,sBAAsB;AACpC,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,YAAY;AACrB,aAAS,MAAM,YAAY;AAC3B,YAAQ,UAAU,cAAW;AAC7B,aAAS,iBAAiB,SAAS,MAAM,KAAK,cAAc,CAAC;AAC7D,UAAM,YAAY,IAAI;AACtB,UAAM,YAAY,QAAQ;AAC1B,SAAK,cAAc,YAAY,KAAK;AAAA,EACtC;AAAA,EAEA,MAAc,gBAA+B;AAC3C,UAAM,SAAS,KAAK,YAAY,MAAM,KAAK,KAAK;AAChD,UAAM,aAAa,KAAK,cAAc,IAAI,KAAK,IAAI,SAAa,MAAM,KAAK,KAAK,aAAa,EAAE,CAAC;AAEhG,UAAM,UAAmE,EAAE,OAAO,GAAG;AACrF,QAAI,WAAY,SAAQ,OAAO;AAC/B,QAAI,OAAQ,SAAQ,SAAS;AAG7B,UAAM,aAAa,KAAK,UAAU,SAAS;AAC3C,QAAI,CAAC,WAAY,MAAK,YAAY;AAElC,QAAI;AACF,YAAM,EAAE,UAAU,IAAI,MAAM,KAAK,UAAU,aAAa,KAAK,aAAa,OAAO;AACjF,WAAK,YAAY;AACjB,WAAK,WAAW;AAChB,WAAK,QAAQ,OAAO,SAAS;AAAA,IAC/B,SAAS,OAAO;AACd,UAAI,CAAC,WAAY,MAAK,UAAU;AAChC,WAAK,IAAI,KAAK,kBAAkB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IAC3F;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,SAAK,cAAc,gBAAgB;AAEnC,QAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,YAAM,QAAQ,GAAG,OAAO,EAAE,OAAO,WAAW,CAAC;AAC7C,YAAM,YAAY,GAAG,OAAO,EAAE,OAAO,gBAAgB,CAAC;AACtD,cAAQ,WAAW,+BAA+B;AAClD,YAAM,YAAY,SAAS;AAC3B,WAAK,cAAc,YAAY,KAAK;AACpC;AAAA,IACF;AAEA,SAAK,UAAU,QAAQ,CAAC,UAAUC,WAAU;AAC1C,YAAM,OAAO,KAAK,WAAW,UAAUA,SAAQ,CAAC;AAEhD,WAAK,MAAM,YAAY,eAAe,OAAOA,MAAK,CAAC;AACnD,WAAK,cAAc,YAAY,IAAI;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEQ,WAAW,UAA4B,QAA6B;AAC1E,UAAM,aAAa,SAAS,WAAW;AACvC,UAAM,YAAY,aAAa,SAAS,MAAM,KAAK,MAAM;AAEzD,UAAM,OAAO,GAAG,OAAO;AAAA,MACrB,OAAO,WAAW,aAAa,sBAAsB,EAAE;AAAA,IACzD,CAAC;AACD,SAAK,QAAQ,aAAa,SAAS;AAGnC,UAAM,MAAM,GAAG,OAAO,EAAE,OAAO,cAAc,CAAC;AAC9C,QAAI,MAAM,aAAa,aAAa,YAAY;AAGhD,UAAM,OAAO,GAAG,OAAO,EAAE,OAAO,eAAe,CAAC;AAGhD,UAAM,SAAS,GAAG,OAAO,EAAE,OAAO,iBAAiB,CAAC;AAEpD,UAAM,MAAM,GAAG,QAAQ,EAAE,OAAO,iBAAiB,CAAC;AAClD,YAAQ,KAAK,IAAI,MAAM,EAAE;AAEzB,UAAM,QAAQ,GAAG,QAAQ,EAAE,OAAO,WAAW,CAAC;AAC9C,UAAM,SAAS,eAAe,SAAS,MAAM,KAAK,MAAM;AACxD,UAAM,MAAM,aAAa;AACzB,UAAM,MAAM,QAAQ;AACpB,YAAQ,OAAO,YAAY,SAAS,IAAI,KAAK,SAAS,IAAI;AAE1D,UAAM,OAAO,GAAG,QAAQ,EAAE,OAAO,eAAe,CAAC;AACjD,YAAQ,MAAM,mBAAmB,SAAS,SAAS,CAAC;AAEpD,WAAO,YAAY,GAAG;AACtB,WAAO,YAAY,KAAK;AACxB,WAAO,YAAY,IAAI;AAGvB,UAAM,UAAU,GAAG,OAAO,EAAE,OAAO,kBAAkB,CAAC;AACtD,YAAQ,SAAS,SAAS,OAAO;AAGjC,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,YAAY;AACtB,YAAQ,WAAW,WAAW;AAC9B,cAAU,MAAM,UAAU;AAC1B,cAAU,aAAa,iBAAiB,OAAO;AAC/C,cAAU,iBAAiB,SAAS,CAAC,MAAM;AACzC,QAAE,gBAAgB;AAClB,YAAM,aAAa,QAAQ,UAAU,OAAO,2BAA2B;AACvE,cAAQ,WAAW,aAAa,eAAe,WAAW;AAC1D,gBAAU,aAAa,iBAAiB,OAAO,UAAU,CAAC;AAAA,IAC5D,CAAC;AAGD,0BAAsB,MAAM;AAC1B,UAAI,QAAQ,eAAe,QAAQ,cAAc;AAC/C,kBAAU,MAAM,UAAU;AAAA,MAC5B;AAAA,IACF,CAAC;AAGD,UAAM,SAAS,GAAG,OAAO,EAAE,OAAO,iBAAiB,CAAC;AAEpD,UAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,eAAW,YAAY;AACvB,QAAI,YAAY;AACd,iBAAW,YAAY,SAAS,SAAS,CAAC;AAC1C,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,cAAQ,MAAM,UAAU;AACxB,iBAAW,YAAY,IAAI;AAAA,IAC7B,OAAO;AACL,iBAAW,YAAY,SAAS,UAAU,CAAC;AAC3C,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,cAAQ,MAAM,cAAW;AACzB,iBAAW,YAAY,IAAI;AAAA,IAC7B;AACA,eAAW,iBAAiB,SAAS,OAAO,MAAM;AAChD,QAAE,gBAAgB;AAClB,YAAM,KAAK,cAAc,UAAU,UAAU;AAAA,IAC/C,CAAC;AAED,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,YAAY;AACtB,cAAU,YAAY,SAAS,UAAU,CAAC;AAC1C,UAAM,cAAc,SAAS,cAAc,MAAM;AACjD,YAAQ,aAAa,YAAY;AACjC,cAAU,YAAY,WAAW;AACjC,cAAU,iBAAiB,SAAS,OAAO,MAAM;AAC/C,QAAE,gBAAgB;AAClB,YAAM,KAAK,eAAe,UAAU,SAAS;AAAA,IAC/C,CAAC;AAED,WAAO,YAAY,UAAU;AAC7B,WAAO,YAAY,SAAS;AAE5B,SAAK,YAAY,MAAM;AACvB,SAAK,YAAY,OAAO;AACxB,SAAK,YAAY,SAAS;AAC1B,SAAK,YAAY,MAAM;AAEvB,SAAK,YAAY,GAAG;AACpB,SAAK,YAAY,IAAI;AAGrB,SAAK,iBAAiB,cAAc,MAAM;AACxC,WAAK,QAAQ,UAAU,SAAS,EAAE;AAAA,IACpC,CAAC;AAGD,SAAK,iBAAiB,SAAS,MAAM;AACnC,UAAI,SAAS,YAAY,SAAS,GAAG;AACnC,cAAM,MAAM,SAAS,YAAY,CAAC;AAClC,eAAO,SAAS,EAAE,MAAM,IAAI,SAAS,KAAK,IAAI,SAAS,UAAU,SAAS,CAAC;AAC3E,aAAK,QAAQ,aAAa,QAAQ;AAAA,MACpC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eAAe,UAA4B,KAAuC;AAC9F,QAAI,WAAW;AACf,QAAI;AACF,YAAM,KAAK,UAAU,eAAe,SAAS,EAAE;AAC/C,WAAK,IAAI,KAAK,oBAAoB,SAAS,EAAE;AAC7C,YAAM,KAAK,cAAc;AAAA,IAC3B,SAAS,OAAO;AACd,UAAI,WAAW;AACf,WAAK,IAAI,KAAK,kBAAkB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IAC3F;AAAA,EACF;AAAA,EAEA,MAAc,mBAAkC;AAC9C,UAAM,YAAY,MAAM,KAAK;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,UAAW;AAEhB,SAAK,aAAa,WAAW;AAC7B,QAAI;AACF,YAAM,KAAK,UAAU,mBAAmB,KAAK,WAAW;AACxD,WAAK,IAAI,KAAK,sBAAsB;AACpC,YAAM,KAAK,cAAc;AAAA,IAC3B,SAAS,OAAO;AACd,WAAK,IAAI,KAAK,kBAAkB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IAC3F,UAAE;AACA,WAAK,aAAa,WAAW;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,kBAAkB,OAAe,SAAmC;AAC1E,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,WAAW,GAAG,OAAO,EAAE,OAAO,sBAAsB,CAAC;AAE3D,YAAM,UAAU,oBAAoB,KAAK,IAAI,CAAC;AAC9C,YAAM,YAAY,kBAAkB,KAAK,IAAI,CAAC;AAE9C,YAAM,SAAS,GAAG,OAAO,EAAE,OAAO,oBAAoB,CAAC;AACvD,aAAO,aAAa,QAAQ,aAAa;AACzC,aAAO,aAAa,cAAc,MAAM;AACxC,aAAO,aAAa,mBAAmB,OAAO;AAC9C,aAAO,aAAa,oBAAoB,SAAS;AAEjD,YAAM,UAAU,GAAG,OAAO,EAAE,OAAO,mBAAmB,CAAC;AACvD,cAAQ,KAAK;AACb,cAAQ,SAAS,KAAK;AAEtB,YAAM,YAAY,GAAG,OAAO,EAAE,OAAO,qBAAqB,CAAC;AAC3D,gBAAU,KAAK;AACf,cAAQ,WAAW,OAAO;AAE1B,YAAM,SAAS,GAAG,OAAO,EAAE,OAAO,qBAAqB,CAAC;AAExD,YAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,gBAAU,OAAO;AACjB,gBAAU,YAAY;AACtB,cAAQ,WAAW,SAAS;AAE5B,YAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,iBAAW,OAAO;AAClB,iBAAW,YAAY;AACvB,cAAQ,YAAY,WAAW;AAE/B,UAAI,SAAS;AACb,YAAM,QAAQ,CAAC,WAAoB;AACjC,YAAI,OAAQ;AACZ,iBAAS;AACT,iBAAS,oBAAoB,WAAW,SAAS;AACjD,iBAAS,MAAM,UAAU;AACzB,eAAO,MAAM,YAAY;AACzB,mBAAW,MAAM;AACf,mBAAS,OAAO;AAChB,kBAAQ,MAAM;AAAA,QAChB,GAAG,GAAG;AAAA,MACR;AAGA,YAAM,YAAY,CAAC,MAAa;AAC9B,cAAM,KAAK;AACX,YAAI,GAAG,QAAQ,UAAU;AACvB,gBAAM,KAAK;AACX;AAAA,QACF;AACA,YAAI,GAAG,QAAQ,OAAO;AACpB,aAAG,eAAe;AAClB,gBAAM,SAAU,SAAS,YAAY,EAAiB;AACtD,cAAI,WAAW,WAAW;AACxB,uBAAW,MAAM;AAAA,UACnB,OAAO;AACL,sBAAU,MAAM;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AACA,eAAS,iBAAiB,WAAW,SAAS;AAE9C,gBAAU,iBAAiB,SAAS,MAAM,MAAM,KAAK,CAAC;AACtD,iBAAW,iBAAiB,SAAS,MAAM,MAAM,IAAI,CAAC;AACtD,eAAS,iBAAiB,SAAS,CAAC,MAAM;AACxC,YAAI,EAAE,WAAW,SAAU,OAAM,KAAK;AAAA,MACxC,CAAC;AAED,aAAO,YAAY,SAAS;AAC5B,aAAO,YAAY,UAAU;AAC7B,aAAO,YAAY,OAAO;AAC1B,aAAO,YAAY,SAAS;AAC5B,aAAO,YAAY,MAAM;AACzB,eAAS,YAAY,MAAM;AAE3B,WAAK,KAAK,YAAY,aAAa,aAC9B,KAAK,KAAK,YAAY,EAAiB,YAAY,QAAQ,IAC5D,KAAK,KAAK,YAAY,QAAQ;AAElC,4BAAsB,MAAM;AAC1B,iBAAS,MAAM,UAAU;AACzB,eAAO,MAAM,YAAY;AACzB,kBAAU,MAAM;AAAA,MAClB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,cAAc,UAA4B,KAAuC;AAE7F,QAAI,WAAW;AACf,QAAI;AACF,YAAM,cAAc,SAAS,WAAW;AACxC,YAAM,KAAK,UAAU,gBAAgB,SAAS,IAAI,WAAW;AAC7D,YAAM,KAAK,cAAc;AAAA,IAC3B,SAAS,OAAO;AACd,UAAI,WAAW;AACf,WAAK,IAAI,KAAK,kBAAkB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IAC3F;AAAA,EACF;AAAA,EAEQ,aAAa,OAAe,WAA8B;AAEhE,SAAK,cAAc,MAAM;AACzB,SAAK,cAAc,IAAI,KAAK;AAG5B,UAAM,QAAQ,UAAU,iBAAoC,UAAU;AACtE,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,KAAK,cAAc,IAAI,KAAK,QAAQ,UAAU,EAAE;AACjE,WAAK,UAAU,OAAO,mBAAmB,QAAQ;AAAA,IACnD;AAEA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,iBAAiB,YAA0B;AACzC,UAAM,YAAY,IAAI,OAAO,UAAU;AACvC,UAAM,OAAO,KAAK,cAAc,cAA2B,sBAAsB,SAAS,IAAI;AAC9F,QAAI,MAAM;AACR,WAAK,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS,CAAC;AAC3D,WAAK,UAAU,IAAI,eAAe;AAClC,WAAK;AAAA,QACH;AAAA,QACA,MAAM;AACJ,eAAK,UAAU,OAAO,eAAe;AAAA,QACvC;AAAA,QACA,EAAE,MAAM,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,cAAc;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AACvD,aAAS,oBAAoB,mBAAmB,KAAK,aAAa;AAClE,SAAK,KAAK,OAAO;AAAA,EACnB;AACF;;;AC7fA,IAAM,gBAAgB;AAGtB,IAAM,gBAAgB;AAGtB,IAAM,mBAAmB;AAGzB,IAAM,iBAAiB;AAEhB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCA0EG,aAAa;AAAA;AAAA;AAAA;AAAA,oCAIT,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAQlB,cAAc;AAAA;AAAA;AAAA;AAAA,kCAId,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAWd,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAYtB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCA+BN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCA4Bb,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC9K3C,SAAS,YAAY,QAA6B;AACvD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAWD,aAAa,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["attr","attr","config","id","config","id","window","el","index","index","config","config"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siteping/widget",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Feedback widget for client review during development — annotations, bugs, questions directly on the site",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.cjs"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"check": "tsc --noEmit",
|
|
22
|
+
"clean": "rm -rf dist"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"feedback",
|
|
26
|
+
"widget",
|
|
27
|
+
"annotation",
|
|
28
|
+
"client-review",
|
|
29
|
+
"development"
|
|
30
|
+
],
|
|
31
|
+
"author": "neosianexus",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"homepage": "https://github.com/NeosiaNexus/siteping/tree/main/packages/widget",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/NeosiaNexus/siteping.git",
|
|
37
|
+
"directory": "packages/widget"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@medv/finder": "^3.2.0",
|
|
41
|
+
"@siteping/core": "workspace:*"
|
|
42
|
+
}
|
|
43
|
+
}
|