@loupekit/sdk 0.13.1 → 0.14.0-next.81

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/styles.ts","../src/fingerprint.ts","../../../node_modules/modern-screenshot/dist/index.mjs","../src/capture.ts","../../shared/dist/activity.js","../../shared/dist/lifecycle.js","../../shared/dist/iteration.js","../../shared/dist/consent.js","../../shared/dist/thread.js","../../shared/dist/timeline.js","../../shared/dist/mentions.js","../../shared/dist/needs-you.js","../../shared/dist/reactions.js","../../shared/dist/presence.js","../../shared/dist/companion-tray.js","../../shared/dist/index.js","../src/store.ts","../src/http-adapter.ts","../src/app.ts","../src/connect.ts","../src/index.ts"],"sourcesContent":["// Scoped to the Shadow DOM — none of this leaks to (or is affected by) the host page.\nexport const STYLES = /* css */ `\n:host { all: initial; }\n* { box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif; }\n\n/* Theme tokens live on :host (inside the Shadow DOM :root matches nothing).\n Dark is the default; the host element gets .theme-light to flip to light. */\n:host {\n --accent: #6b73e6;\n --accent-soft: rgba(107, 115, 230, 0.12);\n --pin: #ff5842;\n --bg: #14161d;\n --bg-2: #1b1e27;\n --bg-3: #262a36;\n --ink: #e7e9f0;\n --muted: #9aa0af;\n --line: #2b2f3b;\n --shadow: 0 12px 48px rgba(0,0,0,.42);\n}\n:host(.theme-light) {\n --accent: #4a55d6;\n --accent-soft: rgba(74, 85, 214, 0.12);\n --pin: #ff5842;\n --bg: #ffffff;\n --bg-2: #f6f7fb;\n --bg-3: #eceef4;\n --ink: #16181f;\n --muted: #6b7180;\n --line: #e2e5ee;\n --shadow: 0 12px 40px rgba(0,0,0,.22);\n}\n\n.overlay { position: fixed; inset: 0; z-index: 2147483000; pointer-events: none; }\n\n/* inspector highlight */\n.hl {\n position: fixed; pointer-events: none; z-index: 2147483001;\n border: 2px solid var(--accent);\n background: var(--accent-soft);\n border-radius: 4px; display: none;\n transition: all 60ms linear;\n}\n.hl .tip {\n position: absolute; top: -24px; left: 0; background: var(--accent); color: #fff;\n font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 4px; white-space: nowrap;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n/* region selection (during drag) + active-comment outline */\n.selbox {\n position: fixed; pointer-events: none; z-index: 2147483001; display: none;\n border: 2px dashed var(--accent); background: var(--accent-soft); border-radius: 4px;\n}\n.region-box {\n position: fixed; pointer-events: none; z-index: 2147483001; display: none;\n border: 2px solid var(--pin); border-radius: 4px;\n box-shadow: 0 0 0 2px rgba(255, 88, 66, .25), 0 4px 16px rgba(0,0,0,.25);\n}\n\n/* pins */\n.pin {\n position: fixed; pointer-events: auto; z-index: 2147483002;\n width: 26px; height: 26px; border-radius: 50% 50% 50% 2px;\n background: var(--pin); color: #fff; border: 2px solid #fff;\n font-size: 12px; font-weight: 700; cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,.35);\n display: grid; place-items: center; transform: translate(-4px, -4px);\n transition: transform 80ms ease;\n}\n.pin:hover { transform: translate(-4px, -4px) scale(1.12); }\n.pin.detached { background: #9aa0af; }\n.pin.done { background: #10935a; }\n.pin.free { background: var(--accent); border-radius: 50% 50% 2px 50%; }\n.pin.free.done { background: #10935a; }\n.pin.active { outline: 3px solid rgba(107,115,230,.45); }\n/* The quick-action \"Markers\" toggle hides every pin without discarding it.\n !important beats the inline display the pin positioner sets on each frame. */\n.overlay.hide-pins .pin { display: none !important; }\n\n/* --------------------------------------------------------------- FAB cluster */\n/* The collapsed state: a primary brand button (with the comment count) plus the\n quick actions that expand out of it. Replaces the old single launcher. */\n.fab-cluster {\n position: fixed; z-index: 2147483003; bottom: 20px; right: 20px;\n display: none; flex-direction: column; align-items: flex-end; gap: 10px;\n}\n.fab-cluster.show { display: flex; }\n/* The way back on a touch screen once the launcher is hidden (no keyboard for Alt+Shift+L):\n a slim tab on the right edge, shown only while the panel is closed. */\n.fab-handle {\n position: fixed; z-index: 2147483003; right: 0; bottom: 96px; width: 12px; height: 56px;\n display: none; padding: 0; border: 0; border-radius: 8px 0 0 8px;\n background: var(--accent); opacity: .6; cursor: pointer; touch-action: manipulation;\n}\n.fab-handle.show { display: block; }\n.fab-handle:hover, .fab-handle:focus-visible { opacity: 1; }\n/* A dragged launcher is anchored to its nearest edges (JS sets left/right/top/bottom),\n and the quick actions grow INTO the page: downward from the upper half, labels to the\n right from the left half. */\n.fab-cluster.at-top { flex-direction: column-reverse; }\n.fab-cluster.at-left, .fab-cluster.at-left .fab-minis { align-items: flex-start; }\n.fab-cluster.at-left .fab-mini .fab-tip { right: auto; left: calc(100% + 8px); }\n.fab-cluster.dragging .launcher { cursor: grabbing; border-color: var(--accent); }\n.fab-cluster.dragging .fab-mini .fab-tip { display: none; }\n\n.fab-minis { display: none; flex-direction: column; align-items: flex-end; gap: 10px; }\n.fab-cluster.expanded .fab-minis { display: flex; }\n.fab-cluster.expanded .fab-minis .fab-mini { animation: loupe-fab-in 180ms cubic-bezier(.16, 1, .3, 1) both; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(1) { animation-delay: 0ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(2) { animation-delay: 30ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(3) { animation-delay: 60ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(4) { animation-delay: 90ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(5) { animation-delay: 120ms; }\n@keyframes loupe-fab-in { from { opacity: 0; transform: translateY(8px) scale(.9); } to { opacity: 1; transform: none; } }\n.fab-cluster.at-top.expanded .fab-minis .fab-mini { animation-name: loupe-fab-in-down; }\n@keyframes loupe-fab-in-down { from { opacity: 0; transform: translateY(-8px) scale(.9); } to { opacity: 1; transform: none; } }\n\n.fab-mini {\n position: relative; width: 40px; height: 40px; border-radius: 50%; padding: 0;\n border: 1px solid var(--line); background: var(--bg); color: var(--ink);\n cursor: pointer; display: inline-flex; align-items: center; justify-content: center;\n box-shadow: var(--shadow);\n}\n.fab-mini:hover { border-color: var(--accent); color: var(--accent); }\n.fab-mini.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.fab-mini.on:hover { color: #fff; }\n.fab-mini svg { display: block; width: 16px; height: 16px; }\n/* The action's label, revealed on hover so the collapsed cluster stays calm. */\n.fab-mini .fab-tip {\n position: absolute; right: calc(100% + 8px); top: 50%; transform: translateY(-50%);\n background: var(--bg); color: var(--ink); border: 1px solid var(--line);\n border-radius: 7px; padding: 4px 8px; font-size: 11px; font-weight: 600; white-space: nowrap;\n box-shadow: var(--shadow); opacity: 0; pointer-events: none; transition: opacity 120ms ease;\n}\n.fab-mini:hover .fab-tip { opacity: 1; }\n\n/* The launcher and its chevron share a box so the chevron can sit on the launcher's\n corner while being its own button (tap = quick actions; the launcher = open). */\n.fab-main { position: relative; display: inline-flex; }\n.launcher {\n position: relative; width: 46px; height: 46px; border-radius: 50%; padding: 0;\n border: 1px solid var(--line); background: var(--bg-2); color: var(--ink);\n cursor: grab; display: inline-flex; align-items: center; justify-content: center;\n box-shadow: var(--shadow);\n touch-action: none; user-select: none; -webkit-user-select: none; /* drag with a finger too */\n}\n.launcher:hover { border-color: var(--accent); }\n.launcher:active { cursor: grabbing; }\n.launcher .logo { font-size: 24px; line-height: 1; color: var(--accent); }\n/* Chevron pinned to the corner: up = actions are tucked away, down = they are out. */\n.fab-more {\n position: absolute; right: -3px; bottom: -3px; width: 20px; height: 20px; border-radius: 50%;\n padding: 0; cursor: pointer; z-index: 1;\n background: var(--bg); border: 1px solid var(--line); color: var(--muted);\n display: grid; place-items: center; transition: transform 160ms cubic-bezier(.16, 1, .3, 1);\n}\n.fab-more:hover { border-color: var(--accent); color: var(--accent); }\n.fab-more .lchev { display: grid; place-items: center; }\n.fab-more svg { width: 11px; height: 11px; display: block; }\n.fab-cluster.expanded .fab-more { transform: rotate(180deg); }\n.fab-cluster.at-top .fab-more { bottom: auto; top: -3px; transform: rotate(180deg); }\n.fab-cluster.at-top.expanded .fab-more { transform: none; }\n.launcher .lcount {\n position: absolute; top: -5px; right: -5px; background: var(--pin); color: #fff;\n font-size: 10px; font-weight: 700; line-height: 1; border-radius: 999px; padding: 3px 6px;\n border: 2px solid var(--bg);\n}\n.launcher .lcount:empty { display: none; }\n@media (prefers-reduced-motion: reduce) {\n .fab-cluster.expanded .fab-minis .fab-mini { animation: none; }\n .launcher .lchev { transition: none; }\n .fab-mini .fab-tip { transition: none; }\n}\n\n/* --------------------------------------------------------------------- dock */\n/* The control panel. One container, four dock modes (left/right/bottom/float),\n overlaying the host page (never reflows it). */\n.dock {\n position: fixed; z-index: 2147483003; pointer-events: auto;\n display: none; flex-direction: column;\n background: var(--bg); color: var(--ink);\n border: 1px solid var(--line); box-shadow: var(--shadow);\n overflow: hidden; font-size: 13px;\n}\n.dock.open { display: flex; }\n.dock.mode-right { top: 0; right: 0; bottom: 0; width: 360px; border-width: 0 0 0 1px; }\n.dock.mode-left { top: 0; left: 0; bottom: 0; width: 360px; border-width: 0 1px 0 0; }\n.dock.mode-bottom { left: 0; right: 0; bottom: 0; height: 320px; border-width: 1px 0 0 0; }\n.dock.mode-float { border-radius: 14px; /* left/top/width/height set inline */ }\n\n/* header: brand + dock controls */\n.dhead {\n display: flex; align-items: center; gap: 8px; flex: none;\n padding: 8px 10px; border-bottom: 1px solid var(--line); background: var(--bg-2);\n}\n.dock.mode-float .dhead { cursor: grab; }\n.dock.mode-float.dragging .dhead { cursor: grabbing; }\n.dock.dragging { user-select: none; }\n.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; letter-spacing: -.01em; }\n.brand .logo { font-size: 16px; line-height: 1; color: var(--accent); flex: none; }\n.brand .title { font-size: 13px; }\n.dctl { display: flex; align-items: center; gap: 2px; margin-left: auto; }\n/* Only the header's own icon buttons. The position and settings popovers live inside\n .dctl too, and a bare .dctl button squeezed their rows and swatches to 26px. */\n.dctl > button, .dctl > .menu-wrap > button {\n display: inline-flex; align-items: center; justify-content: center;\n width: 26px; height: 26px; padding: 0; border: 0; border-radius: 6px;\n background: transparent; color: var(--muted); cursor: pointer;\n}\n.dctl > button:hover, .dctl > .menu-wrap > button:hover { background: var(--bg-3); color: var(--ink); }\n.dctl > button.on, .dctl > .menu-wrap > button.on { background: var(--bg-3); color: var(--accent); }\n.dctl svg { display: block; }\n.dctl .gap { width: 1px; height: 16px; background: var(--line); margin: 0 4px; flex: none; }\n\n/* tools row */\n.tools { display: flex; gap: 6px; flex: none; padding: 10px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }\n.tools button {\n display: flex; align-items: center; gap: 6px; padding: 7px 10px; line-height: 1;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2); color: var(--ink);\n font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.tools button:hover { background: var(--bg-3); }\n.tools button.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.tools .ico { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; }\n.tools .ico svg { width: 15px; height: 15px; display: block; }\n\n/* list */\n.listhead {\n display: flex; align-items: center; gap: 8px; flex: none; padding: 12px 12px 6px;\n font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700;\n}\n.count { background: var(--pin); color: #fff; font-size: 11px; font-weight: 700; line-height: 1; border-radius: 999px; padding: 3px 7px; }\n.list { flex: 1; overflow-y: auto; padding: 6px 10px 12px; display: flex; flex-direction: column; gap: 8px; }\n.empty { color: var(--muted); font-size: 13px; padding: 24px 12px; text-align: center; line-height: 1.5; }\n/* bottom dock lays the list out in flowing columns so it isn't a tall single strip */\n.dock.mode-bottom .list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); align-content: start; }\n\n.item { border: 1px solid var(--line); border-radius: 10px; padding: 10px; cursor: pointer; background: var(--bg-2); }\n.item:hover { border-color: var(--accent); }\n/* The header row now carries the number, a detached badge, a lifecycle chip, a PR\n chip, a checks meter and the caret — more than fits on one line in a narrow\n panel, so it wraps rather than clipping the last chip. The caret keeps its place\n at the end of the row. */\n.item .top { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; margin-bottom: 6px; }\n.item .top .caret { margin-left: auto; }\n.item .num { background: var(--pin); color: #fff; width: 20px; height: 20px; border-radius: 50%; font-size: 11px; font-weight: 700; display: grid; place-items: center; flex: none; }\n.item .num.detached { background: #9aa0af; }\n.item .num.done { background: #10935a; }\n/* Author + absolute time, visible collapsed too. */\n.item .who { display: flex; flex-wrap: wrap; gap: 0 4px; font-size: 11.5px; color: var(--muted); margin-top: 3px; }\n.item .who b { color: var(--ink); font-weight: 600; }\n.item .who time { font-variant-numeric: tabular-nums; white-space: nowrap; }\n.item .device { font-size: 10px; color: var(--muted); background: var(--bg-3); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }\n.item .body { font-size: 13px; line-height: 1.4; }\n.item .meta { font-size: 11px; color: var(--muted); margin-top: 6px; font-family: ui-monospace, Menlo, monospace; word-break: break-all; }\n.item .badge { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 1px 6px; border-radius: 5px; margin-left: auto; white-space: nowrap; }\n.badge.detached { background: var(--bg-3); color: var(--muted); }\n.badge.done { background: #d8f0e4; color: #10935a; }\n.item .actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }\n.item .actions button { font-size: 11px; border: 1px solid var(--line); background: var(--bg-3); border-radius: 6px; padding: 4px 8px; cursor: pointer; color: var(--ink); }\n.item .actions button:hover { border-color: var(--accent); }\n.item img.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); }\n.item video.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); }\n.item .caret { margin-left: auto; color: var(--muted); font-size: 11px; }\n.item .summary { font-size: 13px; font-weight: 600; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.item .detail { margin-top: 6px; }\n.item.collapsed .detail { display: none; }\n.listhead .search {\n margin-left: auto; flex: 1; max-width: 170px; font-size: 12px; text-transform: none; letter-spacing: 0;\n padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--bg-2); color: var(--ink); outline: none;\n}\n.listhead .search:focus { border-color: var(--accent); }\n\n/* float resize grip (bottom-right corner) */\n.resize { display: none; position: absolute; right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize; z-index: 1; }\n.dock.mode-float .resize { display: block; }\n.resize::after {\n content: \"\"; position: absolute; right: 3px; bottom: 3px; width: 7px; height: 7px;\n border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); opacity: .7;\n}\n\n/* composer popover */\n.composer {\n position: fixed; z-index: 2147483004; pointer-events: auto; width: 320px;\n background: var(--bg); color: var(--ink); border: 1px solid var(--line);\n border-radius: 12px; box-shadow: var(--shadow); padding: 12px; display: none;\n}\n.composer .target {\n font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--accent);\n background: var(--bg-2); border-radius: 6px; padding: 5px 8px; margin-bottom: 8px;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.composer textarea {\n width: 100%; min-height: 68px; resize: vertical; border: 1px solid var(--line);\n border-radius: 8px; padding: 8px; font-size: 13px; color: var(--ink); background: var(--bg-2); outline: none;\n}\n.composer textarea:focus { border-color: var(--accent); }\n.composer .row { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; gap: 8px; }\n.composer label.chk { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; cursor: pointer; }\n.composer .btns { display: flex; gap: 6px; }\n.composer button { border: 0; border-radius: 8px; font-size: 13px; font-weight: 600; padding: 7px 12px; cursor: pointer; }\n.composer .primary { background: var(--accent); color: #fff; }\n.composer .primary:disabled { opacity: .5; cursor: default; }\n.composer .ghost { background: var(--bg-3); color: var(--ink); }\n.composer input.title {\n width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 8px; margin-bottom: 8px;\n font-size: 13px; font-weight: 600; color: var(--ink); background: var(--bg-2); outline: none;\n}\n.composer input.title:focus { border-color: var(--accent); }\n.composer .attach { margin-top: 8px; }\n.composer .pick {\n width: 100%; border: 1px dashed var(--line); background: transparent; color: var(--muted);\n border-radius: 8px; padding: 7px; font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.composer .pick:hover { border-color: var(--accent); color: var(--accent); }\n.composer .chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }\n.composer .chip {\n display: inline-flex; align-items: center; gap: 4px; max-width: 100%;\n background: var(--bg-3); border-radius: 6px; padding: 2px 4px 2px 7px; font-size: 11px; color: var(--ink);\n}\n.composer .chip .x { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 13px; line-height: 1; padding: 0 2px; }\n.composer .err { color: var(--pin); font-size: 11px; margin-top: 4px; }\n.composer .err:empty { display: none; }\n\n/* Priority + change-type pickers, side by side under the attachments. */\n.composer .meta2 { display: flex; gap: 6px; margin-top: 8px; }\n.composer select.mini {\n flex: 1; min-width: 0; font-size: 12px; padding: 6px 7px; border-radius: 7px;\n border: 1px solid var(--line); background: var(--bg-2); color: var(--ink); outline: none;\n}\n.composer select.mini:focus { border-color: var(--accent); }\n\n/* ------------------------------------------------------------ sidebar tabs */\n.tabs { display: flex; gap: 4px; flex: none; padding: 8px 10px 0; border-bottom: 1px solid var(--line); }\n.tabs .tab {\n flex: 1; padding: 8px 10px; border: 0; border-bottom: 2px solid transparent;\n background: transparent; color: var(--muted); font-size: 12px; font-weight: 700; cursor: pointer;\n border-radius: 6px 6px 0 0;\n}\n.tabs .tab:hover { color: var(--ink); background: var(--bg-2); }\n.tabs .tab.on { color: var(--accent); border-bottom-color: var(--accent); }\n.tabs .tab.off { opacity: .45; cursor: not-allowed; }\n.tabs .tab.off:hover { color: inherit; background: transparent; }\n\n/* Only the active page shows. Driven by an \"on\" class rather than a .tab-<id>\n selector, so host-registered tab ids need no CSS of their own. */\n.view { display: none; }\n.view.on { display: block; flex: 1; min-height: 0; overflow-y: auto; }\n.view.on.comments-view { display: flex; flex-direction: column; }\n\n/* ------------------------------------------------------------- Home overview */\n.home-view { padding: 12px 12px 18px; }\n.hstat { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }\n.hstat-b {\n display: flex; flex-direction: column; gap: 2px; text-align: left; padding: 10px;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2); color: var(--ink); cursor: pointer;\n}\n.hstat-b:hover { border-color: var(--accent); }\n.hstat-b.on { border-color: var(--accent); background: var(--bg-3); }\n.hstat-n { font-size: 20px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }\n.hstat-l { font-size: 11px; color: var(--muted); }\n.hscope { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.hscope-b {\n flex: 1; padding: 7px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.hscope-b.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.hrefresh {\n flex: none; width: 30px; height: 30px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); cursor: pointer; font-size: 14px;\n}\n.hrefresh:hover { border-color: var(--accent); color: var(--ink); }\n.hpin {\n margin-top: 10px; width: 100%; padding: 9px; border: 0; border-radius: 9px;\n background: var(--accent); color: #fff; font-size: 13px; font-weight: 600; cursor: pointer;\n}\n.hlabel { margin-top: 14px; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700; }\n.hfeed { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; }\n.hfeed-i {\n display: flex; flex-direction: column; gap: 3px; text-align: left; padding: 8px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2); color: var(--ink); cursor: pointer;\n}\n.hfeed-i:hover { border-color: var(--accent); }\n.hfeed-t { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.hfeed-m { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--muted); }\n.hfeed-s { font-weight: 700; }\n.hfeed-s-resolved { color: #34c281; }\n.hfeed-p { font-weight: 700; }\n.hfeed-p-critical { color: var(--pin); }\n.hfeed-p-high { color: #e0a92c; }\n.hempty { padding: 14px; text-align: center; color: var(--muted); font-size: 12px; }\n.hfoot { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 11px; color: var(--muted); text-align: center; }\n\n/* Timeline grouping (project scope) + the repo filter. */\n.daylabel { margin: 8px 2px 0; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700; }\n/* The page a comment belongs to, shown in the project scope (Settings → Page paths). */\n.pathtag {\n padding: 1px 6px; border-radius: 999px; background: var(--bg-3); color: var(--muted);\n font-size: 10.5px; font-family: ui-monospace, Menlo, monospace;\n max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n\n/* recording marker + video in the list */\n.item .rectag { font-size: 10px; font-weight: 700; color: var(--pin); background: var(--bg-3); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }\n.item video.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); background: #000; display: block; }\n\n/* ------------------------------------------------ \"integrates with\" footer */\n.integrations { flex: none; padding: 12px 12px 14px; border-top: 1px solid var(--line); text-align: center; }\n.integrations .ilabel { font-size: 10px; letter-spacing: .12em; color: var(--muted); font-weight: 700; margin-bottom: 8px; }\n.integrations .irow { display: flex; align-items: center; justify-content: center; gap: 14px; }\n.integrations .ibtn { color: var(--muted); display: inline-flex; opacity: .8; cursor: default; }\n.integrations .ibtn:hover { color: var(--accent); opacity: 1; }\n.integrations .ibtn svg { display: block; }\n\n/* ------------------------------------------------------- Connect Claude page */\n.connect-view { padding: 16px 14px 20px; }\n.connect-hero { text-align: center; margin-bottom: 18px; }\n.connect-hero .chero-logo { font-size: 34px; line-height: 1; color: var(--accent); }\n.connect-hero .chero-title { font-size: 18px; font-weight: 800; letter-spacing: -.02em; margin-top: 8px; }\n.connect-hero .chero-sub { font-size: 12.5px; color: var(--muted); line-height: 1.45; margin-top: 6px; }\n.accentink { color: var(--accent); }\n.connect-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }\n.connect-steps .cstep-t { font-size: 13px; font-weight: 700; }\n.connect-steps .cstep-d { font-size: 12px; color: var(--muted); line-height: 1.45; margin-top: 3px; }\n.connect-steps .cstep-code {\n margin: 8px 0 0; padding: 10px; background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 8px; font-family: ui-monospace, Menlo, monospace; font-size: 11px; line-height: 1.4;\n color: var(--ink); white-space: pre; overflow-x: auto;\n}\n\n/* ------------------------------------------------------- recording indicator */\n.recbar {\n position: fixed; z-index: 2147483005; top: 16px; left: 50%; transform: translateX(-50%);\n display: none; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px;\n background: var(--bg); color: var(--ink); border: 1px solid var(--pin);\n box-shadow: var(--shadow); font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.recbar.show { display: inline-flex; }\n.recbar b { color: var(--pin); }\n.recbar .recdot { width: 9px; height: 9px; border-radius: 50%; background: var(--pin); animation: loupe-recpulse 1.1s infinite; }\n@keyframes loupe-recpulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }\n@media (prefers-reduced-motion: reduce) { .recbar .recdot { animation: none; } }\n\n/* ---------------------------------------------------------------- toast */\n/* A short notice (e.g. how to bring a hidden launcher back). Click to dismiss. */\n.toast {\n position: fixed; z-index: 2147483006; bottom: 24px; left: 50%;\n transform: translateX(-50%) translateY(8px); opacity: 0; pointer-events: none;\n max-width: calc(100vw - 32px); padding: 9px 14px; border-radius: 999px; text-align: center;\n background: var(--bg); color: var(--ink); border: 1px solid var(--line); box-shadow: var(--shadow);\n font-size: 12px; font-weight: 600; line-height: 1.4;\n transition: opacity 160ms ease, transform 160ms ease;\n}\n.toast.show { opacity: 1; transform: translateX(-50%); pointer-events: auto; cursor: pointer; }\n.toast kbd {\n font-family: ui-monospace, Menlo, monospace; font-size: 11px; padding: 1px 5px;\n border: 1px solid var(--line); border-radius: 4px; background: var(--bg-3);\n}\n@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }\n\n/* ---------------------------------------------- header popovers (pos + settings) */\n.menu-wrap { position: relative; }\n.menu {\n position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;\n min-width: 214px; padding: 8px; display: none;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);\n}\n.menu.open { display: block; }\n.menu-label {\n margin: 2px 5px 6px; font-size: 10px; font-weight: 700; letter-spacing: .06em;\n text-transform: uppercase; color: var(--muted);\n}\n/* dock-position grid: the four layouts as a 2x2 of buttons */\n.pos-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n.pos-grid button {\n display: flex; align-items: center; gap: 6px; padding: 7px 8px; cursor: pointer;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg); color: var(--muted);\n font-size: 11.5px; font-weight: 600;\n}\n.pos-grid button:hover { border-color: var(--accent); color: var(--ink); }\n.pos-grid button.on { border-color: var(--accent); color: var(--accent); }\n.pos-grid button svg { width: 14px; height: 14px; flex: none; }\n/* settings rows */\n.menu-row {\n display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;\n padding: 7px 6px; border: 0; border-radius: 8px; background: transparent; color: var(--ink);\n font-size: 12.5px; text-align: left; cursor: pointer;\n}\n.menu-row:hover { background: var(--bg-3); }\n.menu-sep { height: 1px; margin: 6px 4px; background: var(--line); }\n/* on/off switch inside a settings row */\n.sw { flex: none; position: relative; width: 30px; height: 17px; border-radius: 999px; background: var(--line); transition: background .12s; }\n.sw::after { content: \"\"; position: absolute; top: 2px; left: 2px; width: 13px; height: 13px; border-radius: 50%; background: #fff; transition: transform .12s; }\n.menu-row[aria-pressed=\"true\"] .sw { background: var(--accent); }\n.menu-row[aria-pressed=\"true\"] .sw::after { transform: translateX(13px); }\n/* accent swatches */\n.acc-dots { display: flex; gap: 8px; padding: 4px 6px 2px; }\n.acc-dot { width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent; padding: 0; cursor: pointer; }\n.acc-dot.on { border-color: var(--ink); }\n\n/* ---------------------------------------------------------------- minimize bar */\n.minbar { display: none; align-items: center; gap: 8px; padding: 9px 10px; cursor: pointer; background: var(--bg-2); }\n.dock.minimized .minbar { display: flex; }\n.dock.minimized .tabs, .dock.minimized .view, .dock.minimized .resize,\n.dock.minimized .dctl [data-role=\"min\"], .dock.minimized .dctl .menu-wrap { display: none !important; }\n.minbar .logo { color: var(--accent); font-size: 14px; }\n.minbar .mtext { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--muted); }\n.minbar .mtext b { color: var(--ink); }\n.minbar .mrestore { flex: none; padding: 0 2px; border: 0; background: transparent; color: var(--accent); font-size: 14px; cursor: pointer; }\n\n/* ---------------------------------------------------------------- activity monitor */\n.activity-view { padding: 10px 12px 16px; }\n.mon-status { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--ink); }\n.mon-spacer { flex: 1; }\n.mon-live { font-size: 10px; font-weight: 600; color: var(--muted); }\n.mon-live.live { color: #2f9e6a; }\n.mon-live.offline { color: #d9534f; }\n.mon-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex: none; }\n.mon-status.st-working .mon-dot { background: var(--accent); animation: loupe-pulse 1.4s ease-in-out infinite; }\n.mon-status.st-error .mon-dot { background: var(--pin); }\n.mon-status.st-idle .mon-dot { background: var(--muted); }\n@keyframes loupe-pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }\n@media (prefers-reduced-motion: reduce) { .mon-status.st-working .mon-dot { animation: none; } }\n.mon-clear {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.mon-clear:hover { border-color: var(--accent); color: var(--ink); }\n\n.mon-summary { margin-top: 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2); overflow: hidden; }\n.mon-sum-head {\n display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px;\n border: 0; background: transparent; color: var(--ink); text-align: left; cursor: pointer;\n}\n.mon-sum-title { font-size: 12px; font-weight: 700; }\n.mon-sum-peek { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--muted); }\n.mon-caret { color: var(--muted); font-size: 11px; }\n.mon-sum-body { padding: 2px 10px 10px; }\n.mon-kv { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; font-size: 11.5px; color: var(--muted); }\n.mon-kv b { color: var(--ink); font-weight: 600; text-align: right; }\n.mon-preview {\n margin-top: 8px; padding: 7px 8px; border-radius: 7px; background: var(--bg);\n font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--muted);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.mon-micro { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.mon-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }\n.mon-chip {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.mon-chip:hover { border-color: var(--accent); color: var(--ink); }\n.mon-chip.on { border-color: var(--accent); background: var(--accent); color: #fff; }\n.mon-feed {\n margin-top: 8px; max-height: 46vh; overflow-y: auto;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg);\n}\n.mon-row {\n display: grid; grid-template-columns: 58px 88px 1fr; gap: 6px;\n padding: 5px 8px; border-bottom: 1px solid var(--line); font-size: 11px; line-height: 1.4;\n}\n.mon-row:last-child { border-bottom: 0; }\n.mon-time { color: var(--muted); font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; }\n.mon-kind { color: var(--accent); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.mon-label { color: var(--ink); overflow-wrap: anywhere; }\n.mon-detail { display: block; color: var(--muted); font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; overflow-wrap: anywhere; }\n.mon-row.lv-warn .mon-label { color: #e0a92c; }\n.mon-row.lv-error .mon-label { color: var(--pin); }\n.mon-empty { padding: 16px 12px; text-align: center; font-size: 11.5px; line-height: 1.6; color: var(--muted); }\n.mon-empty code { font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--ink); }\n\n/* ---------------------------------------------- project manager (repo + environments) */\n.projbar { display: flex; align-items: center; gap: 8px; margin-top: 12px; position: relative; }\n.proj-label { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--muted); }\n.proj-chip {\n display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; padding: 5px 9px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2);\n color: var(--ink); font-size: 11.5px; font-family: ui-monospace, Menlo, monospace; cursor: pointer;\n}\n.proj-chip:hover { border-color: var(--accent); }\n.proj-chip .proj-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }\n.proj-caret { color: var(--muted); font-family: inherit; }\n.proj-pop {\n position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 25;\n display: none; max-height: 60vh; overflow-y: auto; padding: 10px;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);\n}\n.proj-pop.open { display: block; }\n.pp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.pp-x { padding: 0 4px; border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 12px; line-height: 1; cursor: pointer; }\n.pp-x:hover { background: var(--bg-3); color: var(--ink); }\n.pp-cur { margin-bottom: 8px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.pp-cur b { color: var(--ink); font-family: ui-monospace, Menlo, monospace; }\n.pp-list { display: flex; flex-direction: column; gap: 2px; max-height: 30vh; overflow-y: auto; }\n.pp-proj {\n display: flex; align-items: center; gap: 6px; padding: 5px 8px; border: 1px solid transparent;\n border-radius: 7px; font-size: 11.5px; color: var(--ink);\n}\n.pp-proj.on { border-color: var(--accent); }\n.pp-proj-n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.pp-badge {\n flex: none; padding: 1px 6px; border-radius: 999px; background: var(--bg-3);\n color: var(--muted); font-size: 10px; white-space: nowrap;\n}\n.pp-empty { padding: 8px 6px; font-size: 11px; line-height: 1.5; color: var(--muted); }\n.pp-empty code { font-family: ui-monospace, Menlo, monospace; color: var(--ink); }\n.pp-clear {\n margin-top: 8px; padding: 5px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.pp-clear:hover { border-color: var(--pin); color: var(--pin); }\n.pp-sep { height: 1px; margin: 10px 0; background: var(--line); }\n.pp-env { display: flex; align-items: center; gap: 6px; padding: 4px 6px; border-radius: 7px; }\n.pp-env:hover { background: var(--bg-3); }\n.pp-env-u { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--ink); }\n.pp-add { display: flex; gap: 6px; margin-top: 6px; }\n.pp-env-url {\n flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg); color: var(--ink); font-size: 11.5px;\n}\n.pp-env-url:focus { outline: none; border-color: var(--accent); }\n.pp-add-b {\n flex: none; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.pp-err { margin-top: 6px; font-size: 11px; color: var(--pin); }\n.hver { font-family: ui-monospace, Menlo, monospace; }\n.menu-ver {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n margin: 8px 4px 2px; padding-top: 8px; border-top: 1px solid var(--line);\n font-size: 10.5px; color: var(--muted);\n}\n.menu-ver b { color: var(--ink); font-family: ui-monospace, Menlo, monospace; font-weight: 600; }\n.menu-mode { text-transform: uppercase; letter-spacing: .06em; font-size: 9.5px; }\n/* The host package's version, shown only when it differs from this bundle's (a stale publish). */\n.ver-stale { color: var(--pin); font-family: ui-monospace, Menlo, monospace; font-weight: 600; cursor: help; }\n\n/* ------------------------------------------------ tickets between projects */\n.srcchip, .fwdchip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap; font-size: 10px;\n border: 1px solid var(--line); background: var(--bg); color: var(--muted);\n max-width: 140px; overflow: hidden; text-overflow: ellipsis;\n}\n.fwdchip { border-color: var(--accent); color: var(--accent); }\n.fwdchip.bad { border-color: #d9534f; color: #d9534f; }\na.fwdchip { text-decoration: none; cursor: pointer; }\n.fwdchip[class*=\"st-\"] { max-width: 220px; }\n.fwdchip.st-queue { border-color: var(--line); color: var(--muted); }\n.fwdchip.st-in_progress { border-color: #3f8ae0; color: #3f8ae0; }\n.fwdchip.st-in_review { border-color: #c98a1b; color: #c98a1b; }\n.fwdchip.st-resolved { border-color: #2f9e6a; color: #2f9e6a; }\n\n/* ------------------------------------------------ lifecycle chips + review flow */\n.lifechip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap;\n border: 1px solid var(--line); background: var(--bg); color: var(--muted);\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n.lifechip.st-sent { border-color: var(--accent); color: var(--accent); }\n.lifechip.st-in_pr { border-color: #3f8ae0; color: #3f8ae0; }\n.lifechip.st-preview { border-color: var(--accent); background: var(--accent); color: #fff; }\n.lifechip.st-reviewed { border-color: #2f9e6a; color: #2f9e6a; }\n.prchip {\n padding: 1px 6px; border-radius: 6px; text-decoration: none; cursor: pointer;\n border: 1px solid #3f8ae0; background: var(--bg); color: #3f8ae0;\n font-family: ui-monospace, Menlo, monospace; font-size: 10px; font-weight: 700;\n}\n.prchip:hover { background: #3f8ae0; color: #fff; }\n.prchip.st-merged { border-color: #8250df; color: #8250df; }\n.prchip.st-merged:hover { background: #8250df; color: #fff; }\n.prchip.st-closed { border-color: var(--line); color: var(--muted); }\n/* a revision of another thread — the conversation carried over */\n.iterchip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap;\n border: 1px dashed var(--line); background: var(--bg); color: var(--muted);\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n/* a preview that is actually live — never shown optimistically */\n.previewchip {\n padding: 1px 6px; border-radius: 6px; text-decoration: none; white-space: nowrap;\n border: 1px solid #2f9e6a; background: var(--bg); color: #2f9e6a;\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n.previewchip:hover { background: #2f9e6a; color: #fff; }\n/* checks meter — a numerator over a thin bar */\n.checks { display: inline-flex; align-items: center; gap: 4px; }\n.checks-n { font-family: ui-monospace, Menlo, monospace; font-size: 9.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.checks-bar { display: block; width: 26px; height: 3px; border-radius: 2px; background: var(--line); overflow: hidden; }\n.checks-bar i { display: block; height: 100%; background: #2f9e6a; }\n\n/* the \"N waiting on your review\" strip above the list */\n.reviewbar {\n display: flex; align-items: center; gap: 7px; margin: 8px 12px 0; padding: 7px 10px;\n border: 1px solid var(--accent); border-radius: 9px; background: var(--bg-2);\n}\n.rb-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; animation: loupe-pulse 1.6s ease-in-out infinite; }\n@media (prefers-reduced-motion: reduce) { .rb-dot { animation: none; } }\n.rb-t { flex: 1; font-size: 11.5px; color: var(--ink); }\n.rb-t b { font-variant-numeric: tabular-nums; }\n.rb-b {\n padding: 3px 9px; border: 1px solid var(--accent); border-radius: 7px;\n background: var(--accent); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer;\n}\n\n/* the review banner inside a thread */\n.revbanner {\n display: flex; align-items: center; gap: 6px; margin: 8px 0; padding: 7px 8px;\n border: 1px solid var(--accent); border-radius: 9px; background: var(--bg-3);\n}\n.rev-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }\n.rev-t { flex: 1; font-size: 11.5px; font-weight: 600; color: var(--ink); }\n.rev-approve {\n padding: 4px 10px; border: 1px solid var(--accent); border-radius: 7px;\n background: var(--accent); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer;\n}\n.rev-approve:disabled { opacity: .6; cursor: default; }\n.rev-comment, .rev-origin {\n padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.rev-comment:hover, .rev-origin:hover { border-color: var(--accent); }\n\n/* original request beside the proposed change */\n.origin { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; margin: 8px 0; }\n.or-col { min-width: 0; padding: 7px 8px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg); }\n.or-h { margin-bottom: 4px; font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.or-b { font-size: 11px; line-height: 1.45; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }\n.or-code {\n margin: 6px 0 0; padding: 6px; max-height: 130px; overflow: auto; border-radius: 6px;\n background: var(--bg-2); color: var(--muted); font-family: ui-monospace, Menlo, monospace;\n font-size: 10px; white-space: pre-wrap; overflow-wrap: anywhere;\n}\n\n/* ------------------------------------------------- consent-gated agent navigation */\n.consent {\n margin: 8px 10px 0; padding: 10px; border: 1px solid var(--pin); border-radius: 10px;\n background: var(--bg-2);\n}\n.cs-head { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink); }\n.cs-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pin); flex: none; animation: loupe-pulse 1.4s ease-in-out infinite; }\n@media (prefers-reduced-motion: reduce) { .cs-dot { animation: none; } }\n.cs-url {\n margin-top: 6px; padding: 6px 7px; border-radius: 7px; background: var(--bg);\n font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--ink);\n overflow-wrap: anywhere;\n}\n.cs-why { margin-top: 6px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.cs-btns { display: flex; justify-content: flex-end; gap: 6px; margin-top: 9px; }\n.cs-btns button { padding: 5px 10px; border-radius: 7px; font-size: 11.5px; font-weight: 600; cursor: pointer; }\n.cs-deny { border: 1px solid var(--line); background: var(--bg); color: var(--ink); }\n.cs-deny:hover { border-color: var(--accent); }\n.cs-go { border: 1px solid var(--accent); background: var(--accent); color: #fff; }\n\n/* --------------------------------------------------------------- generate + iterate */\n.genwrap { margin-top: 8px; }\n.gen-open {\n width: 100%; padding: 7px; border: 1px dashed var(--line); border-radius: 8px;\n background: transparent; color: var(--muted); font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.gen-open:hover { border-color: var(--accent); color: var(--accent); }\n.genhead { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }\n.gen-t { flex: 1; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }\n.gen-nav { display: inline-flex; align-items: center; gap: 2px; }\n.gen-step {\n width: 20px; height: 20px; padding: 0; border: 1px solid var(--line); border-radius: 6px;\n background: var(--bg); color: var(--ink); font-size: 13px; line-height: 1; cursor: pointer;\n}\n.gen-step:disabled { opacity: .4; cursor: default; }\n.gen-n { min-width: 32px; text-align: center; font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.gen-undo, .gen-x {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.gen-undo:disabled { opacity: .4; cursor: default; }\n.gen-undo:hover, .gen-x:hover { border-color: var(--accent); }\n.genbusy, .genempty { padding: 14px; text-align: center; font-size: 11.5px; color: var(--muted); }\n/* the preview plane: generated markup over the original capture, sandboxed.\n min-height matters — the iframe is absolutely positioned, so a thread with no\n screenshot would otherwise give the plane nothing in-flow and collapse it to a\n couple of pixels. */\n.genplane { position: relative; min-height: 150px; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--bg); }\n.genbase { display: block; width: 100%; }\n.genframe {\n position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: transparent;\n transition: opacity .08s linear;\n}\n.genslider { display: flex; align-items: center; gap: 7px; margin-top: 6px; }\n.gs-lab { font-size: 10.5px; color: var(--muted); }\n.gs-range { flex: 1; min-width: 0; accent-color: var(--accent); }\n.gs-n { min-width: 32px; text-align: right; font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.gennotes {\n margin-top: 6px; padding: 6px 8px; border-radius: 7px; background: var(--bg-3);\n font-size: 11px; line-height: 1.45; color: var(--muted);\n}\n.geniter { display: flex; gap: 5px; margin-top: 7px; }\n.iter-in {\n flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg); color: var(--ink); font-size: 11.5px;\n}\n.iter-in:focus { outline: none; border-color: var(--accent); }\n.iter-send {\n flex: none; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.iter-send:disabled { opacity: .5; cursor: default; }\n/* the access gate, when there is no generator */\n.gengate { padding: 10px; border: 1px solid var(--line); border-radius: 9px; background: var(--bg-2); }\n.gate-t { font-size: 12px; font-weight: 700; color: var(--ink); }\n.gate-b { margin-top: 4px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.gate-ask {\n margin-top: 8px; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.gate-ask:disabled { opacity: .6; cursor: default; }\n.gate-hint { margin-top: 7px; font-size: 10.5px; color: var(--muted); }\n.gate-hint code { font-family: ui-monospace, Menlo, monospace; color: var(--ink); }\n\n/* dictation */\n.voice {\n width: 30px; flex: none; padding: 0; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 13px; cursor: pointer;\n}\n.voice:hover:not(:disabled) { border-color: var(--accent); color: var(--ink); }\n.voice:disabled { opacity: .45; cursor: not-allowed; }\n.voice.on { border-color: var(--pin); color: var(--pin); background: var(--bg-3); }\n\n/* attachments on a reply */\n.reply-attach {\n padding: 3px 7px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 12px; cursor: pointer; line-height: 1.4;\n}\n.reply-attach:hover { border-color: var(--accent); color: var(--accent); }\n.reply-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }\n.msg-atts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }\n.msg-att {\n max-width: 190px; max-height: 130px; border: 1px solid var(--line); border-radius: 8px;\n object-fit: cover; cursor: pointer; background: var(--bg-2);\n}\n\n/* ------------------------------------------------------------- companion chat */\n/* Same inset as the Activity view — without it the composer and its Send button sit\n flush against the panel's edge, which reads as a clipped button. Scoped to .view.on:\n a bare .chat-view display:flex outranked .view display:none by source\n order, so the chat rendered under every other tab and swallowed their clicks. */\n.view.on.chat-view { display: flex; flex-direction: column; gap: 8px; height: 100%; min-height: 0; padding: 10px 12px 16px; }\n.chat-tray {\n display: flex; flex-direction: column; gap: 4px; padding: 8px;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2);\n}\n.tray-head { display: flex; align-items: center; gap: 6px; }\n.tray-title { font-size: 11px; color: var(--muted); }\n.tray-spacer, .chat-spacer { flex: 1; }\n.tray-chip {\n display: flex; align-items: center; gap: 6px; padding: 4px 6px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg); font-size: 11px;\n}\n.tray-chip.off { opacity: .5; }\n.tray-thumb { width: 24px; height: 24px; border-radius: 4px; object-fit: cover; flex: none; }\n.tray-kind { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; flex: none; }\n.tray-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, monospace; }\n.tray-nudge, .tray-x {\n border: 0; background: transparent; color: var(--muted); cursor: pointer;\n font-size: 11px; padding: 1px 4px; border-radius: 4px; line-height: 1.2;\n}\n.tray-nudge:disabled { opacity: .3; cursor: default; }\n.tray-nudge:not(:disabled):hover, .tray-x:hover { color: var(--accent); background: var(--accent-soft); }\n.chat-log { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 2px; }\n.chat-empty { color: var(--muted); font-size: 12px; padding: 12px 4px; line-height: 1.5; }\n.chat-msg { padding: 8px 10px; border-radius: 10px; background: var(--bg-2); border: 1px solid var(--line); }\n.chat-msg.mine { background: var(--accent-soft); border-color: var(--accent); }\n.chat-head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 3px; }\n.chat-who { font-size: 11px; }\n.chat-when { font-size: 10px; color: var(--muted); }\n.chat-ctx {\n font-size: 10px; color: var(--accent); border: 1px solid var(--accent);\n border-radius: 999px; padding: 0 5px; margin-left: auto;\n}\n.chat-body { font-size: 12px; white-space: pre-wrap; word-break: break-word; }\n.chat-compose { border-top: 1px solid var(--line); padding-top: 8px; }\n.chat-in {\n width: 100%; resize: vertical; min-height: 44px; padding: 7px 9px;\n border: 1px solid var(--line); border-radius: 9px; background: var(--bg);\n color: var(--ink); font: inherit; font-size: 12.5px;\n}\n.chat-in:focus { outline: none; border-color: var(--accent); }\n.chat-foot { display: flex; align-items: center; gap: 6px; margin-top: 6px; }\n.chat-add, .chat-mic, .chat-send {\n padding: 4px 9px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.chat-add:hover, .chat-mic:hover { border-color: var(--accent); color: var(--accent); }\n.chat-mic.on { border-color: var(--err, #f2555a); color: #f2555a; background: color-mix(in srgb, #f2555a 14%, transparent); }\n.chat-send { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }\n.chat-send:hover { opacity: .9; }\n.chat-rec { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: #f2555a; }\n.chat-rec-dot { width: 7px; height: 7px; border-radius: 50%; background: #f2555a; animation: chatpulse 1.2s ease-in-out infinite; }\n@keyframes chatpulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }\n.chat-err { font-size: 11px; color: #f2555a; }\n\n/* reactions */\n.rxns { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; position: relative; }\n.rxn {\n display: inline-flex; align-items: center; gap: 3px; padding: 1px 7px;\n border: 1px solid var(--line); border-radius: 999px; background: var(--bg);\n color: var(--ink); font-size: 11px; cursor: pointer; line-height: 1.7;\n}\n.rxn:hover { border-color: var(--accent); }\n.rxn.mine { border-color: var(--accent); background: var(--accent-soft); }\n.rxn-n { color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }\n.rxn.mine .rxn-n { color: var(--accent); }\n.rxn-add {\n width: 20px; height: 20px; padding: 0; border: 1px dashed var(--line); border-radius: 50%;\n background: transparent; color: var(--muted); font-size: 11px; cursor: pointer; line-height: 1;\n}\n.rxn-add:hover { border-color: var(--accent); color: var(--accent); }\n.rxn-pick {\n display: flex; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg); box-shadow: 0 4px 14px rgb(0 0 0 / 18%); z-index: 3;\n}\n.rxn-opt {\n width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%;\n background: transparent; font-size: 14px; cursor: pointer; line-height: 1;\n}\n.rxn-opt:hover { background: var(--accent-soft); }\n\n/* who else is here */\n.peers { display: flex; align-items: center; gap: -2px; margin-right: 8px; }\n.peer-av {\n display: inline-flex; align-items: center; justify-content: center;\n width: 20px; height: 20px; margin-left: -5px; border-radius: 50%;\n border: 2px solid var(--bg); background: var(--accent); color: #fff;\n font-size: 9px; font-weight: 700; letter-spacing: .02em;\n}\n.peer-av:first-child { margin-left: 0; }\n.peer-more { margin-left: 3px; font-size: 10px; color: var(--muted); }\n\n/* in-app mentions */\n.hnotif { margin-top: 10px; }\n.nf-head { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; font-size: 11.5px; color: var(--ink); }\n.nf-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }\n.nf-i {\n display: flex; align-items: baseline; gap: 7px; width: 100%; text-align: left;\n padding: 6px 8px; margin-bottom: 4px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--bg-2); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.nf-i:hover { background: var(--bg-3); }\n.nf-b { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.nf-w { flex: none; color: var(--muted); font-size: 10.5px; }\n.nf-read {\n margin-top: 2px; padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 10.5px; cursor: pointer;\n}\n.nf-read:hover { border-color: var(--accent); color: var(--ink); }\n\n/* mention highlighting + autocomplete */\n.mention { color: var(--accent); font-weight: 600; }\n.mention-list {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n padding: 5px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2);\n}\n.mention-pick {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.mention-pick:hover { border-color: var(--accent); color: var(--accent); }\n/* \"needs you\" — the two reasons the stage cannot express */\n.needsline {\n display: flex; align-items: center; gap: 7px; margin: 8px 0; padding: 7px 9px;\n border: 1px solid #e0a92c; border-radius: 9px; background: var(--bg-2);\n font-size: 11.5px; font-weight: 600; color: var(--ink);\n}\n.needs-dot { width: 7px; height: 7px; border-radius: 50%; background: #e0a92c; flex: none; }\n\n/* ------------------------------------------------------------- conversation */\n.convo { margin-top: 8px; }\n.convo-loading { padding: 10px; text-align: center; font-size: 11.5px; color: var(--muted); }\n.msgs { display: flex; flex-direction: column; gap: 6px; }\n.msg { padding: 7px 8px; border-radius: 9px; background: var(--bg-2); border: 1px solid transparent; }\n/* An agent's reply is called out with a left accent bar and a lighter container —\n it should be obvious at a glance who you are talking to. */\n.msg.agent { border-left: 3px solid var(--accent); background: var(--bg-3); }\n.msg.pending { opacity: .65; }\n.msg.failed { border-color: var(--pin); }\n.msg-head { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }\n.msg-av {\n width: 20px; height: 20px; border-radius: 50%; flex: none;\n display: grid; place-items: center; background: var(--bg-3); color: var(--muted);\n font-size: 10px; font-weight: 700;\n}\n.msg-av.agent { background: var(--accent); color: #fff; }\n.msg-name { font-size: 11.5px; color: var(--ink); }\n.msg-when { flex: 1; font-size: 10.5px; color: var(--muted); }\n.msg-tag {\n padding: 0 5px; border-radius: 999px; background: var(--accent); color: #fff;\n font-size: 9px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;\n}\n.msg-body { font-size: 11.5px; line-height: 1.45; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }\n.msg-state { margin-top: 4px; font-size: 10.5px; color: var(--muted); }\n.msg-state.failed { color: var(--pin); }\n.msg-retry {\n margin-left: 6px; padding: 1px 7px; border: 1px solid var(--pin); border-radius: 6px;\n background: transparent; color: var(--pin); font-size: 10.5px; cursor: pointer;\n}\n.reply { margin-top: 7px; }\n.reply-in {\n width: 100%; resize: vertical; min-height: 40px; padding: 7px 8px;\n border: 1px solid var(--line); border-radius: 9px; background: var(--bg);\n color: var(--ink); font: inherit; font-size: 11.5px;\n}\n.reply-in:focus { outline: none; border-color: var(--accent); }\n.reply-foot { display: flex; align-items: center; gap: 7px; margin-top: 5px; }\n.reply-hint { flex: 1; font-size: 10.5px; color: var(--muted); }\n.reply-send {\n padding: 5px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n/* the activity timeline */\n.tl { margin-top: 10px; }\n.tl-h { margin-bottom: 5px; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.tl-i { position: relative; padding: 0 0 7px 14px; font-size: 11px; color: var(--muted); }\n.tl-i::before { content: \"\"; position: absolute; left: 3px; top: 4px; bottom: -3px; width: 1px; background: var(--line); }\n.tl-i:last-child::before { display: none; }\n.tl-dot { position: absolute; left: 0; top: 3px; width: 7px; height: 7px; border-radius: 50%; background: var(--line); }\n.tl-i.tl-resolved .tl-dot { background: #2f9e6a; }\n.tl-i.tl-pr .tl-dot, .tl-i.tl-preview .tl-dot { background: #3f8ae0; }\n.tl-i.tl-review .tl-dot { background: var(--accent); }\n.tl-l { color: var(--ink); }\n.tl-d { display: block; font-size: 10.5px; color: var(--muted); overflow-wrap: anywhere; }\n.copyrow { display: flex; gap: 6px; margin-top: 8px; }\n.copy-b {\n flex: 1; padding: 5px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.copy-b:hover { border-color: var(--accent); color: var(--ink); }\n\n/* ------------------------------------------------------- hint card (once per view) */\n.hint {\n position: relative; margin: 8px 12px 0; padding: 10px 28px 10px 11px;\n border: 1px solid var(--accent); border-radius: 10px; background: var(--bg-2);\n}\n.hint-t { margin-bottom: 3px; font-size: 12.5px; font-weight: 700; color: var(--ink); }\n.hint-b { font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.hint-off { display: inline-block; margin-top: 6px; padding: 0; border: 0; background: transparent; color: var(--accent); font-size: 11px; text-decoration: underline; cursor: pointer; }\n.hint-x {\n position: absolute; top: 6px; right: 6px; width: 18px; height: 18px; padding: 0;\n border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 13px; line-height: 1; cursor: pointer;\n}\n.hint-x:hover { background: var(--bg-3); color: var(--ink); }\n\n/* ---------------------------------------------------------------- guided tour */\n/* Non-modal on purpose: the dimmer and the spotlight are click-through, so a tour\n can never trap someone mid-task. Only the card itself takes pointer events. */\n.tour { position: fixed; inset: 0; z-index: 2147483200; display: none; pointer-events: none; }\n.tour.open { display: block; }\n.tour-spot {\n position: fixed; border: 2px solid var(--accent); border-radius: 10px; pointer-events: none;\n box-shadow: 0 0 0 9999px rgba(8, 10, 16, .62);\n transition: all .18s ease;\n}\n.tour-card {\n position: fixed; width: 252px; padding: 12px; pointer-events: auto;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); color: var(--ink);\n}\n.tour-title { margin-bottom: 4px; font-size: 13px; font-weight: 700; }\n.tour-body { font-size: 11.5px; line-height: 1.5; color: var(--muted); }\n.tour-foot { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.tour-dots { display: flex; flex: 1; gap: 4px; }\n.tour-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--line); }\n.tour-dots i.on { background: var(--accent); }\n.tour-foot button {\n padding: 5px 9px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.tour-foot .t-next { border-color: var(--accent); background: var(--accent); color: #fff; }\n.tour-foot .t-skip { border: 0; background: transparent; color: var(--muted); }\n\n/* Mobile: left/right/float docking is a desktop affordance. On small screens the\n panel collapses to a bottom sheet that OVERLAYS the page (pushing a side dock\n here would squeeze the page to a useless sliver), regardless of the chosen dock\n mode. !important overrides the inline geometry JS applies for float mode. */\n@media (max-width: 640px) {\n .dock.open {\n top: auto !important; left: 0 !important; right: 0 !important; bottom: 0 !important;\n width: auto !important; height: 76vh !important;\n border-width: 1px 0 0 0 !important; border-radius: 16px 16px 0 0 !important;\n }\n .dctl [data-role=\"pos\"], .dctl .gap { display: none; } /* dock positions don't apply on mobile */\n .menu { min-width: 190px; }\n .resize { display: none !important; }\n .tools button { flex: 1; justify-content: center; } /* full-width tap targets */\n .dock.mode-bottom .list { grid-template-columns: 1fr; }\n .fab-cluster { bottom: 16px; right: 16px; }\n /* While a tool is active, shrink the sheet to just header + tools so most of the\n page stays visible and tappable; the list returns when the tool closes. */\n .dock.inspecting { height: auto !important; }\n .dock.inspecting .listhead, .dock.inspecting .list { display: none; }\n /* The composer is a bottom sheet on a phone: full width, thumb-reachable, and it\n scrolls when the on-screen keyboard is up. JS sets its position inline (hence the\n !important) — on small screens the sheet wins. */\n .composer {\n top: auto !important; left: 0 !important; right: 0 !important; bottom: 0 !important;\n width: auto !important; max-height: 80vh; overflow-y: auto;\n border-radius: 16px 16px 0 0; padding-bottom: 16px;\n }\n}\n`;\n","import type { Anchor, ResolveResult } from \"./types.js\";\n\n// ---- config ----------------------------------------------------------------\n\nconst TEXT_MAX = 120;\nconst ATTR_KEYS = [\"role\", \"aria-label\", \"name\", \"type\", \"alt\", \"href\", \"placeholder\", \"title\"];\n/** Minimum composite score to accept a scan match. Below this we treat the element as gone. */\nconst ACCEPT_THRESHOLD = 0.5;\n/** Weights for the composite similarity score (sum need not be 1; we normalize). */\nconst W = { tag: 0.12, text: 0.34, attrs: 0.22, testid: 0.22, cssPath: 0.2, position: 0.1 };\n\n// ---- capture ----------------------------------------------------------------\n\nexport function captureAnchor(el: Element): Anchor {\n const rect = el.getBoundingClientRect();\n return {\n tag: el.tagName.toLowerCase(),\n cssPath: cssPath(el),\n xpath: xPath(el),\n testid: stableId(el),\n text: normText(el.textContent),\n attrs: readAttrs(el),\n nthOfType: nthOfType(el),\n rect: {\n x: Math.round(rect.left + window.scrollX),\n y: Math.round(rect.top + window.scrollY),\n w: Math.round(rect.width),\n h: Math.round(rect.height),\n },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\n\n// ---- resolve ----------------------------------------------------------------\n\n/**\n * Try to re-locate the element described by `anchor` on the current page.\n * Returns the best candidate above threshold, or null (→ caller falls back to\n * a coordinate pin on the screenshot). Never returns an element inside our own UI.\n */\nexport function resolveAnchor(anchor: Anchor, root: ParentNode = document): ResolveResult | null {\n // 1. Stable id / testid — the strongest signal. Accept immediately if unique.\n if (anchor.testid) {\n const byTestid = safeQueryAll(root, `[data-testid=\"${cssStr(anchor.testid)}\"], [data-test=\"${cssStr(anchor.testid)}\"]`);\n const byId = document.getElementById(anchor.testid);\n const hits = dedupe([...byTestid, ...(byId ? [byId] : [])]).filter(usable);\n if (hits.length === 1) return { element: hits[0]!, score: 0.98, via: \"testid\" };\n // Multiple matches → fall through to scoring to disambiguate.\n }\n\n // 1.5. A cssPath rooted at a stable id/testid + structural position is\n // high-confidence even when the element's own text/content has changed\n // (e.g. a value that updates on redeploy). Require the tag to still match.\n if (/^(\\[data-testid=|#)/.test(anchor.cssPath)) {\n const hits = safeQueryAll(root, anchor.cssPath).filter(usable);\n if (hits.length === 1 && hits[0]!.tagName.toLowerCase() === anchor.tag) {\n return { element: hits[0]!, score: 0.9, via: \"cssPath\" };\n }\n }\n\n const candidates = new Map<Element, ResolveResult[\"via\"]>();\n const consider = (el: Element | null, via: ResolveResult[\"via\"]) => {\n if (el && usable(el) && !candidates.has(el)) candidates.set(el, via);\n };\n\n // 2. Exact locators.\n consider(safeQuery(root, anchor.cssPath), \"cssPath\");\n consider(byXPath(anchor.xpath), \"xpath\");\n for (const el of safeQueryAll(root, anchor.tag)) consider(el, \"scan\");\n\n // 3. Broaden by text when the tag scan is too narrow (e.g. wrapper changed tag).\n if (anchor.text) {\n for (const el of safeQueryAll(root, \"*\")) {\n if (candidates.size > 4000) break; // safety cap on huge pages\n if (normText(el.textContent) === anchor.text) consider(el, \"scan\");\n }\n }\n\n let best: ResolveResult | null = null;\n for (const [el, via] of candidates) {\n const score = similarity(anchor, el, via);\n if (!best || score > best.score) best = { element: el, score, via };\n }\n return best && best.score >= ACCEPT_THRESHOLD ? best : null;\n}\n\nfunction similarity(a: Anchor, el: Element, via: ResolveResult[\"via\"]): number {\n let sum = 0;\n let total = 0;\n\n const add = (w: number, v: number) => { sum += w * v; total += w; };\n\n add(W.tag, el.tagName.toLowerCase() === a.tag ? 1 : 0);\n\n if (a.text) {\n const t = normText(el.textContent);\n add(W.text, t === a.text ? 1 : t && (t.includes(a.text) || a.text.includes(t)) ? 0.5 : 0);\n }\n\n // Every field below is optional in practice: an anchor stored by an older (or\n // hand-written) client can be missing attrs/rect/viewport, and a throw here used\n // to abort the whole panel's first render.\n const attrKeys = Object.keys(a.attrs ?? {});\n if (attrKeys.length) {\n let matched = 0;\n for (const k of attrKeys) if (el.getAttribute(k) === (a.attrs ?? {})[k]) matched++;\n add(W.attrs, matched / attrKeys.length);\n }\n\n if (a.testid) add(W.testid, stableId(el) === a.testid ? 1 : 0);\n\n add(W.cssPath, via === \"cssPath\" ? 1 : 0);\n\n // Positional proximity — normalized by the (possibly changed) viewport diagonal.\n const r = el.getBoundingClientRect();\n const cx = r.left + window.scrollX + r.width / 2;\n const cy = r.top + window.scrollY + r.height / 2;\n const ar = a.rect ?? { x: 0, y: 0, w: 0, h: 0 };\n const av = a.viewport ?? { w: 0, h: 0 };\n const ax = ar.x + ar.w / 2;\n const ay = ar.y + ar.h / 2;\n const diag = Math.hypot(av.w, av.h) || 1;\n const dist = Math.hypot(cx - ax, cy - ay);\n add(W.position, Math.max(0, 1 - dist / diag));\n\n return total ? sum / total : 0;\n}\n\n// ---- locator builders -------------------------------------------------------\n\nfunction cssPath(el: Element): string {\n const segs: string[] = [];\n let node: Element | null = el;\n while (node && node.nodeType === 1 && node !== document.documentElement) {\n const id = node.getAttribute(\"id\");\n const testid = node.getAttribute(\"data-testid\") || node.getAttribute(\"data-test\");\n if (id && isStable(id)) { segs.unshift(`#${cssEsc(id)}`); break; }\n if (testid) { segs.unshift(`[data-testid=\"${cssStr(testid)}\"]`); break; }\n segs.unshift(`${node.tagName.toLowerCase()}:nth-of-type(${nthOfType(node)})`);\n node = node.parentElement;\n if (node === document.body) { segs.unshift(\"body\"); break; }\n }\n return segs.join(\" > \");\n}\n\nfunction xPath(el: Element): string {\n const segs: string[] = [];\n let node: Element | null = el;\n while (node && node.nodeType === 1 && node !== document.documentElement) {\n segs.unshift(`${node.tagName.toLowerCase()}[${nthOfType(node)}]`);\n node = node.parentElement;\n }\n return \"/html/\" + segs.join(\"/\");\n}\n\n// ---- small helpers ----------------------------------------------------------\n\nfunction nthOfType(el: Element): number {\n let i = 1;\n let sib = el.previousElementSibling;\n while (sib) {\n if (sib.tagName === el.tagName) i++;\n sib = sib.previousElementSibling;\n }\n return i;\n}\n\nfunction stableId(el: Element): string | null {\n const testid = el.getAttribute(\"data-testid\") || el.getAttribute(\"data-test\");\n if (testid) return testid;\n const id = el.getAttribute(\"id\");\n return id && isStable(id) ? id : null;\n}\n\n/** Reject framework-generated ids (e.g. \":r3:\", \"ember42\", long hashes). */\nfunction isStable(id: string): boolean {\n if (id.length > 40) return false;\n if (/^(ember|react|radix|headlessui|:r)/i.test(id)) return false;\n if (/[:]/.test(id)) return false;\n return true;\n}\n\nfunction readAttrs(el: Element): Record<string, string> {\n const out: Record<string, string> = {};\n for (const k of ATTR_KEYS) {\n const v = el.getAttribute(k);\n if (v != null && v !== \"\") out[k] = v.length > 200 ? v.slice(0, 200) : v;\n }\n return out;\n}\n\nfunction normText(t: string | null): string {\n return (t || \"\").replace(/\\s+/g, \" \").trim().slice(0, TEXT_MAX);\n}\n\n/**\n * Exclude anything inside our own Shadow-DOM host, the document itself, and — where the\n * browser can tell (`checkVisibility`: Chrome 105+, Firefox 106+, Safari 17.4+) — nodes\n * that are not rendered, so a hidden duplicate never wins over the visible one.\n */\nfunction usable(el: Element): boolean {\n if (el.id === \"loupe-root\" || el.closest(\"#loupe-root\")) return false;\n if (el === document.body || el === document.documentElement) return false;\n if (typeof el.checkVisibility === \"function\" && !el.checkVisibility()) return false;\n return true;\n}\n\nfunction byXPath(xp: string): Element | null {\n try {\n const r = document.evaluate(xp, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);\n return r.singleNodeValue instanceof Element ? r.singleNodeValue : null;\n } catch {\n return null;\n }\n}\n\nfunction safeQuery(root: ParentNode, sel: string): Element | null {\n try { return sel ? root.querySelector(sel) : null; } catch { return null; }\n}\nfunction safeQueryAll(root: ParentNode, sel: string): Element[] {\n try { return sel ? Array.from(root.querySelectorAll(sel)) : []; } catch { return []; }\n}\nfunction dedupe(els: Element[]): Element[] {\n return Array.from(new Set(els));\n}\nfunction cssEsc(s: string): string {\n return (window.CSS && CSS.escape) ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n/** Escape a value for use inside a double-quoted attribute selector. */\nfunction cssStr(s: string): string {\n return s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n","function changeJpegDpi(uint8Array, dpi) {\n uint8Array[13] = 1;\n uint8Array[14] = dpi >> 8;\n uint8Array[15] = dpi & 255;\n uint8Array[16] = dpi >> 8;\n uint8Array[17] = dpi & 255;\n return uint8Array;\n}\n\nconst _P = \"p\".charCodeAt(0);\nconst _H = \"H\".charCodeAt(0);\nconst _Y = \"Y\".charCodeAt(0);\nconst _S = \"s\".charCodeAt(0);\nlet pngDataTable;\nfunction createPngDataTable() {\n const crcTable = new Int32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) {\n c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;\n }\n crcTable[n] = c;\n }\n return crcTable;\n}\nfunction calcCrc(uint8Array) {\n let c = -1;\n if (!pngDataTable)\n pngDataTable = createPngDataTable();\n for (let n = 0; n < uint8Array.length; n++) {\n c = pngDataTable[(c ^ uint8Array[n]) & 255] ^ c >>> 8;\n }\n return c ^ -1;\n}\nfunction searchStartOfPhys(uint8Array) {\n const length = uint8Array.length - 1;\n for (let i = length; i >= 4; i--) {\n if (uint8Array[i - 4] === 9 && uint8Array[i - 3] === _P && uint8Array[i - 2] === _H && uint8Array[i - 1] === _Y && uint8Array[i] === _S) {\n return i - 3;\n }\n }\n return 0;\n}\nfunction changePngDpi(uint8Array, dpi, overwritepHYs = false) {\n const physChunk = new Uint8Array(13);\n dpi *= 39.3701;\n physChunk[0] = _P;\n physChunk[1] = _H;\n physChunk[2] = _Y;\n physChunk[3] = _S;\n physChunk[4] = dpi >>> 24;\n physChunk[5] = dpi >>> 16;\n physChunk[6] = dpi >>> 8;\n physChunk[7] = dpi & 255;\n physChunk[8] = physChunk[4];\n physChunk[9] = physChunk[5];\n physChunk[10] = physChunk[6];\n physChunk[11] = physChunk[7];\n physChunk[12] = 1;\n const crc = calcCrc(physChunk);\n const crcChunk = new Uint8Array(4);\n crcChunk[0] = crc >>> 24;\n crcChunk[1] = crc >>> 16;\n crcChunk[2] = crc >>> 8;\n crcChunk[3] = crc & 255;\n if (overwritepHYs) {\n const startingIndex = searchStartOfPhys(uint8Array);\n uint8Array.set(physChunk, startingIndex);\n uint8Array.set(crcChunk, startingIndex + 13);\n return uint8Array;\n } else {\n const chunkLength = new Uint8Array(4);\n chunkLength[0] = 0;\n chunkLength[1] = 0;\n chunkLength[2] = 0;\n chunkLength[3] = 9;\n const finalHeader = new Uint8Array(54);\n finalHeader.set(uint8Array, 0);\n finalHeader.set(chunkLength, 33);\n finalHeader.set(physChunk, 37);\n finalHeader.set(crcChunk, 50);\n return finalHeader;\n }\n}\nconst b64PhysSignature1 = \"AAlwSFlz\";\nconst b64PhysSignature2 = \"AAAJcEhZ\";\nconst b64PhysSignature3 = \"AAAACXBI\";\nfunction detectPhysChunkFromDataUrl(dataUrl) {\n let b64index = dataUrl.indexOf(b64PhysSignature1);\n if (b64index === -1) {\n b64index = dataUrl.indexOf(b64PhysSignature2);\n }\n if (b64index === -1) {\n b64index = dataUrl.indexOf(b64PhysSignature3);\n }\n return b64index;\n}\n\nconst PREFIX = \"[modern-screenshot]\";\nconst IN_BROWSER = typeof window !== \"undefined\";\nconst SUPPORT_WEB_WORKER = IN_BROWSER && \"Worker\" in window;\nconst SUPPORT_ATOB = IN_BROWSER && \"atob\" in window;\nconst SUPPORT_BTOA = IN_BROWSER && \"btoa\" in window;\nconst USER_AGENT = IN_BROWSER ? window.navigator?.userAgent : \"\";\nconst IN_CHROME = USER_AGENT.includes(\"Chrome\");\nconst IN_SAFARI = USER_AGENT.includes(\"AppleWebKit\") && !IN_CHROME;\nconst IN_FIREFOX = USER_AGENT.includes(\"Firefox\");\nconst isContext = (value) => value && \"__CONTEXT__\" in value;\nconst isCssFontFaceRule = (rule) => rule.constructor.name === \"CSSFontFaceRule\";\nconst isCSSImportRule = (rule) => rule.constructor.name === \"CSSImportRule\";\nconst isLayerBlockRule = (rule) => rule.constructor.name === \"CSSLayerBlockRule\";\nconst isElementNode = (node) => node.nodeType === 1;\nconst isSVGElementNode = (node) => typeof node.className === \"object\";\nconst isSVGImageElementNode = (node) => node.tagName === \"image\";\nconst isSVGUseElementNode = (node) => node.tagName === \"use\";\nconst isHTMLElementNode = (node) => isElementNode(node) && typeof node.style !== \"undefined\" && !isSVGElementNode(node);\nconst isCommentNode = (node) => node.nodeType === 8;\nconst isTextNode = (node) => node.nodeType === 3;\nconst isImageElement = (node) => node.tagName === \"IMG\";\nconst isVideoElement = (node) => node.tagName === \"VIDEO\";\nconst isCanvasElement = (node) => node.tagName === \"CANVAS\";\nconst isTextareaElement = (node) => node.tagName === \"TEXTAREA\";\nconst isInputElement = (node) => node.tagName === \"INPUT\";\nconst isStyleElement = (node) => node.tagName === \"STYLE\";\nconst isScriptElement = (node) => node.tagName === \"SCRIPT\";\nconst isSelectElement = (node) => node.tagName === \"SELECT\";\nconst isSlotElement = (node) => node.tagName === \"SLOT\";\nconst isIFrameElement = (node) => node.tagName === \"IFRAME\";\nconst consoleWarn = (...args) => console.warn(PREFIX, ...args);\nfunction supportWebp(ownerDocument) {\n const canvas = ownerDocument?.createElement?.(\"canvas\");\n if (canvas) {\n canvas.height = canvas.width = 1;\n }\n return Boolean(canvas) && \"toDataURL\" in canvas && Boolean(canvas.toDataURL(\"image/webp\").includes(\"image/webp\"));\n}\nconst isDataUrl = (url) => url.startsWith(\"data:\");\nfunction resolveUrl(url, baseUrl) {\n if (url.match(/^[a-z]+:\\/\\//i))\n return url;\n if (IN_BROWSER && url.match(/^\\/\\//))\n return window.location.protocol + url;\n if (url.match(/^[a-z]+:/i))\n return url;\n if (!IN_BROWSER)\n return url;\n const doc = getDocument().implementation.createHTMLDocument();\n const base = doc.createElement(\"base\");\n const a = doc.createElement(\"a\");\n doc.head.appendChild(base);\n doc.body.appendChild(a);\n if (baseUrl)\n base.href = baseUrl;\n a.href = url;\n return a.href;\n}\nfunction getDocument(target) {\n return (target && isElementNode(target) ? target?.ownerDocument : target) ?? window.document;\n}\nconst XMLNS = \"http://www.w3.org/2000/svg\";\nfunction createSvg(width, height, ownerDocument) {\n const svg = getDocument(ownerDocument).createElementNS(XMLNS, \"svg\");\n svg.setAttributeNS(null, \"width\", width.toString());\n svg.setAttributeNS(null, \"height\", height.toString());\n svg.setAttributeNS(null, \"viewBox\", `0 0 ${width} ${height}`);\n return svg;\n}\nfunction svgToDataUrl(svg, removeControlCharacter) {\n let xhtml = new XMLSerializer().serializeToString(svg);\n if (removeControlCharacter) {\n xhtml = xhtml.replace(/[\\u0000-\\u0008\\v\\f\\u000E-\\u001F\\uD800-\\uDFFF\\uFFFE\\uFFFF]/gu, \"\");\n }\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(xhtml)}`;\n}\nasync function canvasToBlob(canvas, type = \"image/png\", quality = 1) {\n try {\n return await new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error(\"Blob is null\"));\n }\n }, type, quality);\n });\n } catch (error) {\n if (SUPPORT_ATOB) {\n return dataUrlToBlob(canvas.toDataURL(type, quality));\n }\n throw error;\n }\n}\nfunction dataUrlToBlob(dataUrl) {\n const [header, base64] = dataUrl.split(\",\");\n const type = header.match(/data:(.+);/)?.[1] ?? void 0;\n const decoded = window.atob(base64);\n const length = decoded.length;\n const buffer = new Uint8Array(length);\n for (let i = 0; i < length; i += 1) {\n buffer[i] = decoded.charCodeAt(i);\n }\n return new Blob([buffer], { type });\n}\nfunction readBlob(blob, type) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result);\n reader.onerror = () => reject(reader.error);\n reader.onabort = () => reject(new Error(`Failed read blob to ${type}`));\n if (type === \"dataUrl\") {\n reader.readAsDataURL(blob);\n } else if (type === \"arrayBuffer\") {\n reader.readAsArrayBuffer(blob);\n }\n });\n}\nconst blobToDataUrl = (blob) => readBlob(blob, \"dataUrl\");\nconst blobToArrayBuffer = (blob) => readBlob(blob, \"arrayBuffer\");\nfunction createImage(url, ownerDocument) {\n const img = getDocument(ownerDocument).createElement(\"img\");\n img.decoding = \"sync\";\n img.loading = \"eager\";\n img.src = url;\n return img;\n}\nfunction loadMedia(media, options) {\n return new Promise((resolve) => {\n const { timeout, ownerDocument, onError: userOnError, onWarn } = options ?? {};\n const node = typeof media === \"string\" ? createImage(media, getDocument(ownerDocument)) : media;\n let timer = null;\n let removeEventListeners = null;\n function onResolve() {\n resolve(node);\n timer && clearTimeout(timer);\n removeEventListeners?.();\n }\n if (timeout) {\n timer = setTimeout(onResolve, timeout);\n }\n if (isVideoElement(node)) {\n const currentSrc = node.currentSrc || node.src;\n if (!currentSrc) {\n if (node.poster) {\n return loadMedia(node.poster, options).then(resolve);\n }\n return onResolve();\n }\n if (node.readyState >= 2) {\n return onResolve();\n }\n const onLoadeddata = onResolve;\n const onError = (error) => {\n onWarn?.(\n \"Failed video load\",\n currentSrc,\n error\n );\n userOnError?.(error);\n onResolve();\n };\n removeEventListeners = () => {\n node.removeEventListener(\"loadeddata\", onLoadeddata);\n node.removeEventListener(\"error\", onError);\n };\n node.addEventListener(\"loadeddata\", onLoadeddata, { once: true });\n node.addEventListener(\"error\", onError, { once: true });\n } else {\n const currentSrc = isSVGImageElementNode(node) ? node.href.baseVal : node.currentSrc || node.src;\n if (!currentSrc) {\n return onResolve();\n }\n const onLoad = async () => {\n if (isImageElement(node) && \"decode\" in node) {\n try {\n await node.decode();\n } catch (error) {\n onWarn?.(\n \"Failed to decode image, trying to render anyway\",\n node.dataset.originalSrc || currentSrc,\n error\n );\n }\n }\n onResolve();\n };\n const onError = (error) => {\n onWarn?.(\n \"Failed image load\",\n node.dataset.originalSrc || currentSrc,\n error\n );\n onResolve();\n };\n if (isImageElement(node) && node.complete) {\n return onLoad();\n }\n removeEventListeners = () => {\n node.removeEventListener(\"load\", onLoad);\n node.removeEventListener(\"error\", onError);\n };\n node.addEventListener(\"load\", onLoad, { once: true });\n node.addEventListener(\"error\", onError, { once: true });\n }\n });\n}\nasync function waitUntilLoad(node, options) {\n if (isHTMLElementNode(node)) {\n if (isImageElement(node) || isVideoElement(node)) {\n await loadMedia(node, options);\n } else {\n await Promise.all(\n [\"img\", \"video\"].flatMap((selectors) => {\n return Array.from(node.querySelectorAll(selectors)).map((el) => loadMedia(el, options));\n })\n );\n }\n }\n}\nconst uuid = /* @__PURE__ */ function uuid2() {\n let counter = 0;\n const random = () => `0000${(Math.random() * 36 ** 4 << 0).toString(36)}`.slice(-4);\n return () => {\n counter += 1;\n return `u${random()}${counter}`;\n };\n}();\nfunction splitFontFamily(fontFamily) {\n return fontFamily?.split(\",\").map((val) => val.trim().replace(/\"|'/g, \"\").toLowerCase()).filter(Boolean);\n}\n\nlet uid = 0;\nfunction createLogger(debug) {\n const prefix = `${PREFIX}[#${uid}]`;\n uid++;\n return {\n // eslint-disable-next-line no-console\n time: (label) => debug && console.time(`${prefix} ${label}`),\n // eslint-disable-next-line no-console\n timeEnd: (label) => debug && console.timeEnd(`${prefix} ${label}`),\n warn: (...args) => debug && consoleWarn(...args)\n };\n}\n\nfunction getDefaultRequestInit(bypassingCache) {\n return {\n cache: bypassingCache ? \"no-cache\" : \"force-cache\"\n };\n}\n\nasync function orCreateContext(node, options) {\n return isContext(node) ? node : createContext(node, { ...options, autoDestruct: true });\n}\nasync function createContext(node, options) {\n const { scale = 1, workerUrl, workerNumber = 1 } = options || {};\n const debug = Boolean(options?.debug);\n const features = options?.features ?? true;\n const ownerDocument = node.ownerDocument ?? (IN_BROWSER ? window.document : void 0);\n const ownerWindow = node.ownerDocument?.defaultView ?? (IN_BROWSER ? window : void 0);\n const requests = /* @__PURE__ */ new Map();\n const context = {\n // Options\n width: 0,\n height: 0,\n quality: 1,\n type: \"image/png\",\n scale,\n backgroundColor: null,\n style: null,\n filter: null,\n maximumCanvasSize: 0,\n timeout: 3e4,\n progress: null,\n debug,\n fetch: {\n requestInit: getDefaultRequestInit(options?.fetch?.bypassingCache),\n placeholderImage: \"data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n bypassingCache: false,\n ...options?.fetch\n },\n fetchFn: null,\n font: {},\n drawImageInterval: 100,\n workerUrl: null,\n workerNumber,\n onCloneEachNode: null,\n onCloneNode: null,\n onEmbedNode: null,\n onCreateForeignObjectSvg: null,\n includeStyleProperties: null,\n autoDestruct: false,\n ...options,\n // InternalContext\n __CONTEXT__: true,\n log: createLogger(debug),\n node,\n ownerDocument,\n ownerWindow,\n dpi: scale === 1 ? null : 96 * scale,\n svgStyleElement: createStyleElement(ownerDocument),\n svgDefsElement: ownerDocument?.createElementNS(XMLNS, \"defs\"),\n svgStyles: /* @__PURE__ */ new Map(),\n defaultComputedStyles: /* @__PURE__ */ new Map(),\n workers: [\n ...Array.from({\n length: SUPPORT_WEB_WORKER && workerUrl && workerNumber ? workerNumber : 0\n })\n ].map(() => {\n try {\n const worker = new Worker(workerUrl);\n worker.onmessage = async (event) => {\n const { url, result } = event.data;\n if (result) {\n requests.get(url)?.resolve?.(result);\n } else {\n requests.get(url)?.reject?.(new Error(`Error receiving message from worker: ${url}`));\n }\n };\n worker.onmessageerror = (event) => {\n const { url } = event.data;\n requests.get(url)?.reject?.(new Error(`Error receiving message from worker: ${url}`));\n };\n return worker;\n } catch (error) {\n context.log.warn(\"Failed to new Worker\", error);\n return null;\n }\n }).filter(Boolean),\n fontFamilies: /* @__PURE__ */ new Map(),\n fontCssTexts: /* @__PURE__ */ new Map(),\n acceptOfImage: `${[\n supportWebp(ownerDocument) && \"image/webp\",\n \"image/svg+xml\",\n \"image/*\",\n \"*/*\"\n ].filter(Boolean).join(\",\")};q=0.8`,\n requests,\n drawImageCount: 0,\n tasks: [],\n features,\n isEnable: (key) => {\n if (key === \"restoreScrollPosition\") {\n return typeof features === \"boolean\" ? false : features[key] ?? false;\n }\n if (typeof features === \"boolean\") {\n return features;\n }\n return features[key] ?? true;\n },\n shadowRoots: []\n };\n context.log.time(\"wait until load\");\n await waitUntilLoad(node, { timeout: context.timeout, onWarn: context.log.warn });\n context.log.timeEnd(\"wait until load\");\n const { width, height } = resolveBoundingBox(node, context);\n context.width = width;\n context.height = height;\n return context;\n}\nfunction createStyleElement(ownerDocument) {\n if (!ownerDocument)\n return void 0;\n const style = ownerDocument.createElement(\"style\");\n const cssText = style.ownerDocument.createTextNode(`\n.______background-clip--text {\n background-clip: text;\n -webkit-background-clip: text;\n}\n`);\n style.appendChild(cssText);\n return style;\n}\nfunction resolveBoundingBox(node, context) {\n let { width, height } = context;\n if (isElementNode(node) && (!width || !height)) {\n const box = node.getBoundingClientRect();\n width = width || box.width || Number(node.getAttribute(\"width\")) || 0;\n height = height || box.height || Number(node.getAttribute(\"height\")) || 0;\n }\n return { width, height };\n}\n\nasync function imageToCanvas(image, context) {\n const {\n log,\n timeout,\n drawImageCount,\n drawImageInterval\n } = context;\n log.time(\"image to canvas\");\n const loaded = await loadMedia(image, { timeout, onWarn: context.log.warn });\n const { canvas, context2d } = createCanvas(image.ownerDocument, context);\n const drawImage = () => {\n try {\n context2d?.drawImage(loaded, 0, 0, canvas.width, canvas.height);\n } catch (error) {\n context.log.warn(\"Failed to drawImage\", error);\n }\n };\n drawImage();\n if (context.isEnable(\"fixSvgXmlDecode\")) {\n for (let i = 0; i < drawImageCount; i++) {\n await new Promise((resolve) => {\n setTimeout(() => {\n context2d?.clearRect(0, 0, canvas.width, canvas.height);\n drawImage();\n resolve();\n }, i + drawImageInterval);\n });\n }\n }\n context.drawImageCount = 0;\n log.timeEnd(\"image to canvas\");\n return canvas;\n}\nfunction createCanvas(ownerDocument, context) {\n const { width, height, scale, backgroundColor, maximumCanvasSize: max } = context;\n const canvas = ownerDocument.createElement(\"canvas\");\n canvas.width = Math.floor(width * scale);\n canvas.height = Math.floor(height * scale);\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n if (max) {\n if (canvas.width > max || canvas.height > max) {\n if (canvas.width > max && canvas.height > max) {\n if (canvas.width > canvas.height) {\n canvas.height *= max / canvas.width;\n canvas.width = max;\n } else {\n canvas.width *= max / canvas.height;\n canvas.height = max;\n }\n } else if (canvas.width > max) {\n canvas.height *= max / canvas.width;\n canvas.width = max;\n } else {\n canvas.width *= max / canvas.height;\n canvas.height = max;\n }\n }\n }\n const context2d = canvas.getContext(\"2d\");\n if (context2d && backgroundColor) {\n context2d.fillStyle = backgroundColor;\n context2d.fillRect(0, 0, canvas.width, canvas.height);\n }\n return { canvas, context2d };\n}\n\nfunction cloneCanvas(canvas, context) {\n if (canvas.ownerDocument) {\n try {\n const dataURL = canvas.toDataURL();\n if (dataURL !== \"data:,\") {\n return createImage(dataURL, canvas.ownerDocument);\n }\n } catch (error) {\n context.log.warn(\"Failed to clone canvas\", error);\n }\n }\n const cloned = canvas.cloneNode(false);\n const ctx = canvas.getContext(\"2d\");\n const clonedCtx = cloned.getContext(\"2d\");\n try {\n if (ctx && clonedCtx) {\n clonedCtx.putImageData(\n ctx.getImageData(0, 0, canvas.width, canvas.height),\n 0,\n 0\n );\n }\n return cloned;\n } catch (error) {\n context.log.warn(\"Failed to clone canvas\", error);\n }\n return cloned;\n}\n\nfunction cloneIframe(iframe, context) {\n try {\n if (iframe?.contentDocument?.documentElement) {\n return cloneNode(iframe.contentDocument.documentElement, context);\n }\n } catch (error) {\n context.log.warn(\"Failed to clone iframe\", error);\n }\n return iframe.cloneNode(false);\n}\n\nfunction cloneImage(image) {\n const cloned = image.cloneNode(false);\n if (image.currentSrc && image.currentSrc !== image.src) {\n cloned.src = image.currentSrc;\n cloned.srcset = \"\";\n }\n if (cloned.loading === \"lazy\") {\n cloned.loading = \"eager\";\n }\n return cloned;\n}\n\nasync function cloneVideo(video, context) {\n if (video.ownerDocument && !video.currentSrc && video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n const cloned = video.cloneNode(false);\n cloned.crossOrigin = \"anonymous\";\n if (video.currentSrc && video.currentSrc !== video.src) {\n cloned.src = video.currentSrc;\n }\n const ownerDocument = cloned.ownerDocument;\n if (ownerDocument) {\n let canPlay = true;\n await loadMedia(cloned, { onError: () => canPlay = false, onWarn: context.log.warn });\n if (!canPlay) {\n if (video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n return cloned;\n }\n cloned.currentTime = video.currentTime;\n await new Promise((resolve) => {\n cloned.addEventListener(\"seeked\", resolve, { once: true });\n });\n const canvas = ownerDocument.createElement(\"canvas\");\n canvas.width = video.offsetWidth;\n canvas.height = video.offsetHeight;\n try {\n const ctx = canvas.getContext(\"2d\");\n if (ctx)\n ctx.drawImage(cloned, 0, 0, canvas.width, canvas.height);\n } catch (error) {\n context.log.warn(\"Failed to clone video\", error);\n if (video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n return cloned;\n }\n return cloneCanvas(canvas, context);\n }\n return cloned;\n}\n\nfunction cloneElement(node, context) {\n if (isCanvasElement(node)) {\n return cloneCanvas(node, context);\n }\n if (isIFrameElement(node)) {\n return cloneIframe(node, context);\n }\n if (isImageElement(node)) {\n return cloneImage(node);\n }\n if (isVideoElement(node)) {\n return cloneVideo(node, context);\n }\n return node.cloneNode(false);\n}\n\nfunction getSandBox(context) {\n let sandbox = context.sandbox;\n if (!sandbox) {\n const { ownerDocument } = context;\n try {\n if (ownerDocument) {\n sandbox = ownerDocument.createElement(\"iframe\");\n sandbox.id = `__SANDBOX__${uuid()}`;\n sandbox.width = \"0\";\n sandbox.height = \"0\";\n sandbox.style.visibility = \"hidden\";\n sandbox.style.position = \"fixed\";\n ownerDocument.body.appendChild(sandbox);\n sandbox.srcdoc = '<!DOCTYPE html><meta charset=\"UTF-8\"><title></title><body>';\n context.sandbox = sandbox;\n }\n } catch (error) {\n context.log.warn(\"Failed to getSandBox\", error);\n }\n }\n return sandbox;\n}\n\nconst ignoredStyles = [\n \"width\",\n \"height\",\n \"-webkit-text-fill-color\"\n];\nconst includedAttributes = [\n \"stroke\",\n \"fill\"\n];\nfunction getDefaultStyle(node, pseudoElement, context) {\n const { defaultComputedStyles } = context;\n const nodeName = node.nodeName.toLowerCase();\n const isSvgNode = isSVGElementNode(node) && nodeName !== \"svg\";\n const attributes = isSvgNode ? includedAttributes.map((name) => [name, node.getAttribute(name)]).filter(([, value]) => value !== null) : [];\n const key = [\n isSvgNode && \"svg\",\n nodeName,\n attributes.map((name, value) => `${name}=${value}`).join(\",\"),\n pseudoElement\n ].filter(Boolean).join(\":\");\n if (defaultComputedStyles.has(key))\n return defaultComputedStyles.get(key);\n const sandbox = getSandBox(context);\n const sandboxWindow = sandbox?.contentWindow;\n if (!sandboxWindow)\n return /* @__PURE__ */ new Map();\n const sandboxDocument = sandboxWindow?.document;\n let root;\n let el;\n if (isSvgNode) {\n root = sandboxDocument.createElementNS(XMLNS, \"svg\");\n el = root.ownerDocument.createElementNS(root.namespaceURI, nodeName);\n attributes.forEach(([name, value]) => {\n el.setAttributeNS(null, name, value);\n });\n root.appendChild(el);\n } else {\n root = el = sandboxDocument.createElement(nodeName);\n }\n el.textContent = \" \";\n sandboxDocument.body.appendChild(root);\n const computedStyle = sandboxWindow.getComputedStyle(el, pseudoElement);\n const styles = /* @__PURE__ */ new Map();\n for (let len = computedStyle.length, i = 0; i < len; i++) {\n const name = computedStyle.item(i);\n if (ignoredStyles.includes(name))\n continue;\n styles.set(name, computedStyle.getPropertyValue(name));\n }\n sandboxDocument.body.removeChild(root);\n defaultComputedStyles.set(key, styles);\n return styles;\n}\n\nfunction getDiffStyle(style, defaultStyle, includeStyleProperties) {\n const diffStyle = /* @__PURE__ */ new Map();\n const prefixs = [];\n const prefixTree = /* @__PURE__ */ new Map();\n if (includeStyleProperties) {\n for (const name of includeStyleProperties) {\n applyTo(name);\n }\n } else {\n for (let len = style.length, i = 0; i < len; i++) {\n const name = style.item(i);\n applyTo(name);\n }\n }\n for (let len = prefixs.length, i = 0; i < len; i++) {\n prefixTree.get(prefixs[i])?.forEach((value, name) => diffStyle.set(name, value));\n }\n function applyTo(name) {\n const value = style.getPropertyValue(name);\n const priority = style.getPropertyPriority(name);\n const subIndex = name.lastIndexOf(\"-\");\n const prefix = subIndex > -1 ? name.substring(0, subIndex) : void 0;\n if (prefix) {\n let map = prefixTree.get(prefix);\n if (!map) {\n map = /* @__PURE__ */ new Map();\n prefixTree.set(prefix, map);\n }\n map.set(name, [value, priority]);\n }\n if (defaultStyle.get(name) === value && !priority)\n return;\n if (prefix) {\n prefixs.push(prefix);\n } else {\n diffStyle.set(name, [value, priority]);\n }\n }\n return diffStyle;\n}\n\nfunction copyCssStyles(node, cloned, isRoot, context) {\n const { ownerWindow, includeStyleProperties, currentParentNodeStyle } = context;\n const clonedStyle = cloned.style;\n const computedStyle = ownerWindow.getComputedStyle(node);\n const defaultStyle = getDefaultStyle(node, null, context);\n currentParentNodeStyle?.forEach((_, key) => {\n defaultStyle.delete(key);\n });\n const style = getDiffStyle(computedStyle, defaultStyle, includeStyleProperties);\n style.delete(\"transition-property\");\n style.delete(\"all\");\n style.delete(\"d\");\n style.delete(\"content\");\n if (isRoot) {\n style.delete(\"position\");\n style.delete(\"margin-top\");\n style.delete(\"margin-right\");\n style.delete(\"margin-bottom\");\n style.delete(\"margin-left\");\n style.delete(\"margin-block-start\");\n style.delete(\"margin-block-end\");\n style.delete(\"margin-inline-start\");\n style.delete(\"margin-inline-end\");\n style.set(\"box-sizing\", [\"border-box\", \"\"]);\n }\n if (style.get(\"background-clip\")?.[0] === \"text\") {\n cloned.classList.add(\"______background-clip--text\");\n }\n if (IN_CHROME) {\n if (!style.has(\"font-kerning\"))\n style.set(\"font-kerning\", [\"normal\", \"\"]);\n if ((style.get(\"overflow-x\")?.[0] === \"hidden\" || style.get(\"overflow-y\")?.[0] === \"hidden\") && style.get(\"text-overflow\")?.[0] === \"ellipsis\" && node.scrollWidth === node.clientWidth) {\n style.set(\"text-overflow\", [\"clip\", \"\"]);\n }\n }\n for (let len = clonedStyle.length, i = 0; i < len; i++) {\n clonedStyle.removeProperty(clonedStyle.item(i));\n }\n style.forEach(([value, priority], name) => {\n clonedStyle.setProperty(name, value, priority);\n });\n return style;\n}\n\nfunction copyInputValue(node, cloned) {\n if (isTextareaElement(node) || isInputElement(node) || isSelectElement(node)) {\n cloned.setAttribute(\"value\", node.value);\n }\n}\n\nconst pseudoClasses = [\n \"::before\",\n \"::after\"\n // '::placeholder', TODO\n];\nconst scrollbarPseudoClasses = [\n \"::-webkit-scrollbar\",\n \"::-webkit-scrollbar-button\",\n // '::-webkit-scrollbar:horizontal', TODO\n \"::-webkit-scrollbar-thumb\",\n \"::-webkit-scrollbar-track\",\n \"::-webkit-scrollbar-track-piece\",\n // '::-webkit-scrollbar:vertical', TODO\n \"::-webkit-scrollbar-corner\",\n \"::-webkit-resizer\"\n];\nfunction copyPseudoClass(node, cloned, copyScrollbar, context, addWordToFontFamilies) {\n const { ownerWindow, svgStyleElement, svgStyles, currentNodeStyle } = context;\n if (!svgStyleElement || !ownerWindow)\n return;\n function copyBy(pseudoClass) {\n const computedStyle = ownerWindow.getComputedStyle(node, pseudoClass);\n let content = computedStyle.getPropertyValue(\"content\");\n if (!content || content === \"none\")\n return;\n addWordToFontFamilies?.(content);\n content = content.replace(/(')|(\")|(counter\\(.+\\))/g, \"\");\n const klasses = [uuid()];\n const defaultStyle = getDefaultStyle(node, pseudoClass, context);\n currentNodeStyle?.forEach((_, key) => {\n defaultStyle.delete(key);\n });\n const style = getDiffStyle(computedStyle, defaultStyle, context.includeStyleProperties);\n style.delete(\"content\");\n style.delete(\"-webkit-locale\");\n if (style.get(\"background-clip\")?.[0] === \"text\") {\n cloned.classList.add(\"______background-clip--text\");\n }\n const cloneStyle = [\n `content: '${content}';`\n ];\n style.forEach(([value, priority], name) => {\n cloneStyle.push(`${name}: ${value}${priority ? \" !important\" : \"\"};`);\n });\n if (cloneStyle.length === 1)\n return;\n try {\n cloned.className = [cloned.className, ...klasses].join(\" \");\n } catch (err) {\n context.log.warn(\"Failed to copyPseudoClass\", err);\n return;\n }\n const cssText = cloneStyle.join(\"\\n \");\n let allClasses = svgStyles.get(cssText);\n if (!allClasses) {\n allClasses = [];\n svgStyles.set(cssText, allClasses);\n }\n allClasses.push(`.${klasses[0]}${pseudoClass}`);\n }\n pseudoClasses.forEach(copyBy);\n if (copyScrollbar)\n scrollbarPseudoClasses.forEach(copyBy);\n}\n\nconst excludeParentNodes = /* @__PURE__ */ new Set([\n \"symbol\"\n // test/fixtures/svg.symbol.html\n]);\nasync function appendChildNode(node, cloned, child, context, addWordToFontFamilies) {\n if (isElementNode(child) && (isStyleElement(child) || isScriptElement(child)))\n return;\n if (context.filter && !context.filter(child))\n return;\n if (excludeParentNodes.has(cloned.nodeName) || excludeParentNodes.has(child.nodeName)) {\n context.currentParentNodeStyle = void 0;\n } else {\n context.currentParentNodeStyle = context.currentNodeStyle;\n }\n const childCloned = await cloneNode(child, context, false, addWordToFontFamilies);\n if (context.isEnable(\"restoreScrollPosition\")) {\n restoreScrollPosition(node, childCloned);\n }\n cloned.appendChild(childCloned);\n}\nasync function cloneChildNodes(node, cloned, context, addWordToFontFamilies) {\n let firstChild = node.firstChild;\n if (isElementNode(node)) {\n if (node.shadowRoot) {\n firstChild = node.shadowRoot?.firstChild;\n context.shadowRoots.push(node.shadowRoot);\n }\n }\n for (let child = firstChild; child; child = child.nextSibling) {\n if (isCommentNode(child))\n continue;\n if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === \"function\") {\n const nodes = child.assignedNodes();\n for (let i = 0; i < nodes.length; i++) {\n await appendChildNode(node, cloned, nodes[i], context, addWordToFontFamilies);\n }\n } else {\n await appendChildNode(node, cloned, child, context, addWordToFontFamilies);\n }\n }\n}\nfunction restoreScrollPosition(node, chlidCloned) {\n if (!isHTMLElementNode(node) || !isHTMLElementNode(chlidCloned))\n return;\n const { scrollTop, scrollLeft } = node;\n if (!scrollTop && !scrollLeft) {\n return;\n }\n const { transform } = chlidCloned.style;\n const matrix = new DOMMatrix(transform);\n const { a, b, c, d } = matrix;\n matrix.a = 1;\n matrix.b = 0;\n matrix.c = 0;\n matrix.d = 1;\n matrix.translateSelf(-scrollLeft, -scrollTop);\n matrix.a = a;\n matrix.b = b;\n matrix.c = c;\n matrix.d = d;\n chlidCloned.style.transform = matrix.toString();\n}\nfunction applyCssStyleWithOptions(cloned, context) {\n const { backgroundColor, width, height, style: styles } = context;\n const clonedStyle = cloned.style;\n if (backgroundColor)\n clonedStyle.setProperty(\"background-color\", backgroundColor, \"important\");\n if (width)\n clonedStyle.setProperty(\"width\", `${width}px`, \"important\");\n if (height)\n clonedStyle.setProperty(\"height\", `${height}px`, \"important\");\n if (styles) {\n for (const name in styles) clonedStyle[name] = styles[name];\n }\n}\nconst NORMAL_ATTRIBUTE_RE = /^[\\w-:]+$/;\nasync function cloneNode(node, context, isRoot = false, addWordToFontFamilies) {\n const { ownerDocument, ownerWindow, fontFamilies, onCloneEachNode } = context;\n if (ownerDocument && isTextNode(node)) {\n if (addWordToFontFamilies && /\\S/.test(node.data)) {\n addWordToFontFamilies(node.data);\n }\n return ownerDocument.createTextNode(node.data);\n }\n if (ownerDocument && ownerWindow && isElementNode(node) && (isHTMLElementNode(node) || isSVGElementNode(node))) {\n const cloned2 = await cloneElement(node, context);\n if (context.isEnable(\"removeAbnormalAttributes\")) {\n const names = cloned2.getAttributeNames();\n for (let len = names.length, i = 0; i < len; i++) {\n const name = names[i];\n if (!NORMAL_ATTRIBUTE_RE.test(name)) {\n cloned2.removeAttribute(name);\n }\n }\n }\n const style = context.currentNodeStyle = copyCssStyles(node, cloned2, isRoot, context);\n if (isRoot)\n applyCssStyleWithOptions(cloned2, context);\n let copyScrollbar = false;\n if (context.isEnable(\"copyScrollbar\")) {\n const overflow = [\n style.get(\"overflow-x\")?.[0],\n style.get(\"overflow-y\")?.[0]\n ];\n copyScrollbar = overflow.includes(\"scroll\") || (overflow.includes(\"auto\") || overflow.includes(\"overlay\")) && (node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth);\n }\n const textTransform = style.get(\"text-transform\")?.[0];\n const families = splitFontFamily(style.get(\"font-family\")?.[0]);\n const addWordToFontFamilies2 = families ? (word) => {\n if (textTransform === \"uppercase\") {\n word = word.toUpperCase();\n } else if (textTransform === \"lowercase\") {\n word = word.toLowerCase();\n } else if (textTransform === \"capitalize\") {\n word = word[0].toUpperCase() + word.substring(1);\n }\n families.forEach((family) => {\n let fontFamily = fontFamilies.get(family);\n if (!fontFamily) {\n fontFamilies.set(family, fontFamily = /* @__PURE__ */ new Set());\n }\n word.split(\"\").forEach((text) => fontFamily.add(text));\n });\n } : void 0;\n copyPseudoClass(\n node,\n cloned2,\n copyScrollbar,\n context,\n addWordToFontFamilies2\n );\n copyInputValue(node, cloned2);\n if (!isVideoElement(node)) {\n await cloneChildNodes(\n node,\n cloned2,\n context,\n addWordToFontFamilies2\n );\n }\n await onCloneEachNode?.(cloned2);\n return cloned2;\n }\n const cloned = node.cloneNode(false);\n await cloneChildNodes(node, cloned, context);\n await onCloneEachNode?.(cloned);\n return cloned;\n}\n\nfunction destroyContext(context) {\n context.ownerDocument = void 0;\n context.ownerWindow = void 0;\n context.svgStyleElement = void 0;\n context.svgDefsElement = void 0;\n context.svgStyles.clear();\n context.defaultComputedStyles.clear();\n if (context.sandbox) {\n try {\n context.sandbox.remove();\n } catch (err) {\n context.log.warn(\"Failed to destroyContext\", err);\n }\n context.sandbox = void 0;\n }\n context.workers = [];\n context.fontFamilies.clear();\n context.fontCssTexts.clear();\n context.requests.clear();\n context.tasks = [];\n context.shadowRoots = [];\n}\n\nfunction baseFetch(options) {\n const { url, timeout, responseType, ...requestInit } = options;\n const controller = new AbortController();\n const timer = timeout ? setTimeout(() => controller.abort(), timeout) : void 0;\n return fetch(url, { signal: controller.signal, ...requestInit }).then((response) => {\n if (!response.ok) {\n throw new Error(\"Failed fetch, not 2xx response\", { cause: response });\n }\n switch (responseType) {\n case \"arrayBuffer\":\n return response.arrayBuffer();\n case \"dataUrl\":\n return response.blob().then(blobToDataUrl);\n case \"text\":\n default:\n return response.text();\n }\n }).finally(() => clearTimeout(timer));\n}\nfunction contextFetch(context, options) {\n const { url: rawUrl, requestType = \"text\", responseType = \"text\", imageDom } = options;\n let url = rawUrl;\n const {\n timeout,\n acceptOfImage,\n requests,\n fetchFn,\n fetch: {\n requestInit,\n bypassingCache,\n placeholderImage\n },\n font,\n workers,\n fontFamilies\n } = context;\n if (requestType === \"image\" && (IN_SAFARI || IN_FIREFOX)) {\n context.drawImageCount++;\n }\n let request = requests.get(rawUrl);\n if (!request) {\n if (bypassingCache) {\n if (bypassingCache instanceof RegExp && bypassingCache.test(url)) {\n url += (/\\?/.test(url) ? \"&\" : \"?\") + (/* @__PURE__ */ new Date()).getTime();\n }\n }\n const canFontMinify = requestType.startsWith(\"font\") && font && font.minify;\n const fontTexts = /* @__PURE__ */ new Set();\n if (canFontMinify) {\n const families = requestType.split(\";\")[1].split(\",\");\n families.forEach((family) => {\n if (!fontFamilies.has(family))\n return;\n fontFamilies.get(family).forEach((text) => fontTexts.add(text));\n });\n }\n const needFontMinify = canFontMinify && fontTexts.size;\n const baseFetchOptions = {\n url,\n timeout,\n responseType: needFontMinify ? \"arrayBuffer\" : responseType,\n headers: requestType === \"image\" ? { accept: acceptOfImage } : void 0,\n ...requestInit\n };\n request = {\n type: requestType,\n resolve: void 0,\n reject: void 0,\n response: null\n };\n request.response = (async () => {\n if (fetchFn && requestType === \"image\") {\n const result = await fetchFn(rawUrl);\n if (result)\n return result;\n }\n if (!IN_SAFARI && rawUrl.startsWith(\"http\") && workers.length) {\n return new Promise((resolve, reject) => {\n const worker = workers[requests.size & workers.length - 1];\n worker.postMessage({ rawUrl, ...baseFetchOptions });\n request.resolve = resolve;\n request.reject = reject;\n });\n }\n return baseFetch(baseFetchOptions);\n })().catch((error) => {\n requests.delete(rawUrl);\n if (requestType === \"image\" && placeholderImage) {\n context.log.warn(\"Failed to fetch image base64, trying to use placeholder image\", url);\n return typeof placeholderImage === \"string\" ? placeholderImage : placeholderImage(imageDom);\n }\n throw error;\n });\n requests.set(rawUrl, request);\n }\n return request.response;\n}\n\nasync function replaceCssUrlToDataUrl(cssText, baseUrl, context, isImage) {\n if (!hasCssUrl(cssText))\n return cssText;\n for (const [rawUrl, url] of parseCssUrls(cssText, baseUrl)) {\n try {\n const dataUrl = await contextFetch(\n context,\n {\n url,\n requestType: isImage ? \"image\" : \"text\",\n responseType: \"dataUrl\"\n }\n );\n cssText = cssText.replace(toRE(rawUrl), `$1${dataUrl}$3`);\n } catch (error) {\n context.log.warn(\"Failed to fetch css data url\", rawUrl, error);\n }\n }\n return cssText;\n}\nfunction hasCssUrl(cssText) {\n return /url\\((['\"]?)([^'\"]+?)\\1\\)/.test(cssText);\n}\nconst URL_RE = /url\\((['\"]?)([^'\"]+?)\\1\\)/g;\nfunction parseCssUrls(cssText, baseUrl) {\n const result = [];\n cssText.replace(URL_RE, (raw, quotation, url) => {\n result.push([url, resolveUrl(url, baseUrl)]);\n return raw;\n });\n return result.filter(([url]) => !isDataUrl(url));\n}\nfunction toRE(url) {\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, \"\\\\$1\");\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, \"g\");\n}\n\nconst properties = [\n \"background-image\",\n \"border-image-source\",\n \"-webkit-border-image\",\n \"-webkit-mask-image\",\n \"list-style-image\"\n];\nfunction embedCssStyleImage(style, context) {\n return properties.map((property) => {\n const value = style.getPropertyValue(property);\n if (!value || value === \"none\") {\n return null;\n }\n if (IN_SAFARI || IN_FIREFOX) {\n context.drawImageCount++;\n }\n return replaceCssUrlToDataUrl(value, null, context, true).then((newValue) => {\n if (!newValue || value === newValue)\n return;\n style.setProperty(\n property,\n newValue,\n style.getPropertyPriority(property)\n );\n });\n }).filter(Boolean);\n}\n\nfunction embedImageElement(cloned, context) {\n if (isImageElement(cloned)) {\n const originalSrc = cloned.currentSrc || cloned.src;\n if (!isDataUrl(originalSrc)) {\n return [\n contextFetch(context, {\n url: originalSrc,\n imageDom: cloned,\n requestType: \"image\",\n responseType: \"dataUrl\"\n }).then((url) => {\n if (!url)\n return;\n cloned.srcset = \"\";\n cloned.dataset.originalSrc = originalSrc;\n cloned.src = url || \"\";\n })\n ];\n }\n if (IN_SAFARI || IN_FIREFOX) {\n context.drawImageCount++;\n }\n } else if (isSVGElementNode(cloned) && !isDataUrl(cloned.href.baseVal)) {\n const originalSrc = cloned.href.baseVal;\n return [\n contextFetch(context, {\n url: originalSrc,\n imageDom: cloned,\n requestType: \"image\",\n responseType: \"dataUrl\"\n }).then((url) => {\n if (!url)\n return;\n cloned.dataset.originalSrc = originalSrc;\n cloned.href.baseVal = url || \"\";\n })\n ];\n }\n return [];\n}\n\nfunction embedSvgUse(cloned, context) {\n const { ownerDocument, svgDefsElement } = context;\n const href = cloned.getAttribute(\"href\") ?? cloned.getAttribute(\"xlink:href\");\n if (!href)\n return [];\n const [svgUrl, id] = href.split(\"#\");\n if (id) {\n const query = `#${id}`;\n const definition = context.shadowRoots.reduce(\n (res, root) => {\n return res ?? root.querySelector(`svg ${query}`);\n },\n ownerDocument?.querySelector(`svg ${query}`)\n );\n if (svgUrl) {\n cloned.setAttribute(\"href\", query);\n }\n if (svgDefsElement?.querySelector(query))\n return [];\n if (definition) {\n svgDefsElement?.appendChild(definition.cloneNode(true));\n return [];\n } else if (svgUrl) {\n return [\n contextFetch(context, {\n url: svgUrl,\n responseType: \"text\"\n }).then((svgData) => {\n svgDefsElement?.insertAdjacentHTML(\"beforeend\", svgData);\n })\n ];\n }\n }\n return [];\n}\n\nfunction embedNode(cloned, context) {\n const { tasks } = context;\n if (isElementNode(cloned)) {\n if (isImageElement(cloned) || isSVGImageElementNode(cloned)) {\n tasks.push(...embedImageElement(cloned, context));\n }\n if (isSVGUseElementNode(cloned)) {\n tasks.push(...embedSvgUse(cloned, context));\n }\n }\n if (isHTMLElementNode(cloned)) {\n tasks.push(...embedCssStyleImage(cloned.style, context));\n }\n cloned.childNodes.forEach((child) => {\n embedNode(child, context);\n });\n}\n\nasync function embedWebFont(clone, context) {\n const {\n ownerDocument,\n svgStyleElement,\n fontFamilies,\n fontCssTexts,\n tasks,\n font\n } = context;\n if (!ownerDocument || !svgStyleElement || !fontFamilies.size) {\n return;\n }\n if (font && font.cssText) {\n const cssText = filterPreferredFormat(font.cssText, context);\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText}\n`));\n } else {\n const styleSheets = Array.from(ownerDocument.styleSheets).filter((styleSheet) => {\n try {\n return \"cssRules\" in styleSheet && Boolean(styleSheet.cssRules.length);\n } catch (error) {\n context.log.warn(`Error while reading CSS rules from ${styleSheet.href}`, error);\n return false;\n }\n });\n const tempDoc = ownerDocument.implementation.createHTMLDocument(\"\");\n const tempStyleEl = tempDoc.createElement(\"style\");\n tempDoc.head.appendChild(tempStyleEl);\n const tempStyleSheet = tempStyleEl.sheet;\n await Promise.all(\n styleSheets.flatMap((styleSheet) => {\n return Array.from(styleSheet.cssRules).map(async (cssRule) => {\n if (isCSSImportRule(cssRule)) {\n const baseUrl = cssRule.href;\n let cssText = \"\";\n try {\n cssText = await contextFetch(context, {\n url: baseUrl,\n requestType: \"text\",\n responseType: \"text\"\n });\n } catch (error) {\n context.log.warn(`Error fetch remote css import from ${baseUrl}`, error);\n }\n const replacedCssText = cssText.replace(\n URL_RE,\n (raw, quotation, url) => raw.replace(url, resolveUrl(url, baseUrl))\n );\n for (const rule of parseCss(replacedCssText)) {\n try {\n tempStyleSheet.insertRule(rule, tempStyleSheet.cssRules.length);\n } catch (error) {\n context.log.warn(\"Error inserting rule from remote css import\", { rule, error });\n }\n }\n }\n });\n })\n );\n if (tempStyleSheet.cssRules.length)\n styleSheets.push(tempStyleSheet);\n const cssRules = [];\n styleSheets.forEach((sheet) => {\n unwrapCssLayers(sheet.cssRules, cssRules);\n });\n cssRules.filter((cssRule) => isCssFontFaceRule(cssRule) && hasCssUrl(cssRule.style.getPropertyValue(\"src\")) && splitFontFamily(cssRule.style.getPropertyValue(\"font-family\"))?.some((val) => fontFamilies.has(val))).forEach((value) => {\n const rule = value;\n const cssText = fontCssTexts.get(rule.cssText);\n if (cssText) {\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText}\n`));\n } else {\n tasks.push(\n replaceCssUrlToDataUrl(\n rule.cssText,\n rule.parentStyleSheet ? rule.parentStyleSheet.href : null,\n context\n ).then((cssText2) => {\n cssText2 = filterPreferredFormat(cssText2, context);\n fontCssTexts.set(rule.cssText, cssText2);\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText2}\n`));\n })\n );\n }\n });\n }\n}\nconst COMMENTS_RE = /(\\/\\*[\\s\\S]*?\\*\\/)/g;\nconst KEYFRAMES_RE = /((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})/gi;\nfunction parseCss(source) {\n if (source == null)\n return [];\n const result = [];\n let cssText = source.replace(COMMENTS_RE, \"\");\n while (true) {\n const matches = KEYFRAMES_RE.exec(cssText);\n if (!matches)\n break;\n result.push(matches[0]);\n }\n cssText = cssText.replace(KEYFRAMES_RE, \"\");\n const IMPORT_RE = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi;\n const UNIFIED_RE = new RegExp(\n // eslint-disable-next-line\n \"((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})\",\n \"gi\"\n );\n while (true) {\n let matches = IMPORT_RE.exec(cssText);\n if (!matches) {\n matches = UNIFIED_RE.exec(cssText);\n if (!matches) {\n break;\n } else {\n IMPORT_RE.lastIndex = UNIFIED_RE.lastIndex;\n }\n } else {\n UNIFIED_RE.lastIndex = IMPORT_RE.lastIndex;\n }\n result.push(matches[0]);\n }\n return result;\n}\nconst URL_WITH_FORMAT_RE = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g;\nconst FONT_SRC_RE = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g;\nfunction filterPreferredFormat(str, context) {\n const { font } = context;\n const preferredFormat = font ? font?.preferredFormat : void 0;\n return preferredFormat ? str.replace(FONT_SRC_RE, (match) => {\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_RE.exec(match) || [];\n if (!format)\n return \"\";\n if (format === preferredFormat)\n return `src: ${src};`;\n }\n }) : str;\n}\nfunction unwrapCssLayers(rules, out = []) {\n for (const rule of Array.from(rules)) {\n if (isLayerBlockRule(rule)) {\n out.push(...unwrapCssLayers(rule.cssRules));\n } else if (\"cssRules\" in rule) {\n unwrapCssLayers(rule.cssRules, out);\n } else {\n out.push(rule);\n }\n }\n return out;\n}\n\nconst SVG_EXTERNAL_RESOURCE_REGEX = /\\bx?link:?href\\s*=\\s*[\"'](?!data:)[^\"']+[\"']/i;\nfunction svgHasExternalResources(svg) {\n return SVG_EXTERNAL_RESOURCE_REGEX.test(svg.innerHTML);\n}\nasync function domToForeignObjectSvg(node, options) {\n const context = await orCreateContext(node, options);\n if (isElementNode(context.node) && isSVGElementNode(context.node) && !svgHasExternalResources(context.node))\n return context.node;\n const {\n ownerDocument,\n log,\n tasks,\n svgStyleElement,\n svgDefsElement,\n svgStyles,\n font,\n progress,\n autoDestruct,\n onCloneNode,\n onEmbedNode,\n onCreateForeignObjectSvg\n } = context;\n log.time(\"clone node\");\n const clone = await cloneNode(context.node, context, true);\n if (svgStyleElement && ownerDocument) {\n let allCssText = \"\";\n svgStyles.forEach((klasses, cssText) => {\n allCssText += `${klasses.join(\",\\n\")} {\n ${cssText}\n}\n`;\n });\n svgStyleElement.appendChild(ownerDocument.createTextNode(allCssText));\n }\n log.timeEnd(\"clone node\");\n await onCloneNode?.(clone);\n if (font !== false && isElementNode(clone)) {\n log.time(\"embed web font\");\n await embedWebFont(clone, context);\n log.timeEnd(\"embed web font\");\n }\n log.time(\"embed node\");\n embedNode(clone, context);\n const count = tasks.length;\n let current = 0;\n const runTask = async () => {\n while (true) {\n const task = tasks.pop();\n if (!task)\n break;\n try {\n await task;\n } catch (error) {\n context.log.warn(\"Failed to run task\", error);\n }\n progress?.(++current, count);\n }\n };\n progress?.(current, count);\n await Promise.all([...Array.from({ length: 4 })].map(runTask));\n log.timeEnd(\"embed node\");\n await onEmbedNode?.(clone);\n const svg = createForeignObjectSvg(clone, context);\n svgDefsElement && svg.insertBefore(svgDefsElement, svg.children[0]);\n svgStyleElement && svg.insertBefore(svgStyleElement, svg.children[0]);\n autoDestruct && destroyContext(context);\n await onCreateForeignObjectSvg?.(svg);\n return svg;\n}\nfunction createForeignObjectSvg(clone, context) {\n const { width, height } = context;\n const svg = createSvg(width, height, clone.ownerDocument);\n const foreignObject = svg.ownerDocument.createElementNS(svg.namespaceURI, \"foreignObject\");\n foreignObject.setAttributeNS(null, \"x\", \"0%\");\n foreignObject.setAttributeNS(null, \"y\", \"0%\");\n foreignObject.setAttributeNS(null, \"width\", \"100%\");\n foreignObject.setAttributeNS(null, \"height\", \"100%\");\n foreignObject.append(clone);\n svg.appendChild(foreignObject);\n return svg;\n}\n\nasync function domToCanvas(node, options) {\n const context = await orCreateContext(node, options);\n const svg = await domToForeignObjectSvg(context);\n const dataUrl = svgToDataUrl(svg, context.isEnable(\"removeControlCharacter\"));\n if (!context.autoDestruct) {\n context.svgStyleElement = createStyleElement(context.ownerDocument);\n context.svgDefsElement = context.ownerDocument?.createElementNS(XMLNS, \"defs\");\n context.svgStyles.clear();\n }\n const image = createImage(dataUrl, svg.ownerDocument);\n return await imageToCanvas(image, context);\n}\n\nasync function domToBlob(node, options) {\n const context = await orCreateContext(node, options);\n const { log, type, quality, dpi } = context;\n const canvas = await domToCanvas(context);\n log.time(\"canvas to blob\");\n const blob = await canvasToBlob(canvas, type, quality);\n if ([\"image/png\", \"image/jpeg\"].includes(type) && dpi) {\n const arrayBuffer = await blobToArrayBuffer(blob.slice(0, 33));\n let uint8Array = new Uint8Array(arrayBuffer);\n if (type === \"image/png\") {\n uint8Array = changePngDpi(uint8Array, dpi);\n } else if (type === \"image/jpeg\") {\n uint8Array = changeJpegDpi(uint8Array, dpi);\n }\n log.timeEnd(\"canvas to blob\");\n return new Blob([uint8Array, blob.slice(33)], { type });\n }\n log.timeEnd(\"canvas to blob\");\n return blob;\n}\n\nasync function domToDataUrl(node, options) {\n const context = await orCreateContext(node, options);\n const { log, quality, type, dpi } = context;\n const canvas = await domToCanvas(context);\n log.time(\"canvas to data url\");\n let dataUrl = canvas.toDataURL(type, quality);\n if ([\"image/png\", \"image/jpeg\"].includes(type) && dpi && SUPPORT_ATOB && SUPPORT_BTOA) {\n const [format, body] = dataUrl.split(\",\");\n let headerLength = 0;\n let overwritepHYs = false;\n if (type === \"image/png\") {\n const b64Index = detectPhysChunkFromDataUrl(body);\n if (b64Index >= 0) {\n headerLength = Math.ceil((b64Index + 28) / 3) * 4;\n overwritepHYs = true;\n } else {\n headerLength = 33 / 3 * 4;\n }\n } else if (type === \"image/jpeg\") {\n headerLength = 18 / 3 * 4;\n }\n const stringHeader = body.substring(0, headerLength);\n const restOfData = body.substring(headerLength);\n const headerBytes = window.atob(stringHeader);\n const uint8Array = new Uint8Array(headerBytes.length);\n for (let i = 0; i < uint8Array.length; i++) {\n uint8Array[i] = headerBytes.charCodeAt(i);\n }\n const finalArray = type === \"image/png\" ? changePngDpi(uint8Array, dpi, overwritepHYs) : changeJpegDpi(uint8Array, dpi);\n const base64Header = window.btoa(String.fromCharCode(...finalArray));\n dataUrl = [format, \",\", base64Header, restOfData].join(\"\");\n }\n log.timeEnd(\"canvas to data url\");\n return dataUrl;\n}\n\nasync function domToSvg(node, options) {\n const context = await orCreateContext(node, options);\n const { width, height, ownerDocument } = context;\n const dataUrl = await domToDataUrl(context);\n const svg = createSvg(width, height, ownerDocument);\n const svgImage = svg.ownerDocument.createElementNS(svg.namespaceURI, \"image\");\n svgImage.setAttributeNS(null, \"href\", dataUrl);\n svgImage.setAttributeNS(null, \"height\", \"100%\");\n svgImage.setAttributeNS(null, \"width\", \"100%\");\n svg.appendChild(svgImage);\n return svgToDataUrl(svg, context.isEnable(\"removeControlCharacter\"));\n}\n\nasync function domToImage(node, options) {\n const context = await orCreateContext(node, options);\n const { ownerDocument, width, height, scale, type } = context;\n const url = type === \"image/svg+xml\" ? await domToSvg(context) : await domToDataUrl(context);\n const image = createImage(url, ownerDocument);\n image.width = Math.floor(width * scale);\n image.height = Math.floor(height * scale);\n image.style.width = `${width}px`;\n image.style.height = `${height}px`;\n return image;\n}\n\nasync function domToJpeg(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/jpeg\" })\n );\n}\n\nasync function domToPixel(node, options) {\n const context = await orCreateContext(node, options);\n const canvas = await domToCanvas(context);\n return canvas.getContext(\"2d\").getImageData(0, 0, canvas.width, canvas.height).data;\n}\n\nasync function domToPng(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/png\" })\n );\n}\n\nasync function domToWebp(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/webp\" })\n );\n}\n\nexport { createContext, destroyContext, domToBlob, domToCanvas, domToDataUrl, domToForeignObjectSvg, domToImage, domToJpeg, domToPixel, domToPng, domToSvg, domToWebp, loadMedia, waitUntilLoad };\n","import { domToPng } from \"modern-screenshot\";\nimport type { ElementContext, RegionRect } from \"./types.js\";\n\nconst STYLE_KEYS = [\n \"display\", \"position\", \"width\", \"height\", \"margin\", \"padding\",\n \"color\", \"background-color\", \"font-size\", \"font-weight\", \"font-family\",\n \"border\", \"border-radius\", \"box-shadow\", \"flex\", \"grid-template-columns\",\n \"text-align\", \"line-height\", \"opacity\",\n];\n\n/** outerHTML + a curated slice of computed styles — the context handed to Claude. */\nexport function captureElementContext(el: Element): ElementContext {\n const html = el.outerHTML.length > 6000 ? el.outerHTML.slice(0, 6000) + \"…\" : el.outerHTML;\n const cs = getComputedStyle(el);\n const styles: Record<string, string> = {};\n for (const k of STYLE_KEYS) {\n const v = cs.getPropertyValue(k);\n if (v) styles[k] = v.trim();\n }\n return { html, styles };\n}\n\n/** Max time (ms) any single capture may spend fetching/embedding assets. */\nconst CAPTURE_TIMEOUT = 6000;\n\n/** Resolve `undefined` if `p` doesn't settle within `ms` — so a capture can never hang the UI. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T | undefined> {\n return Promise.race([p, new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), ms))]);\n}\n\n/**\n * Give web fonts a brief chance to finish loading so they embed instead of\n * falling back — but NEVER block on it. On some SPAs `document.fonts.ready`\n * settles slowly (or keeps loading), which would otherwise hang the capture,\n * so we race it against a short cap.\n */\nasync function fontsReady(): Promise<void> {\n try {\n const fonts = (document as Document & { fonts?: FontFaceSet }).fonts;\n if (!fonts?.ready) return;\n await Promise.race([\n fonts.ready,\n new Promise<void>((resolve) => setTimeout(resolve, 800)),\n ]);\n } catch {\n /* FontFaceSet unsupported — carry on */\n }\n}\n\n/** Skip Loupe's own UI and redacted elements in any capture. */\nfunction captureFilter(node: Node): boolean {\n if (!(node instanceof Element)) return true;\n if (node.id === \"loupe-root\") return false;\n if (node.hasAttribute(\"data-loupe-redact\")) return false;\n return true;\n}\n\n/**\n * Screenshot the target element. Elements marked [data-loupe-redact] are\n * excluded before anything leaves the browser, and our own UI is never captured.\n */\nexport async function captureScreenshot(el: Element): Promise<string | undefined> {\n try {\n await fontsReady();\n return await withTimeout(\n domToPng(el as HTMLElement, {\n scale: Math.min(window.devicePixelRatio || 1, 2),\n backgroundColor: getComputedStyle(document.body).backgroundColor || \"#ffffff\",\n timeout: CAPTURE_TIMEOUT,\n filter: captureFilter,\n }),\n CAPTURE_TIMEOUT + 2000,\n );\n } catch (err) {\n console.warn(\"[loupe] screenshot capture failed\", err);\n return undefined;\n }\n}\n\n/**\n * Screenshot a free-form rectangle (the \"region shot\"). `rect` is in **viewport**\n * coordinates (what's on screen now). The default renders the whole page and crops;\n * the extension overrides this with a real captureVisibleTab crop. Redacted regions\n * are painted over before the pixels leave the browser.\n */\nexport async function captureRegionScreenshot(rect: RegionRect): Promise<string | undefined> {\n try {\n await fontsReady();\n const scale = Math.min(window.devicePixelRatio || 1, 2);\n // Render the SMALLEST element that fully covers the selection, not the whole\n // page. Rendering document.body is heavy and its cross-origin font embedding\n // often times out (→ fallback fonts, reflow); a scoped subtree behaves like\n // the reliable element capture.\n const container = regionContainer(rect);\n const origin = container.getBoundingClientRect();\n const full = await withTimeout(\n domToPng(container, {\n scale,\n backgroundColor: getComputedStyle(document.body).backgroundColor || \"#ffffff\",\n timeout: CAPTURE_TIMEOUT,\n filter: captureFilter,\n }),\n CAPTURE_TIMEOUT + 2000,\n );\n if (!full) return undefined;\n const redact = Array.from(document.querySelectorAll(\"[data-loupe-redact]\")).map((n) =>\n (n as Element).getBoundingClientRect(),\n );\n return await cropRegion(full, rect, origin.left, origin.top, scale, redact);\n } catch (err) {\n console.warn(\"[loupe] region capture failed\", err);\n return undefined;\n }\n}\n\n/** The smallest on-page element whose box fully covers the selection rectangle. */\nfunction regionContainer(rect: RegionRect): HTMLElement {\n const cx = rect.x + rect.w / 2;\n const cy = rect.y + rect.h / 2;\n let node = document.elementFromPoint(cx, cy) as HTMLElement | null;\n if (node && node.closest(\"#loupe-root\")) node = null; // never our own UI\n const covers = (r: DOMRect) =>\n r.left <= rect.x && r.top <= rect.y && r.right >= rect.x + rect.w && r.bottom >= rect.y + rect.h;\n while (node && node !== document.body && node !== document.documentElement) {\n if (covers(node.getBoundingClientRect())) return node;\n node = node.parentElement;\n }\n return document.body;\n}\n\n/** Options for a screen recording. */\nexport interface RecordOptions {\n /** Auto-stop after this many ms (a safety cap so recordings never run forever). */\n maxMs?: number;\n /** Called once with a `stop()` fn so the caller can wire a Stop button to it. */\n register?: (stop: () => void) => void;\n}\n\n/** Best available webm MIME the browser can record, or \"\" to let MediaRecorder pick. */\nfunction pickRecordingMime(): string {\n const MR: any = (window as any).MediaRecorder;\n if (!MR?.isTypeSupported) return \"\";\n for (const t of [\"video/webm;codecs=vp9\", \"video/webm;codecs=vp8\", \"video/webm\"]) {\n if (MR.isTypeSupported(t)) return t;\n }\n return \"\";\n}\n\nfunction blobToDataUrl(blob: Blob): Promise<string> {\n return new Promise((resolve, reject) => {\n const r = new FileReader();\n r.onload = () => resolve(String(r.result));\n r.onerror = () => reject(r.error);\n r.readAsDataURL(blob);\n });\n}\n\n/** Read a file the reporter picked into a data URL (for upload, or offline storage). */\nexport function fileToDataUrl(file: File): Promise<string> {\n return blobToDataUrl(file);\n}\n\n/** Classify an attachment by MIME type — videos play inline, images render as thumbs. */\nexport function attachmentKind(mime: string | undefined): \"image\" | \"video\" {\n return (mime ?? \"\").startsWith(\"video/\") ? \"video\" : \"image\";\n}\n\n/**\n * Record a screen video cropped to `rect` (viewport coords), mirroring the region\n * screenshot flow. Uses getDisplayMedia (real pixels) — the browser shows a share\n * prompt; picking the current tab keeps the crop aligned. Each frame is drawn to a\n * canvas cropped to the selection, then re-encoded to webm. Returns a data URL, or\n * undefined if the user cancels the prompt or recording isn't supported. The default\n * is overridable via LoupeConfig.captureRecording (e.g. the extension).\n */\nexport async function captureRegionRecording(rect: RegionRect, opts?: RecordOptions): Promise<string | undefined> {\n const md = navigator.mediaDevices as MediaDevices & {\n getDisplayMedia?: (c?: any) => Promise<MediaStream>;\n };\n if (!md?.getDisplayMedia || !(window as any).MediaRecorder) return undefined;\n\n let stream: MediaStream;\n try {\n stream = await md.getDisplayMedia({ video: { frameRate: 30 }, audio: false, preferCurrentTab: true } as any);\n } catch {\n return undefined; // user dismissed the picker\n }\n\n try {\n return await recordCropped(stream, rect, opts);\n } catch (err) {\n console.warn(\"[loupe] screen recording failed\", err);\n return undefined;\n } finally {\n stream.getTracks().forEach((t) => t.stop());\n }\n}\n\nasync function recordCropped(stream: MediaStream, rect: RegionRect, opts?: RecordOptions): Promise<string | undefined> {\n const maxMs = opts?.maxMs ?? 20000;\n const video = document.createElement(\"video\");\n video.srcObject = stream;\n video.muted = true;\n (video as any).playsInline = true;\n await video.play().catch(() => undefined);\n\n const track = stream.getVideoTracks()[0];\n const s = track?.getSettings?.() ?? {};\n const vw = (s.width as number) || video.videoWidth || window.innerWidth;\n const vh = (s.height as number) || video.videoHeight || window.innerHeight;\n // The shared surface (ideally the current tab) maps to the page viewport by scale.\n const sx = vw / window.innerWidth;\n const sy = vh / window.innerHeight;\n const cw = Math.max(2, Math.round(rect.w * sx));\n const ch = Math.max(2, Math.round(rect.h * sy));\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = cw;\n canvas.height = ch;\n const ctx = canvas.getContext(\"2d\")!;\n let raf = 0;\n const draw = () => {\n try { ctx.drawImage(video, rect.x * sx, rect.y * sy, cw, ch, 0, 0, cw, ch); } catch { /* not ready yet */ }\n raf = requestAnimationFrame(draw);\n };\n draw();\n\n const out = (canvas as HTMLCanvasElement & { captureStream(fps?: number): MediaStream }).captureStream(30);\n const mime = pickRecordingMime();\n const rec = new MediaRecorder(out, mime ? { mimeType: mime } : undefined);\n const chunks: BlobPart[] = [];\n rec.ondataavailable = (e) => { if (e.data && e.data.size) chunks.push(e.data); };\n\n const stop = () => { if (rec.state !== \"inactive\") rec.stop(); };\n opts?.register?.(stop);\n // Auto-stop on the cap, or when the user ends the share via the browser UI.\n const timer = window.setTimeout(stop, maxMs);\n track?.addEventListener(\"ended\", stop);\n\n const done = new Promise<void>((resolve) => { rec.onstop = () => resolve(); });\n rec.start();\n await done;\n\n window.clearTimeout(timer);\n cancelAnimationFrame(raf);\n if (!chunks.length) return undefined;\n return blobToDataUrl(new Blob(chunks, { type: mime || \"video/webm\" }));\n}\n\n/** Crop `rect` (viewport coords) out of a full-page data URL whose origin sits at (ox, oy). */\nfunction cropRegion(\n dataUrl: string,\n rect: RegionRect,\n ox: number,\n oy: number,\n scale: number,\n redact: DOMRect[],\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const sw = Math.max(1, Math.round(rect.w * scale));\n const sh = Math.max(1, Math.round(rect.h * scale));\n const canvas = document.createElement(\"canvas\");\n canvas.width = sw;\n canvas.height = sh;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(img, (rect.x - ox) * scale, (rect.y - oy) * scale, sw, sh, 0, 0, sw, sh);\n ctx.fillStyle = \"#0f0f14\";\n for (const r of redact) {\n ctx.fillRect((r.left - rect.x) * scale, (r.top - rect.y) * scale, r.width * scale, r.height * scale);\n }\n resolve(canvas.toDataURL(\"image/png\"));\n };\n img.onerror = reject;\n img.src = dataUrl;\n });\n}\n","/**\n * The activity contract.\n *\n * The panel renders a live feed of what an agent (or the host app) is doing.\n * Nothing here knows *who* produces the events: the bridge, an MCP-driven agent\n * and the host application all push through the same shape, and the SDK emits its\n * own operations into it too, so the view is useful before a bridge exists.\n */\nexport const ACTIVITY_STATUSES = [\"idle\", \"working\", \"error\"];\nexport const ACTIVITY_STATUS_LABELS = {\n idle: \"Idle\",\n working: \"Working\",\n error: \"Error\",\n};\n/** \"2m 14s\" / \"48s\" / \"—\" for a duration in ms. */\nexport function formatDuration(ms) {\n if (!ms || ms < 0)\n return \"—\";\n const s = Math.round(ms / 1000);\n if (s < 60)\n return `${s}s`;\n const m = Math.floor(s / 60);\n const rest = s % 60;\n if (m < 60)\n return rest ? `${m}m ${rest}s` : `${m}m`;\n const h = Math.floor(m / 60);\n return `${h}h ${m % 60}m`;\n}\n/**\n * Derive the summary from a feed. Pure, so the panel and any other consumer agree\n * on what the numbers mean.\n */\nexport function summarizeActivity(events, status = \"idle\", now = Date.now()) {\n const files = new Set();\n const kinds = new Map();\n let errors = 0;\n let first = Infinity;\n for (const e of events) {\n for (const f of e.files ?? [])\n files.add(f);\n kinds.set(e.kind, (kinds.get(e.kind) ?? 0) + 1);\n if (e.level === \"error\")\n errors++;\n const t = Date.parse(e.at);\n if (!Number.isNaN(t))\n first = Math.min(first, t);\n }\n return {\n status,\n events: events.length,\n errors,\n files: files.size,\n durationMs: events.length && first !== Infinity ? Math.max(0, now - first) : 0,\n byKind: [...kinds.entries()]\n .map(([kind, count]) => ({ kind, count }))\n .sort((a, b) => b.count - a.count || a.kind.localeCompare(b.kind)),\n };\n}\n","/**\n * The lifecycle of a thread's change.\n *\n * A thread does not just sit on a board — its fix moves through an agent, a pull\n * request and a preview. This module is the single definition of that progression,\n * so the panel's chips, the dashboard and anything else agree on what \"In PR\" means.\n *\n * The rule the whole flow rests on: **only a human resolves a thread.** An agent\n * moves work to In Review; a person approves it from there.\n */\nexport const LIFECYCLE_LABELS = {\n sent: \"Sent to agent\",\n in_pr: \"In PR\",\n preview: \"Review preview\",\n reviewed: \"Reviewed\",\n};\n/**\n * Derive the chip for a thread, or `null` when there is nothing to say — an\n * untouched thread in Queue should not wear a badge explaining that.\n *\n * Precedence is deliberate: a merged PR outranks the board stage, because \"Reviewed\"\n * on a resolved thread and \"In PR\" on an open one are both more specific than the\n * column it sits in.\n */\nexport function lifecycle(c) {\n const hasProposal = !!c.proposal;\n const pr = c.pr ?? undefined;\n const withPr = (stage) => {\n const out = { stage, label: LIFECYCLE_LABELS[stage] };\n if (pr) {\n out.pr = pr;\n if (typeof pr.checksTotal === \"number\" && pr.checksTotal > 0) {\n const passed = Math.max(0, Math.min(pr.checksTotal, pr.checksPassed ?? 0));\n out.checks = {\n text: `${passed}/${pr.checksTotal}`,\n ratio: passed / pr.checksTotal,\n };\n }\n }\n return out;\n };\n if (c.status === \"resolved\")\n return hasProposal || pr ? withPr(\"reviewed\") : null;\n if (pr)\n return withPr(\"in_pr\");\n if (c.status === \"in_review\")\n return { stage: \"preview\", label: LIFECYCLE_LABELS.preview };\n if (hasProposal)\n return { stage: \"sent\", label: LIFECYCLE_LABELS.sent };\n return null;\n}\n/** Threads a reviewer still has to look at. */\nexport function awaitingReview(comments) {\n return comments.filter((c) => c.status === \"in_review\");\n}\n","/**\n * Iteration history for a generated change.\n *\n * Generating a change is not a one-shot: you generate, look at it, ask for a\n * refinement, look again. This is the pure model of that stack, so the panel's\n * preview pane and anything else agree on what \"the current iteration\" is — and so\n * the undo/prev/next rules can be tested without a DOM.\n */\nexport function emptyIterations() {\n return { items: [], index: -1 };\n}\n/** The iteration currently being previewed, or null when there is none. */\nexport function current(state) {\n return state.index >= 0 ? state.items[state.index] ?? null : null;\n}\n/**\n * Push a new iteration and preview it.\n *\n * A new iteration is appended **after** the current one rather than always at the\n * end, so generating from a point in the history branches there instead of silently\n * discarding what came later. The tail beyond the current index is dropped, because\n * a preview must always describe a real lineage.\n */\nexport function addIteration(state, iteration) {\n const head = state.items.slice(0, state.index + 1);\n const items = [...head, iteration].slice(-MAX_ITERATIONS);\n return { items, index: items.length - 1 };\n}\n/** Cap the stack — this is a working history, not an archive. */\nexport const MAX_ITERATIONS = 20;\nexport function canUndo(state) {\n return state.items.length > 0;\n}\n/**\n * Discard the newest iteration and preview the one before it. Distinct from\n * stepping back: undo throws the work away, `move(-1)` keeps it for the redo.\n */\nexport function undo(state) {\n if (!state.items.length)\n return state;\n const items = state.items.slice(0, -1);\n return { items, index: items.length - 1 };\n}\nexport function canMove(state, delta) {\n const next = state.index + delta;\n return next >= 0 && next < state.items.length;\n}\n/** Step through the history without discarding anything. */\nexport function move(state, delta) {\n return canMove(state, delta) ? { ...state, index: state.index + delta } : state;\n}\n/** \"2 / 3\" for the navigation counter, or \"\" when there is nothing to navigate. */\nexport function stackLabel(state) {\n return state.items.length ? `${state.index + 1} / ${state.items.length}` : \"\";\n}\n","/**\n * Letting an agent move the browser.\n *\n * An agent that can navigate is genuinely useful — \"the fix is on the preview URL,\n * let me show you\" — and genuinely dangerous if it happens silently. So navigation\n * is a **request** that a human answers, and the only way to get a URL out of this\n * module is to have granted one.\n *\n * The state machine is pure and lives here (not in the panel) because the safety\n * property is the point: `decide()` returns a URL only on an explicit grant, and\n * that is what the tests pin down.\n */\nexport function emptyConsent() {\n return { state: \"idle\", request: null, history: [] };\n}\n/** Only absolute http(s) may be requested — `javascript:` and friends never are. */\nexport function isNavigableUrl(raw) {\n try {\n const u = new URL(raw);\n return u.protocol === \"http:\" || u.protocol === \"https:\";\n }\n catch {\n return false;\n }\n}\n/**\n * Queue a navigation request for the user to answer. A second request replaces the\n * first: two prompts at once would be a good way to get a careless yes.\n */\nexport function requestNavigation(record, request) {\n if (!isNavigableUrl(request.url))\n return record;\n return {\n state: \"requested\",\n request: {\n id: request.id ?? `nav${Date.now().toString(36)}`,\n at: request.at ?? new Date().toISOString(),\n url: request.url,\n reason: request.reason,\n requester: request.requester,\n },\n history: record.history,\n };\n}\nexport function isPending(record) {\n return record.state === \"requested\" && record.request !== null;\n}\n/**\n * Answer the pending request.\n *\n * Returns the record plus the URL to navigate to — `null` unless the user actually\n * granted it. Callers must use this return value rather than reading the request\n * themselves, which is the whole point: there is no path to a URL that skips the\n * decision.\n */\nexport function decide(record, granted, now = new Date().toISOString()) {\n if (!isPending(record))\n return { record, navigateTo: null };\n const url = record.request.url;\n return {\n record: {\n state: granted ? \"granted\" : \"denied\",\n request: null,\n history: [...record.history, { url, decision: granted ? \"granted\" : \"denied\", at: now }],\n },\n navigateTo: granted ? url : null,\n };\n}\n/** Drop a pending request without deciding (a timeout, the panel closing). */\nexport function withdraw(record) {\n return isPending(record) ? { ...record, state: \"idle\", request: null } : record;\n}\n","/**\n * Thread messages.\n *\n * A comment used to be one body. That is not a conversation: an agent has to be able\n * to reply, a reviewer to answer, and each message to carry its own attachments. This\n * is the model everything downstream (mentions, activity, notification) depends on.\n *\n * The legacy single `body` stays exactly as it was and is *also* message #1 — see\n * `firstMessageFromComment`. Nothing had to be migrated to make replies work.\n */\n/**\n * The comment's own body, presented as the first message of its thread.\n *\n * Synthesised rather than stored, so there is no backfill to run and no window where\n * a thread renders with no messages. The id is derived from the comment so it is\n * stable across calls — a UI list keyed on it does not flicker.\n */\nexport function firstMessageFromComment(comment) {\n return {\n id: `${comment.id}:0`,\n threadId: comment.id,\n author: { ...comment.author, type: \"user\" },\n body: comment.body,\n attachments: comment.attachments?.length ? comment.attachments : undefined,\n createdAt: comment.createdAt,\n };\n}\n/** The first message plus every reply, oldest first. */\nexport function threadConversation(comment, replies, opts = {}) {\n // A retracted message is not part of the conversation as anyone reads it. The\n // record survives in the store for whoever needs it.\n const visible = opts.includeDeleted ? replies : replies.filter((m) => !m.deletedAt);\n return [firstMessageFromComment(comment), ...visible].sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n}\n/** Replies a reader should see — never the retracted ones. */\nexport function visibleMessages(messages) {\n return messages.filter((m) => !m.deletedAt);\n}\n/** Who has taken part, in the order they first spoke. */\nexport function participantsOf(messages) {\n const seen = new Map();\n for (const m of messages)\n if (!seen.has(m.author.id))\n seen.set(m.author.id, m.author);\n return [...seen.values()];\n}\n/** Whether a message came from an agent rather than a person. */\nexport function isAgentMessage(m) {\n return m.author.type === \"agent\";\n}\n/** \"Iteration 2\" — or nothing at all for an original thread. */\nexport function iterationLabel(link) {\n if (!link.parentThreadId || link.iterationType !== \"revision\")\n return null;\n return `Iteration ${link.iterationNumber ?? 2}`;\n}\n/** The event a new reply publishes, so an open thread can refresh itself. */\nexport const THREAD_MESSAGE_ADDED = \"message_added\";\n/** …and a retraction, so the other side stops showing it. */\nexport const THREAD_MESSAGE_DELETED = \"message_deleted\";\n","/**\n * The thread timeline.\n *\n * \"Agent activity on your feedback\" — what actually happened, in order. Built from\n * what the thread already carries (its stage, its PR, its proposal, its replies)\n * rather than from a separate event log, so it cannot drift from the truth: if the\n * timeline says a PR was opened, there is a `pr` on the comment saying so.\n *\n * Pure, so the panel and the dashboard render the same story.\n */\n/** \"a <button> “Complete checkout”\" — how the captured thing reads in a timeline. */\nexport function describeTarget(input) {\n const parts = [];\n if (input.anchor?.tag)\n parts.push(`a <${input.anchor.tag}>`);\n if (input.anchor?.selector)\n parts.push(`\\`${input.anchor.selector}\\``);\n return parts.length ? parts.join(\" \") : input.kind === \"free\" ? \"a page note\" : \"an element\";\n}\n/**\n * The story of a thread, oldest first.\n *\n * Stages are read from the thread's *current* state, so a step that was skipped does\n * not appear — there is no \"preview live\" row for a thread that never had one. The\n * timestamps for those steps are not stored, so they borrow the newest message's time;\n * that is a real limitation and the reason the entries are ordered by stage rather\n * than pretending to a precision we do not have.\n */\nexport function threadTimeline(input, messages = []) {\n const out = [];\n const latest = messages.length ? messages[messages.length - 1].at : input.createdAt;\n out.push({\n at: input.createdAt,\n kind: \"captured\",\n label: \"Feedback captured\",\n detail: [input.title, describeTarget(input)].filter(Boolean).join(\" · \"),\n });\n for (const m of messages) {\n out.push({\n at: m.at,\n kind: \"message\",\n label: `${m.authorName} replied`,\n actor: m.fromAgent ? m.authorName : undefined,\n });\n }\n const stage = normalizeStage(input.status);\n const reached = (s) => STAGE_ORDER.indexOf(stage) >= STAGE_ORDER.indexOf(s);\n if (input.proposal || reached(\"in_review\")) {\n const agent = input.proposal?.author ?? \"Claude Code\";\n out.push({\n at: input.proposal?.createdAt ?? latest,\n kind: \"sent\",\n label: `Change ready from ${agent}`,\n detail: \"The rewritten markup is on the thread.\",\n actor: agent,\n });\n }\n if (input.pr) {\n out.push({\n at: latest,\n kind: \"pr\",\n label: input.pr.number ? `Pull request #${input.pr.number} opened` : \"Pull request opened\",\n detail: input.pr.state === \"merged\" ? \"Merged.\" : input.pr.state === \"closed\" ? \"Closed without merging.\" : \"Waiting on review.\",\n });\n // Only when a URL is actually known — a preview is never inferred.\n if (input.pr.previewUrl) {\n out.push({ at: latest, kind: \"preview\", label: \"Preview live\", detail: input.pr.previewUrl });\n }\n }\n if (reached(\"in_review\")) {\n out.push({ at: latest, kind: \"review\", label: \"Waiting on a human review\", detail: \"Only a person can close this.\" });\n }\n if (stage === \"resolved\") {\n out.push({ at: latest, kind: \"resolved\", label: \"Resolved\", detail: \"A person closed this.\" });\n }\n return out;\n}\nconst STAGE_ORDER = [\"queue\", \"todo\", \"in_progress\", \"in_review\", \"resolved\"];\n/** Legacy names map onto the same stages, so an old row still renders a timeline. */\nfunction normalizeStage(status) {\n if (status === \"open\")\n return \"queue\";\n if (status === \"done\")\n return \"resolved\";\n return status;\n}\n/**\n * A thread as plain text, for pasting into a chat or a ticket.\n *\n * Deliberately starts with the element selector: pasted somewhere without Loupe, the\n * selector is the only part that still identifies *what* is being talked about.\n */\nexport function threadAsText(input, messages = []) {\n const lines = [\n `# ${input.title ?? \"Feedback\"} (#${input.id})`,\n \"\",\n `- Stage: ${normalizeStage(input.status)}`,\n `- Page: ${input.url ?? \"—\"}`,\n ];\n if (input.anchor?.selector)\n lines.push(`- Target: \\`${input.anchor.selector}\\``);\n if (input.pr?.number)\n lines.push(`- PR: #${input.pr.number}${input.pr.previewUrl ? ` · preview ${input.pr.previewUrl}` : \"\"}`);\n lines.push(\"\", \"## Request\", \"\", input.body);\n if (messages.length) {\n lines.push(\"\", \"## Conversation\", \"\");\n for (const m of messages)\n lines.push(`**${m.authorName}**${m.fromAgent ? \" (agent)\" : \"\"} — ${m.at}`, \"\", m.body, \"\");\n }\n return lines.join(\"\\n\");\n}\n","/**\n * @mentions.\n *\n * The failure mode that matters here is a *silent* one: a mention that looks like it\n * notified someone and did not. So parsing is conservative and the caller is told\n * which handles it could not resolve, rather than dropping them quietly.\n */\n/** A handle: letters, digits, and the punctuation people actually use in names. */\nconst HANDLE = /^[A-Za-z0-9][A-Za-z0-9._-]*/;\n/**\n * Ranges in the body that must not be searched: fenced blocks, inline code, and\n * `mailto:`-style text. A name inside a code sample is documentation, not a mention.\n */\nfunction excludedRanges(body) {\n const ranges = [];\n // Fenced blocks first, so an inline-code match inside one is not double counted.\n for (const m of body.matchAll(/```[\\s\\S]*?```/g))\n ranges.push([m.index, m.index + m[0].length]);\n const fenced = (i) => ranges.some(([a, b]) => i >= a && i < b);\n for (const m of body.matchAll(/`[^`\\n]*`/g)) {\n if (!fenced(m.index))\n ranges.push([m.index, m.index + m[0].length]);\n }\n return ranges;\n}\n/**\n * Every mention in a body.\n *\n * Deliberately *not* matched: an email address (`sara@acme.test`) — the `@` is\n * preceded by a word character, which no mention ever is. Trailing punctuation is\n * not part of the handle, so `@sara,` mentions `sara`.\n */\nexport function parseMentions(body) {\n if (!body)\n return [];\n const excluded = excludedRanges(body);\n const inExcluded = (i) => excluded.some(([a, b]) => i >= a && i < b);\n const out = [];\n const seen = new Set();\n for (let i = 0; i < body.length; i++) {\n if (body[i] !== \"@\")\n continue;\n if (inExcluded(i))\n continue;\n // A mention starts at the beginning of the body or after whitespace/opening\n // punctuation — never in the middle of a word, which is what rules out emails.\n const prev = i > 0 ? body[i - 1] : \"\";\n if (prev && !/[\\s([{<\"'*_~]/.test(prev))\n continue;\n const match = HANDLE.exec(body.slice(i + 1));\n if (!match)\n continue;\n const raw = match[0];\n // `@sara.` and `@sara,` end the handle at the punctuation; a dot *inside* a handle\n // (`@jane.doe`) is kept.\n const handle = raw.replace(/[._-]+$/, \"\");\n if (!handle)\n continue;\n const key = handle.toLowerCase();\n // The same person mentioned twice is one mention, but the first position wins so\n // highlighting stays stable.\n if (seen.has(key))\n continue;\n seen.add(key);\n out.push({ handle, start: i, length: handle.length + 1 });\n }\n return out;\n}\n/** Handles compare case-insensitively; a display name's first word also works. */\nexport function resolveMentions(body, candidates) {\n const byKey = new Map();\n for (const c of candidates) {\n byKey.set(c.name.toLowerCase(), c);\n byKey.set(c.name.toLowerCase().replace(/\\s+/g, \"\"), c);\n const first = c.name.split(/\\s+/)[0];\n if (first)\n byKey.set(first.toLowerCase(), c);\n if (c.email)\n byKey.set(c.email.split(\"@\")[0].toLowerCase(), c);\n byKey.set(c.id.toLowerCase(), c);\n }\n const resolved = [];\n const unknown = [];\n for (const mention of parseMentions(body)) {\n const user = byKey.get(mention.handle.toLowerCase());\n if (user && !resolved.some((r) => r.user.id === user.id))\n resolved.push({ mention, user });\n else if (!user)\n unknown.push(mention.handle);\n }\n return { resolved, unknown };\n}\n/**\n * Split a body into text and mention segments, so a renderer can highlight names\n * without re-parsing (and without highlighting the wrong occurrence).\n */\nexport function mentionSegments(body, mentions) {\n if (!mentions.length)\n return [{ text: body, mention: false }];\n const sorted = [...mentions].sort((a, b) => a.start - b.start);\n const out = [];\n let at = 0;\n for (const m of sorted) {\n if (m.start > at)\n out.push({ text: body.slice(at, m.start), mention: false });\n out.push({ text: body.slice(m.start, m.start + m.length), mention: true });\n at = m.start + m.length;\n }\n if (at < body.length)\n out.push({ text: body.slice(at), mention: false });\n return out;\n}\n/** The handles someone could type, for an autocomplete list. */\nexport function mentionSuggestions(body, caret, candidates) {\n // The handle being typed: from the last `@` before the caret to the caret.\n const before = body.slice(0, caret);\n const at = before.lastIndexOf(\"@\");\n if (at < 0)\n return [];\n const typed = before.slice(at + 1);\n // Bail once they have typed a space — the mention is finished, or was never one.\n if (/\\s/.test(typed))\n return [];\n const q = typed.toLowerCase();\n return candidates\n .filter((c) => !q || c.name.toLowerCase().includes(q) || c.id.toLowerCase().includes(q))\n .slice(0, 6);\n}\n","/**\n * \"Needs you\".\n *\n * A board that shows everything is a board nobody reads. This is the one predicate\n * that answers *what is blocked on a person right now* — and it lives in shared so\n * the panel, the dashboard and the MCP tools cannot disagree about it.\n *\n * The exclusion matters as much as the match: a thread where an **agent is still\n * working** is not waiting on a human, and counting it would train people to ignore\n * the filter.\n */\nexport const NEEDS_YOU_LABELS = {\n review: \"Waiting on your review\",\n question: \"The agent asked you something\",\n failed: \"The agent's run failed\",\n};\n/** Does this look like the agent asking for an answer rather than reporting one? */\nexport function looksLikeQuestion(body) {\n const lines = body.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n const last = lines[lines.length - 1];\n if (!last)\n return false;\n // A question mark at the end of the last line, ignoring a trailing quote or bracket.\n return /\\?[\"')\\]]*$/.test(last);\n}\n/**\n * Whether a human needs to do something.\n *\n * Precedence is deliberate: a failed run outranks an unanswered question (fix the\n * breakage first), and both outrank a routine review, because a review is the normal\n * state of work moving and a failure is not.\n */\nexport function needsYou(input) {\n const stage = normalizeStage(input.status);\n // Resolved threads need nobody, whatever else is true of them.\n if (stage === \"resolved\")\n return { needs: false };\n if (input.agentFailed)\n return { needs: true, reason: \"failed\", label: NEEDS_YOU_LABELS.failed };\n // An agent's question is addressed to a person; a *person's* question is addressed to\n // the agent, so it must not land here.\n if (input.last?.fromAgent && looksLikeQuestion(input.last.body)) {\n return { needs: true, reason: \"question\", label: NEEDS_YOU_LABELS.question };\n }\n if (stage === \"in_review\")\n return { needs: true, reason: \"review\", label: NEEDS_YOU_LABELS.review };\n return { needs: false };\n}\n/** Threads a human has to act on, in board order. */\nexport function needsYouThreads(threads) {\n return threads.filter((t) => needsYou(t).needs);\n}\nfunction normalizeStage(status) {\n if (status === \"open\")\n return \"queue\";\n if (status === \"done\")\n return \"resolved\";\n return status;\n}\n","/**\n * Reactions.\n *\n * A reaction is a toggle, not an increment: pressing the same emoji twice must leave\n * you having reacted once. That is the whole correctness question, and it is why the\n * toggle lives here as a pure function rather than being inferred from counts at the\n * call site.\n */\n/** The emoji offered in the picker. Deliberately short — a long list is a decision nobody makes. */\nexport const REACTION_CHOICES = [\"👍\", \"🎉\", \"👀\", \"🙏\", \"❤️\", \"🚀\"];\n/**\n * Aggregate one message's reactions for a viewer.\n *\n * Ordered by count (most reacted first), then by the picker's own order so the row\n * does not reshuffle between renders when counts tie.\n */\nexport function summarizeReactions(reactions, viewerId) {\n const byEmoji = new Map();\n for (const r of reactions) {\n const list = byEmoji.get(r.emoji) ?? [];\n list.push(r);\n byEmoji.set(r.emoji, list);\n }\n const rank = (emoji) => {\n const at = REACTION_CHOICES.indexOf(emoji);\n return at < 0 ? REACTION_CHOICES.length : at;\n };\n return [...byEmoji.entries()]\n .map(([emoji, list]) => ({\n emoji,\n count: list.length,\n mine: viewerId ? list.some((r) => r.userId === viewerId) : false,\n users: list.map((r) => r.userName ?? r.userId),\n }))\n .sort((a, b) => b.count - a.count || rank(a.emoji) - rank(b.emoji) || a.emoji.localeCompare(b.emoji));\n}\n/**\n * Toggle one person's reaction, returning the new set.\n *\n * Idempotent in both directions: toggling on twice adds one, toggling off twice removes\n * one and then does nothing. Applying the same toggle to an already-toggled set is\n * therefore safe to retry, which matters because a flaky network will.\n */\nexport function toggleReaction(reactions, next) {\n const has = reactions.some((r) => r.messageId === next.messageId && r.emoji === next.emoji && r.userId === next.userId);\n if (has) {\n return reactions.filter((r) => !(r.messageId === next.messageId && r.emoji === next.emoji && r.userId === next.userId));\n }\n return [...reactions, next];\n}\n/** Reactions grouped per message, for rendering a whole conversation at once. */\nexport function reactionsByMessage(reactions, viewerId) {\n const byMessage = new Map();\n for (const r of reactions) {\n const list = byMessage.get(r.messageId) ?? [];\n list.push(r);\n byMessage.set(r.messageId, list);\n }\n const out = new Map();\n for (const [messageId, list] of byMessage)\n out.set(messageId, summarizeReactions(list, viewerId));\n return out;\n}\n","/**\n * Presence.\n *\n * Who else has this page open. The only interesting part is expiry: a browser that is\n * closed or crashes sends no goodbye, so liveness is a heartbeat and silence past the\n * TTL means gone. Without that, the peer list slowly fills with ghosts and stops being\n * believed.\n *\n * Pure — the bridge and the panel both use it, and neither gets its own rules.\n */\n/** Silence after which a peer is presumed gone. Shorter than an agent's — a browser closes fast. */\nexport const PEER_TTL_MS = 20000;\n/** How often a client should heartbeat. Comfortably inside the TTL. */\nexport const PEER_HEARTBEAT_MS = 6000;\n/** Stable across reloads and tabs of the same page, so a refresh does not duplicate you. */\nexport function peerId(url, userId) {\n let h = 0x811c9dc5;\n const input = `${url}\\u0000${userId}`;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return `p_${h.toString(16).padStart(8, \"0\")}`;\n}\nexport function joinPresence(peers, input, now = Date.now()) {\n const id = peerId(input.url, input.userId);\n const without = peers.filter((p) => p.id !== id);\n return [...without, { id, ...input, lastSeen: now }];\n}\n/** Refresh one peer. An unknown id is ignored — the next join revives it. */\nexport function heartbeatPresence(peers, id, now = Date.now()) {\n if (!peers.some((p) => p.id === id))\n return peers;\n return peers.map((p) => (p.id === id ? { ...p, lastSeen: now } : p));\n}\nexport function leavePresence(peers, id) {\n return peers.filter((p) => p.id !== id);\n}\n/** Drop anything silent for the TTL. Inclusive at the boundary. */\nexport function sweepPresence(peers, now = Date.now(), ttlMs = PEER_TTL_MS) {\n return peers.filter((p) => now - p.lastSeen < ttlMs);\n}\n/** Peers on one page, excluding the viewer — \"who else is here\". */\nexport function peersOnPage(peers, url, viewerId) {\n return peers.filter((p) => p.url === url && p.id !== viewerId);\n}\n/**\n * Cursor updates arrive faster than anyone can usefully render them, so a client\n * throttles. Returns the delay to wait before sending the next one — 0 when it can go\n * immediately, so the first move is never delayed.\n */\nexport function throttleDelay(lastSentAt, now = Date.now(), minMs = 80) {\n if (!lastSentAt)\n return 0;\n const elapsed = now - lastSentAt;\n return elapsed >= minMs ? 0 : minMs - elapsed;\n}\n/** Initials for a tiny avatar: two words → two letters, one word → one. */\nexport function initialsOf(name) {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (!words.length)\n return \"?\";\n if (words.length === 1)\n return words[0].slice(0, 1).toUpperCase();\n return (words[0].slice(0, 1) + words[words.length - 1].slice(0, 1)).toUpperCase();\n}\n","/**\n * The companion gather tray.\n *\n * The point of the tray is that a visual brief is usually about *several* things at\n * once — \"these three cards, not the header\" — and one-click-at-a-time forces the\n * person to write what they could have shown. So the tray holds a list, and ordering is\n * part of the message: it is how you say which one matters most.\n *\n * Pure, so the reorder and include rules can be tested without a DOM.\n */\nexport function emptyTray() {\n return { items: [] };\n}\n/**\n * Add an item, or replace the one already there.\n *\n * Replaced rather than appended when it is the same reference: clicking \"add\" twice on\n * the same element is a person confirming, not a person wanting it twice. The position\n * is kept so a reorder is not undone by a re-add.\n */\nexport function addToTray(state, item) {\n const full = { include: true, ...item };\n const at = state.items.findIndex((i) => i.id === full.id);\n if (at < 0)\n return { items: [...state.items, full] };\n const items = [...state.items];\n items[at] = { ...items[at], ...full, include: items[at].include };\n return { items };\n}\nexport function removeFromTray(state, id) {\n return { items: state.items.filter((i) => i.id !== id) };\n}\nexport function toggleInclude(state, id) {\n return { items: state.items.map((i) => (i.id === id ? { ...i, include: !i.include } : i)) };\n}\n/** Move one item to an absolute position, clamped rather than rejected. */\nexport function moveInTray(state, id, to) {\n const from = state.items.findIndex((i) => i.id === id);\n if (from < 0)\n return state;\n const target = Math.max(0, Math.min(state.items.length - 1, to));\n if (target === from)\n return state;\n const items = [...state.items];\n const [moved] = items.splice(from, 1);\n items.splice(target, 0, moved);\n return { items };\n}\n/** Nudge one position up or down — what an arrow button does. */\nexport function nudgeInTray(state, id, delta) {\n const at = state.items.findIndex((i) => i.id === id);\n if (at < 0)\n return state;\n return moveInTray(state, id, at + delta);\n}\n/** Only what is checked. Order is preserved, because order is meaning. */\nexport function includedItems(state) {\n return state.items.filter((i) => i.include);\n}\nexport function trayCount(state) {\n return { total: state.items.length, included: includedItems(state).length };\n}\nexport function clearTray() {\n return { items: [] };\n}\n/**\n * The payload the bridge expects.\n *\n * A flat array of contexts rather than separate element/screenshot lists: the tray is\n * ordered and the agent should read it in that order, and splitting it by kind is how\n * that ordering gets lost at the boundary.\n */\nexport function trayPayload(state) {\n return includedItems(state).map((i) => ({\n kind: i.kind,\n id: i.ref ?? i.id,\n url: i.url,\n label: i.label,\n }));\n}\n/** A one-line description of the tray, for a button label. */\nexport function traySummary(state) {\n const { total, included } = trayCount(state);\n if (!total)\n return \"No context gathered\";\n if (included === total)\n return `${total} context${total === 1 ? \"\" : \"s\"}`;\n return `${included} of ${total} included`;\n}\n/**\n * Whether dictation is available.\n *\n * Two different reasons to hide the control, and they need different wording: an\n * unsupported browser is a fact, while a secure-origin failure is fixable by loading\n * the page differently. Telling someone their browser cannot do it when the real\n * problem is `http://` sends them looking in the wrong place.\n */\nexport function voiceSupport(env) {\n if (!env.isSecureContext)\n return \"insecure\";\n return env.hasCtor ? \"supported\" : \"unsupported\";\n}\nexport function voiceMessage(support) {\n if (support === \"supported\")\n return null;\n if (support === \"insecure\")\n return \"Dictation needs a secure page (https, or localhost).\";\n return \"This browser cannot dictate — the Web Speech API is not available.\";\n}\n/** mm:ss for the recording pill, so a long recording still reads. */\nexport function elapsedLabel(ms) {\n const total = Math.max(0, Math.floor(ms / 1000));\n const mm = Math.floor(total / 60);\n const ss = total % 60;\n return `${mm}:${String(ss).padStart(2, \"0\")}`;\n}\n","// Canonical types + pure helpers shared across the SDK, server, dashboard, and MCP.\nexport * from \"./activity.js\";\nexport * from \"./lifecycle.js\";\nexport * from \"./iteration.js\";\nexport * from \"./consent.js\";\nexport * from \"./preview.js\";\nexport * from \"./thread.js\";\nexport * from \"./timeline.js\";\nexport * from \"./mentions.js\";\nexport * from \"./needs-you.js\";\nexport * from \"./reactions.js\";\nexport * from \"./presence.js\";\nexport * from \"./companion-tray.js\";\n/** Board order, left to right. */\nexport const COMMENT_STAGES = [\"queue\", \"todo\", \"in_progress\", \"in_review\", \"resolved\"];\n/** Human labels for the board columns. */\nexport const STAGE_LABELS = {\n queue: \"Queue\",\n todo: \"To Do\",\n in_progress: \"In Progress\",\n in_review: \"In Review\",\n resolved: \"Resolved\",\n};\n/**\n * Statuses this project shipped before the five-stage board. Still accepted on\n * input (and on rows written by an older client) so a rolling upgrade never\n * writes a value the board cannot place.\n */\nconst LEGACY_STATUS = {\n open: \"queue\",\n in_progress: \"in_progress\",\n done: \"resolved\",\n};\n/**\n * Coerce any accepted status — current stage or legacy alias — into a stage.\n * Anything unrecognised lands in `queue`, the untriaged inbox, rather than\n * falling off the board entirely.\n */\nexport function normalizeStatus(value) {\n if (typeof value === \"string\") {\n if (COMMENT_STAGES.includes(value))\n return value;\n if (value in LEGACY_STATUS)\n return LEGACY_STATUS[value];\n }\n return \"queue\";\n}\n/** Whether a comment is still open work (everything except `resolved`). */\nexport function isOpenStage(stage) {\n return stage !== \"resolved\";\n}\n/**\n * Every raw `status` value that belongs to this stage — the stage itself plus any\n * legacy alias that maps onto it. A SQL filter uses this so it still finds rows\n * written before the five-stage board.\n */\nexport function statusAliases(stage) {\n const out = [stage];\n for (const [legacy, mapped] of Object.entries(LEGACY_STATUS)) {\n if (mapped === stage && !out.includes(legacy))\n out.push(legacy);\n }\n return out;\n}\n/** Priorities, most urgent first. */\nexport const COMMENT_PRIORITIES = [\"critical\", \"high\", \"medium\", \"low\"];\n/** Human labels for the priority chips. */\nexport const PRIORITY_LABELS = {\n critical: \"Critical\",\n high: \"High\",\n medium: \"Medium\",\n low: \"Low\",\n};\n/** Sort key: 0 is the most urgent, so `a - b` sorts correctly. */\nexport const PRIORITY_RANK = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n/** Change types. */\nexport const CHANGE_TYPES = [\"frontend\", \"backend\", \"api\", \"other\"];\n/** Human labels for the change-type chips. */\nexport const CHANGE_TYPE_LABELS = {\n frontend: \"Frontend\",\n backend: \"Backend\",\n api: \"API\",\n other: \"Other\",\n};\n/** Defaults applied when a comment does not say. */\nexport const DEFAULT_PRIORITY = \"medium\";\nexport const DEFAULT_CHANGE_TYPE = \"other\";\n/** Coerce any value into a priority, falling back to the default. */\nexport function normalizePriority(value) {\n if (typeof value === \"string\" && COMMENT_PRIORITIES.includes(value)) {\n return value;\n }\n return DEFAULT_PRIORITY;\n}\n/** Coerce any value into a change type, falling back to the default. */\nexport function normalizeChangeType(value) {\n if (typeof value === \"string\" && CHANGE_TYPES.includes(value)) {\n return value;\n }\n return DEFAULT_CHANGE_TYPE;\n}\n/** Classify a viewport width into a device bucket (mobile < 768 ≤ tablet < 1024 ≤ desktop). */\nexport function deviceType(width) {\n if (width < 768)\n return \"mobile\";\n if (width < 1024)\n return \"tablet\";\n return \"desktop\";\n}\nconst DROP_EXACT = new Set([\n \"api\", \"key\", \"fbclid\", \"gclid\", \"gbraid\", \"wbraid\", \"msclkid\",\n \"ref\", \"ref_src\", \"mc_cid\", \"mc_eid\", \"_hsenc\", \"_hsmi\", \"igshid\",\n]);\n/**\n * Normalize a page URL so comments don't fragment across tracking/volatile params.\n * Keeps the path + a filtered, sorted query. Drops utm_*, click ids, and Loupe's\n * own dev params (api/key). Accepts a full URL or a path+search string.\n */\nexport function normalizeUrl(input) {\n try {\n const u = new URL(input, \"http://loupe.local\");\n let path = u.pathname;\n const kept = [];\n for (const [k, v] of u.searchParams) {\n const key = k.toLowerCase();\n if (DROP_EXACT.has(key) || key.startsWith(\"utm_\"))\n continue;\n kept.push([k, v]);\n }\n kept.sort((a, b) => (a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0])));\n const qs = new URLSearchParams(kept).toString();\n if (path.length > 1 && path.endsWith(\"/\"))\n path = path.slice(0, -1);\n return path + (qs ? `?${qs}` : \"\");\n }\n catch {\n const i = input.indexOf(\"?\");\n return i >= 0 ? input.slice(0, i) : input;\n }\n}\n","import type { ActivityEvent, Attachment, Comment, MessageAttachment, OrgInfo, Reaction, StorageAdapter, ThreadAuthor, ThreadMessage } from \"./types.js\";\nimport { toggleReaction } from \"./types.js\";\nimport { attachmentKind, fileToDataUrl } from \"./capture.js\";\n\n/**\n * Prototype storage: everything lives in localStorage, keyed by project + path.\n * The production adapter swaps this for HTTP calls to the backend — the SDK\n * only depends on the StorageAdapter interface, so nothing else changes.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private key(projectKey: string, url: string) {\n return `loupe:${projectKey}:${url}`;\n }\n\n private readAll(projectKey: string, url: string): Comment[] {\n try {\n const raw = localStorage.getItem(this.key(projectKey, url));\n return raw ? (JSON.parse(raw) as Comment[]) : [];\n } catch {\n return [];\n }\n }\n\n private writeAll(projectKey: string, url: string, comments: Comment[]) {\n localStorage.setItem(this.key(projectKey, url), JSON.stringify(comments));\n }\n\n async list(projectKey: string, url: string): Promise<Comment[]> {\n return this.readAll(projectKey, url);\n }\n\n /** Every page's comments for this project, newest first — the \"All\" scope. */\n async listAll(projectKey: string): Promise<Comment[]> {\n const prefix = `loupe:${projectKey}:`;\n const out: Comment[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (!k || !k.startsWith(prefix)) continue;\n try {\n out.push(...(JSON.parse(localStorage.getItem(k) || \"[]\") as Comment[]));\n } catch { /* skip an unreadable key */ }\n }\n return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n }\n\n async save(comment: Comment): Promise<Comment> {\n const all = this.readAll(comment.projectKey, comment.url);\n all.push(comment);\n this.writeAll(comment.projectKey, comment.url, all);\n return comment;\n }\n\n /**\n * Offline mode: keep the file inline. localStorage is only a few MB, so refuse\n * anything that would blow the quota rather than silently dropping it.\n */\n async upload(_projectKey: string, file: File): Promise<Attachment> {\n if (file.size > 3_000_000) throw new Error(\"attachment too large for offline mode\");\n return {\n url: await fileToDataUrl(file),\n name: file.name,\n mime: file.type || undefined,\n kind: attachmentKind(file.type),\n size: file.size,\n };\n }\n\n /**\n * Keys that hold a comment list. `loupe:dock` (panel state) and `loupe:msgs:*`\n * (replies) share the prefix but are not comment lists — treating them as one made\n * update()/remove() throw, and would have it hunt a comment id among messages.\n */\n private commentKeys(): string[] {\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(\"loupe:\") && k !== \"loupe:dock\" && !k.startsWith(\"loupe:msgs:\")) keys.push(k);\n }\n return keys;\n }\n\n private parseList(key: string): Comment[] {\n try {\n const value = JSON.parse(localStorage.getItem(key) || \"[]\");\n return Array.isArray(value) ? (value as Comment[]) : [];\n } catch {\n return [];\n }\n }\n\n /** Replies, kept under their own key so they survive a comment being re-saved. */\n private msgKey(threadId: string) {\n return `loupe:msgs:${threadId}`;\n }\n\n async listMessages(threadId: string): Promise<ThreadMessage[]> {\n try {\n const raw = localStorage.getItem(this.msgKey(threadId));\n const parsed = raw ? JSON.parse(raw) : [];\n return Array.isArray(parsed) ? (parsed as ThreadMessage[]) : [];\n } catch {\n return [];\n }\n }\n\n async addMessage(\n threadId: string,\n message: { author: ThreadAuthor; body: string; attachments?: MessageAttachment[] },\n ): Promise<ThreadMessage> {\n const stored: ThreadMessage = {\n id: `m${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n threadId,\n author: message.author,\n body: message.body,\n attachments: message.attachments?.length ? message.attachments : undefined,\n createdAt: new Date().toISOString(),\n };\n const all = await this.listMessages(threadId);\n all.push(stored);\n localStorage.setItem(this.msgKey(threadId), JSON.stringify(all));\n return stored;\n }\n\n /** Offline reactions, keyed per thread. */\n async listReactions(threadId: string): Promise<Reaction[]> {\n try {\n const raw = localStorage.getItem(`loupe:rxn:${threadId}`);\n const parsed = raw ? JSON.parse(raw) : [];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n async toggleReaction(input: { threadId: string; messageId: string; emoji: string; userId: string; userName?: string }): Promise<Reaction[]> {\n const current = await this.listReactions(input.threadId);\n // The same pure toggle the server uses, so offline and online behave identically.\n const next = toggleReaction(current, {\n messageId: input.messageId, emoji: input.emoji, userId: input.userId, userName: input.userName,\n });\n localStorage.setItem(`loupe:rxn:${input.threadId}`, JSON.stringify(next));\n return next;\n }\n\n /** Offline: the people are whoever has already commented locally. */\n async listPeople(projectKey: string): Promise<{ id: string; name: string; email?: string }[]> {\n const prefix = `loupe:${projectKey}:`;\n const seen = new Map<string, { id: string; name: string; email?: string }>();\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (!k || !k.startsWith(prefix)) continue;\n for (const c of this.parseList(k)) {\n if (c.author?.id && !seen.has(c.author.id)) seen.set(c.author.id, c.author);\n }\n }\n return [...seen.values()];\n }\n\n /** Offline mode has no server to notify anyone from. */\n async listNotifications(): Promise<any[]> {\n return [];\n }\n\n async markNotificationsRead(): Promise<void> {\n /* nothing to mark offline */\n }\n\n async update(id: string, patch: Partial<Comment>): Promise<void> {\n // We don't know the url here, so scan the loupe:* list keys for the id.\n for (const k of this.commentKeys()) {\n const list = this.parseList(k);\n const idx = list.findIndex((c) => c.id === id);\n if (idx >= 0) {\n list[idx] = { ...list[idx]!, ...patch };\n localStorage.setItem(k, JSON.stringify(list));\n return;\n }\n }\n }\n\n async remove(id: string): Promise<void> {\n for (const k of this.commentKeys()) {\n const list = this.parseList(k);\n const next = list.filter((c) => c.id !== id);\n if (next.length !== list.length) {\n localStorage.setItem(k, JSON.stringify(next));\n return;\n }\n }\n }\n\n /** Offline: there is no organization to read. */\n async getOrg(): Promise<OrgInfo | null> {\n return null;\n }\n\n /** Offline: no server feed; the panel shows only what this browser reports. */\n async listActivity(_projectKey: string, _since?: string): Promise<ActivityEvent[] | null> {\n return null;\n }\n}\n","import type { ActivityEvent, Attachment, Comment, LoupeUser, MessageAttachment, OrgInfo, Reaction, StorageAdapter, ThreadAuthor, ThreadMessage } from \"./types.js\";\nimport { attachmentKind, fileToDataUrl } from \"./capture.js\";\n\n/**\n * Talks to the Loupe backend. Selected automatically when `apiBase` is set in\n * init(). Sends the identity headers the backend verifies (HMAC in production).\n */\nexport class HttpAdapter implements StorageAdapter {\n constructor(\n private base: string,\n private user: LoupeUser,\n private userHmac?: string,\n private extraHeaders?: Record<string, string>,\n private credentials?: RequestCredentials,\n ) {\n this.base = base.replace(/\\/$/, \"\");\n }\n\n private headers(): HeadersInit {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\", \"X-Loupe-User\": this.user.id };\n if (this.userHmac) h[\"X-Loupe-Hmac\"] = this.userHmac;\n if (this.extraHeaders) Object.assign(h, this.extraHeaders);\n return h;\n }\n\n /** Base fetch options shared by every request (credentials mode, if set). */\n private opts(init?: RequestInit): RequestInit {\n return this.credentials ? { credentials: this.credentials, ...init } : { ...init };\n }\n\n async list(projectKey: string, url: string): Promise<Comment[]> {\n const q = new URLSearchParams({ projectKey, url });\n const res = await fetch(`${this.base}/v1/comments?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`list failed: ${res.status}`);\n return (await res.json()) as Comment[];\n }\n\n /** Every comment in the project (no page filter) — the \"All\" scope. */\n async listAll(projectKey: string): Promise<Comment[]> {\n const q = new URLSearchParams({ projectKey });\n const res = await fetch(`${this.base}/v1/comments?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listAll failed: ${res.status}`);\n return (await res.json()) as Comment[];\n }\n\n /** Upload an inline data-URL asset to object storage; return its URL (or the data URL on failure). */\n private async uploadBlob(projectKey: string, data: string): Promise<string> {\n try {\n const up = await fetch(`${this.base}/v1/blobs`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ projectKey, data }),\n }));\n if (up.ok) return (await up.json()).url as string;\n } catch {\n /* fall back to inlining below */\n }\n return data;\n }\n\n async save(comment: Comment): Promise<Comment> {\n // Upload media to object storage first, then store only the URL — keeps the\n // comment row (and every later list/read) small.\n if (comment.screenshot?.startsWith(\"data:\")) {\n comment = { ...comment, screenshot: await this.uploadBlob(comment.projectKey, comment.screenshot) };\n }\n if (comment.recording?.startsWith(\"data:\")) {\n comment = { ...comment, recording: await this.uploadBlob(comment.projectKey, comment.recording) };\n }\n const res = await fetch(`${this.base}/v1/comments`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(comment),\n }));\n if (!res.ok) throw new Error(`save failed: ${res.status}`);\n return (await res.json()) as Comment;\n }\n\n /** Persist one reporter-attached file to object storage and describe it. */\n async upload(projectKey: string, file: File): Promise<Attachment> {\n const data = await fileToDataUrl(file);\n return {\n url: await this.uploadBlob(projectKey, data),\n name: file.name,\n mime: file.type || undefined,\n kind: attachmentKind(file.type),\n size: file.size,\n };\n }\n\n /** Replies on a thread. The comment's own body is message #1, not returned here. */\n async listMessages(threadId: string): Promise<ThreadMessage[]> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/messages`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listMessages failed: ${res.status}`);\n return (await res.json()) as ThreadMessage[];\n }\n\n async addMessage(\n threadId: string,\n message: { author: ThreadAuthor; body: string; attachments?: MessageAttachment[] },\n ): Promise<ThreadMessage & { mentions?: string[]; unknownMentions?: string[] }> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/messages`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(message),\n }));\n if (!res.ok) throw new Error(`addMessage failed: ${res.status}`);\n return (await res.json()) as ThreadMessage & { mentions?: string[]; unknownMentions?: string[] };\n }\n\n async listReactions(threadId: string): Promise<Reaction[]> {\n // Thread-level, not per message: a thread's reactions are one small set and the\n // client aggregates them, so this is one request rather than one per reply.\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/reactions`, this.opts({ headers: this.headers() }));\n // A 404 means the thread is gone, which for its reactions means there are none.\n if (res.status === 404) return [];\n if (!res.ok) throw new Error(`listReactions failed: ${res.status}`);\n return ((await res.json()) as { reactions: Reaction[] }).reactions;\n }\n\n async toggleReaction(input: { threadId: string; messageId: string; emoji: string; userId: string; userName?: string }): Promise<Reaction[]> {\n const res = await fetch(\n `${this.base}/v1/comments/${encodeURIComponent(input.threadId)}/messages/${encodeURIComponent(input.messageId)}/reactions`,\n this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ emoji: input.emoji, userId: input.userId, userName: input.userName }),\n }),\n );\n if (!res.ok) throw new Error(`toggleReaction failed: ${res.status}`);\n return ((await res.json()) as { reactions: Reaction[] }).reactions;\n }\n\n /** Everyone who has taken part in this project, for mention resolution. */\n async listPeople(projectKey: string): Promise<{ id: string; name: string; email?: string }[]> {\n const q = new URLSearchParams({ projectKey });\n const res = await fetch(`${this.base}/v1/people?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listPeople failed: ${res.status}`);\n return (await res.json()) as { id: string; name: string; email?: string }[];\n }\n\n async listNotifications(projectKey: string, recipient: string): Promise<any[]> {\n const q = new URLSearchParams({ projectKey, recipient });\n const res = await fetch(`${this.base}/v1/notifications?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listNotifications failed: ${res.status}`);\n return ((await res.json()) as { notifications: any[] }).notifications;\n }\n\n async markNotificationsRead(projectKey: string, recipient: string, id?: string): Promise<void> {\n await fetch(`${this.base}/v1/notifications/read`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ projectKey, recipient, id }),\n }));\n }\n\n async update(id: string, patch: Partial<Comment>): Promise<void> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(id)}`, this.opts({\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(patch),\n }));\n if (!res.ok) throw new Error(`update failed: ${res.status}`);\n }\n\n /** The organization, read through the host app. A 404 means the backend has no such endpoint. */\n async getOrg(): Promise<OrgInfo | null> {\n const res = await fetch(`${this.base}/v1/org`, this.opts({ headers: this.headers() }));\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`getOrg failed: ${res.status}`);\n // Check the shape: a proxy's JSON or some other endpoint's answer is not an organization.\n const body = (await res.json()) as OrgInfo;\n if (!body || typeof body !== \"object\" || !body.project || !Array.isArray(body.projects)) {\n throw new Error(\"getOrg: the answer was not an organization\");\n }\n return body;\n }\n\n /** The server's activity feed. A 404 means the backend keeps none. */\n async listActivity(projectKey: string, since?: string): Promise<ActivityEvent[] | null> {\n const q = new URLSearchParams({ projectKey });\n if (since) q.set(\"since\", since);\n const res = await fetch(`${this.base}/v1/activity?${q}`, this.opts({ headers: this.headers() }));\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`listActivity failed: ${res.status}`);\n const body = await res.json();\n if (!Array.isArray(body)) throw new Error(\"listActivity: the answer was not a list\");\n return body as ActivityEvent[];\n }\n\n async remove(id: string): Promise<void> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(id)}`, this.opts({\n method: \"DELETE\",\n headers: this.headers(),\n }));\n if (!res.ok && res.status !== 404) throw new Error(`remove failed: ${res.status}`);\n }\n}\n","import { STYLES } from \"./styles.js\";\nimport type { Peer, Reaction } from \"@loupekit/shared\";\nimport { captureAnchor, resolveAnchor } from \"./fingerprint.js\";\nimport { attachmentKind, captureElementContext, captureScreenshot, captureRegionScreenshot, captureRegionRecording } from \"./capture.js\";\nimport { LocalStorageAdapter } from \"./store.js\";\nimport { HttpAdapter } from \"./http-adapter.js\";\nimport {\n ACTIVITY_STATUS_LABELS,\n addIteration,\n awaitingReview,\n CHANGE_TYPES,\n CHANGE_TYPE_LABELS,\n COMMENT_PRIORITIES,\n canMove,\n canUndo,\n current as currentIteration,\n decide as decideConsent,\n DEFAULT_CHANGE_TYPE,\n DEFAULT_PRIORITY,\n emptyConsent,\n emptyIterations,\n formatDuration,\n iterationLabel,\n isPending as consentPending,\n lifecycle,\n move as moveIteration,\n normalizePriority,\n normalizeStatus,\n PRIORITY_LABELS,\n requestNavigation as requestNav,\n STAGE_LABELS,\n stackLabel,\n threadAsText,\n addToTray,\n clearTray,\n elapsedLabel,\n emptyTray,\n includedItems,\n initialsOf,\n nudgeInTray,\n removeFromTray,\n toggleInclude,\n trayPayload,\n traySummary,\n voiceMessage,\n voiceSupport,\n type TrayState,\n PEER_HEARTBEAT_MS,\n mentionSegments,\n summarizeReactions,\n toggleReaction,\n mentionSuggestions,\n needsYou,\n parseMentions,\n REACTION_CHOICES,\n threadConversation,\n threadTimeline,\n summarizeActivity,\n undo as undoIteration,\n withdraw as withdrawConsent,\n} from \"./types.js\";\nimport type {\n ActivityEvent, ActivityEventInput, ActivityStatus, Anchor, Attachment, ChangeType, Comment, OrgInfo,\n CommentPriority, ConsentRecord, IterationState, LocalAiConfig, LoupeConfig, RegionRect,\n ResolveResult, StorageAdapter, ThreadAuthor, ThreadMessage,\n} from \"./types.js\";\n\ndeclare const __LOUPE_VERSION__: string | undefined;\n/** The build that produced this bundle (baked in by tsup); recorded on every comment. */\nexport const SDK_VERSION = typeof __LOUPE_VERSION__ === \"string\" ? __LOUPE_VERSION__ : \"dev\";\n/** The launcher button's rendered size, used to keep a dragged launcher inside the viewport. */\nconst FAB_SIZE = 46;\n/** Pointer travel (px) before a press on the launcher counts as a drag rather than a tap. */\nconst FAB_DRAG_THRESHOLD = 6;\n/** Keyboard shortcut that shows a hidden launcher again (and hides a shown one). */\nconst LAUNCHER_SHORTCUT = \"Alt+Shift+L\";\n\ntype Mode = \"off\" | \"inspect\" | \"region\" | \"free\" | \"record\";\n/** Accent presets — a variant per theme, since light needs a darker hue to stay legible. */\nconst ACCENTS: { id: string; dark: string; light: string; soft: string }[] = [\n { id: \"indigo\", dark: \"#6b73e6\", light: \"#4a55d6\", soft: \"rgba(107,115,230,0.12)\" },\n { id: \"violet\", dark: \"#a06be6\", light: \"#7c3fd4\", soft: \"rgba(160,107,230,0.14)\" },\n { id: \"teal\", dark: \"#2fb6a8\", light: \"#0f8f83\", soft: \"rgba(47,182,168,0.14)\" },\n { id: \"amber\", dark: \"#d99a2b\", light: \"#a9700f\", soft: \"rgba(217,154,43,0.14)\" },\n { id: \"rose\", dark: \"#e05c86\", light: \"#c2295a\", soft: \"rgba(224,92,134,0.14)\" },\n];\nconst ACCENT_IDS = ACCENTS.map((a) => a.id);\n\n/**\n * The guided tour: one short step per idea a new user needs. Each step names the\n * tab it belongs to, so the tour can move the panel itself out of the way.\n */\nconst TOUR: { sel: string; tab: Tab; title: string; body: string }[] = [\n // Home first: the panel already opens there, so the first step never moves the\n // user — the tour starts where they are.\n { sel: \".hstat\", tab: \"home\", title: \"Home shows what needs you\",\n body: \"Four tiles count open, needs-you, resolved and stale feedback. Click one to narrow the list to that bucket.\" },\n { sel: \".hscope\", tab: \"home\", title: \"This page, or the whole project\",\n body: \"Switch to All to see every page's feedback as a day-grouped timeline.\" },\n { sel: \".tools\", tab: \"comments\", title: \"Pin feedback anywhere\",\n body: \"Inspect picks an element, Note drops a page-level comment, Region captures a rectangle, and Record films one.\" },\n { sel: '.tabs [data-tab=\"activity\"]', tab: \"activity\", title: \"Watch the work happen\",\n body: \"Comments, status changes and forwarded tickets land here as they happen, with anything a bridge or your app reports. Tool chips filter it.\" },\n { sel: '.dctl [data-role=\"settings\"]', tab: \"activity\", title: \"Make it yours\",\n body: \"Accents, the visibility switches, and Restart tour all live here.\" },\n];\n\n/** One contextual hint per built-in view, shown once (unless hints are switched off). */\nconst HINTS: Record<BuiltinTab, { title: string; body: string }> = {\n chat: {\n title: \"Talk to the agent\",\n body: \"Gather what you are looking at and send it in one go. The agent gets it on its very next step — not after it finishes.\",\n },\n home: { title: \"Your triage at a glance\", body: \"The tiles count this page by default. Switch to All for the whole project, or click a tile to jump straight to that bucket.\" },\n comments: { title: \"Pin, note or record\", body: \"Inspect selects an element, Note comments anywhere on the page, Region screenshots a rectangle, and Record captures video of one.\" },\n activity: { title: \"Watch the work happen\", body: \"Every event the bridge or your app reports lands here, alongside Loupe's own operations. Click a tool chip to filter the feed.\" },\n};\n\n/** Where the control panel is anchored — the four layouts the position menu offers. */\ntype DockMode = \"left\" | \"right\" | \"bottom\" | \"float\";\n/** The pages that ship with the panel. Hosts can add more via `init({ tabs })`. */\ntype BuiltinTab = \"home\" | \"comments\" | \"activity\" | \"chat\";\nconst BUILTIN_TABS: { id: BuiltinTab; label: string }[] = [\n { id: \"home\", label: \"Home\" },\n { id: \"comments\", label: \"Comments\" },\n { id: \"activity\", label: \"Activity\" },\n { id: \"chat\", label: \"Chat\" },\n];\n/** A tab id — built-in or host-registered. */\ntype Tab = string;\n/** Which comments the panel is looking at: just this page, or the whole project. */\ntype Scope = \"page\" | \"all\";\n/** A stat tile the user clicked — narrows the list to that bucket. */\ntype StatFilter = \"\" | \"open\" | \"needs_you\" | \"resolved\" | \"stale\";\n/** What the composer is about to attach a comment to. */\ntype ComposeTarget =\n | { kind: \"element\"; element: Element }\n | { kind: \"region\"; region: RegionRect; element: Element | null; screenshot?: string; recording?: string }\n | { kind: \"free\"; offset: { x: number; y: number }; point: { x: number; y: number }; label?: string };\n\nconst DOCK_MODES: DockMode[] = [\"left\", \"right\", \"bottom\", \"float\"];\n/** How long a single screen recording may run before it auto-stops. */\nconst RECORD_MAX_MS = 20000;\n/** Attachment limits for the composer — small enough to survive a base64 POST. */\nconst MAX_FILES = 10;\n/** How often the panel re-reads comments, open threads and mentions when no bridge pushes them. */\nconst SYNC_POLL_MS = 10_000;\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024;\nconst MAX_VIDEO_BYTES = 25 * 1024 * 1024;\n\nconst uid = () =>\n (crypto as any).randomUUID ? crypto.randomUUID() : \"c_\" + Math.abs(hash(String(performance.now()))).toString(36);\nfunction hash(s: string) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return h; }\n\n/**\n * A phone/tablet. `(pointer: coarse)` is the primary signal, but a phone asking for the\n * **desktop site** reports a FINE pointer, so touch capability is the backstop. Getting\n * this wrong sends a finger user down the mouse path: a composer that grabs the focus\n * (keyboard over the page) and a drag-select that fights the page scroll.\n */\nfunction isTouchDevice(): boolean {\n try {\n if (window.matchMedia(\"(pointer: coarse)\").matches) return true;\n if (window.matchMedia(\"(hover: none)\").matches) return true;\n } catch {\n /* matchMedia unavailable */\n }\n if (typeof navigator !== \"undefined\" && (navigator.maxTouchPoints ?? 0) > 0) return true;\n return typeof window !== \"undefined\" && \"ontouchstart\" in window;\n}\n\n/** Whether the browser says the primary pointer is coarse (diagnostic only). */\nfunction coarsePointer(): boolean {\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\n/** Whether screen recording is possible at all (absent in every iOS browser). */\nfunction canShareScreen(): boolean {\n return typeof (navigator.mediaDevices as MediaDevices | undefined)?.getDisplayMedia === \"function\";\n}\n\n/** A captured data-URL as a File, so a screenshot can ride along as a normal attachment. */\nfunction dataUrlToFile(dataUrl: string, name: string): File | null {\n const m = /^data:([^;,]+)(;base64)?,([\\s\\S]*)$/.exec(dataUrl);\n if (!m) return null;\n const [, type, b64, payload = \"\"] = m;\n try {\n const raw = b64 ? atob(payload) : decodeURIComponent(payload);\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);\n return new File([bytes], name, { type: type || \"image/png\" });\n } catch {\n return null;\n }\n}\n\nexport class LoupeApp {\n private cfg: LoupeConfig;\n private store: StorageAdapter;\n private root!: HTMLElement;\n private shadow!: ShadowRoot;\n private overlay!: HTMLElement;\n private hl!: HTMLElement;\n private selbox!: HTMLElement;\n private regionBox!: HTMLElement;\n private composer!: HTMLElement;\n\n /** The dockable control panel (header + tabs + tools + comment list). */\n private dock!: HTMLElement;\n /**\n * The collapsed FAB cluster shown while the panel is closed: a primary brand\n * button (with the comment count) plus quick actions that expand out of it.\n * `launcher` is the primary button itself (kept as a class for the dock's\n * show/hide logic); `fabMinis` is the row of quick actions.\n */\n private fabCluster!: HTMLElement;\n private fabMinis!: HTMLElement;\n private fabBadge!: HTMLElement;\n /** Whether the quick-action minis are expanded out of the primary FAB. */\n private fabExpanded = false;\n /** Whether pin markers are hidden on the page (a quick-action toggle, persisted). */\n private markersHidden = false;\n /**\n * Whether the collapsed launcher is hidden altogether (persisted). The way back is\n * Alt+Shift+L, Settings → Launcher, or the host calling `showLauncher()`.\n */\n private launcherHidden = false;\n /** The way back on a touch screen once the launcher is hidden: a slim tab at the viewport edge. */\n private fabHandle!: HTMLButtonElement;\n /**\n * Where the user dragged the launcher to — the launcher's top-left in viewport px —\n * or null for the default corner on the dock's side. Persisted; clamped on apply so\n * a position saved on a wide screen still lands inside a narrow one.\n */\n private fabPos: { x: number; y: number } | null = null;\n /** The in-flight launcher drag: pointer start, launcher origin, and whether it has moved past the tap threshold. */\n private fabDrag: { px: number; py: number; ox: number; oy: number; moved: boolean } | null = null;\n /** Set for one tick after a drag so the click the browser fires afterwards does not open the panel. */\n private fabSuppressClick = false;\n /** Transient notice at the bottom of the viewport (e.g. how to bring a hidden launcher back). */\n private toastEl!: HTMLElement;\n private toastTimer?: number;\n private themeBtn!: HTMLButtonElement;\n private listEl!: HTMLElement;\n private countEl!: HTMLElement;\n /** Floating \"recording…\" indicator + stop button, shown only while recording. */\n private recBar!: HTMLElement;\n /** Stops the in-flight screen recording (wired while recording). */\n private stopRecording?: () => void;\n\n private comments: Comment[] = [];\n /** Free-text filter over the list (title / body / author). */\n private search = \"\";\n /** Ids of list items the user expanded — items are collapsed by default. */\n private expanded = new Set<string>();\n /** comment.id → currently resolved element (or null when detached). */\n private resolved = new Map<string, Element | null>();\n /** comment.id → pin element. */\n private pins = new Map<string, HTMLElement>();\n\n private mode: Mode = \"off\";\n private lastUrl = \"\";\n /** In-flight region screenshot, captured in the background while the composer is open. */\n private pendingShot?: Promise<string | undefined>;\n private targetOffset = { x: 0.5, y: 0.5 };\n private pending: ComposeTarget | null = null;\n private dragStart: { x: number; y: number } | null = null;\n /** region comment whose outline is currently highlighted (tracks scroll). */\n private activeRegionId: string | null = null;\n private regionTimer?: number;\n\n // ---- control-panel state (persisted in localStorage `loupe:dock`) ----------\n private dockMode: DockMode = \"right\";\n private open = true;\n private theme: \"dark\" | \"light\" = \"dark\";\n private tab: Tab = \"home\";\n /** \"page\" = this URL only; \"all\" = the whole project (the timeline scope). */\n private scope: Scope = \"page\";\n /** Every-page comments, fetched the first time the \"All\" scope is opened. */\n private allComments: Comment[] = [];\n /** True once the project-wide list has been read, so an empty project still shows 0, not ⋯. */\n private allLoaded = false;\n /** A clicked stat tile, which narrows the list. */\n private statFilter: StatFilter = \"\";\n /** The Home overview container (stat tiles + activity), rebuilt on render. */\n private homeEl!: HTMLElement;\n /** Accent preset id (see ACCENTS), applied as inline --accent / --accent-soft. */\n private accent = \"indigo\";\n /** Collapsed to the one-line minimize bar. */\n private minimized = false;\n /** The \"help layer\": FAB tooltips and the contextual hint cards. */\n private hoverHints = true;\n /** Show each comment's page path (useful in the project scope). */\n private showPaths = false;\n /** Views whose hint card has already been shown. */\n private hintsSeen = new Set<string>();\n /** Current guided-tour step, or -1 when the tour is closed. */\n private tourStep = -1;\n /** The first-run tour has been finished or skipped. */\n private tourDone = false;\n private posMenu!: HTMLElement;\n private settingsMenu!: HTMLElement;\n private minBar!: HTMLElement;\n private tourEl!: HTMLElement;\n private tourSpot!: HTMLElement;\n private tourCard!: HTMLElement;\n /** The live Activity feed — in memory only; it is a monitor, not an archive. */\n private activityEvents: ActivityEvent[] = [];\n private activityStatus: ActivityStatus = \"idle\";\n /** A tool chip the user clicked, which narrows the feed to that kind. */\n private activityFilter = \"\";\n /** Auto-scroll the feed to the newest event (off while the user is reading). */\n private activityFollow = true;\n /** The summary card's key/value rows are behind this toggle. */\n private summaryOpen = false;\n private activityEl!: HTMLElement;\n private feedEl!: HTMLElement;\n /** Per-browser project settings: the environment URLs and the Local AI endpoint. */\n private project: { environments: string[]; localAi?: LocalAiConfig } = { environments: [] };\n /** The organization, read once from the backend. Null offline or before it loads. */\n private org: OrgInfo | null = null;\n /** Whether the server keeps an activity feed, and whether the last read reached it. */\n private activityRemote: \"unsupported\" | \"live\" | \"offline\" = \"unsupported\";\n /** Newest server event seen, so a poll asks only for what is new. */\n private activitySince = \"\";\n private activityPoll?: ReturnType<typeof setInterval>;\n /** The backend answered that it keeps no feed, so the panel stops asking. */\n private activityNone = false;\n /** The no-bridge refresh: re-reads comments, open threads and mentions every SYNC_POLL_MS. */\n private syncPoll?: ReturnType<typeof setInterval>;\n private syncBusy = false;\n /** Iteration history per thread — generating a change is a stack, not a one-shot. */\n private iterations = new Map<string, IterationState>();\n /** The thread whose generate pane is open, if any. */\n private genOpen: string | null = null;\n /** Threads with a generation in flight. */\n private genBusy = new Set<string>();\n /** Opacity of the generated plane over the original, 0..1 (the compare slider). */\n private genOpacity = 0.6;\n /** The navigation consent state machine — a URL only ever comes out of `decide`. */\n private consent: ConsentRecord = emptyConsent();\n private consentEl!: HTMLElement;\n /** The live SpeechRecognition instance while dictating, if any. */\n private voice: any = null;\n private voiceEl!: HTMLElement;\n /** The project manager popover, and its search box. */\n private projMenu!: HTMLElement;\n private projOpen = false;\n private projError = \"\";\n private envDraft = \"\";\n /** Float-mode window geometry; (x<=0 && y<=0) → placed on first layout. */\n private floatRect = { x: 0, y: 0, w: 380, h: 540 };\n private floatDrag: { px: number; py: number; ox: number; oy: number } | null = null;\n private floatResize: { px: number; py: number; ow: number; oh: number } | null = null;\n\n private raf = 0;\n private mo?: MutationObserver;\n private tick?: number;\n\n constructor(cfg: LoupeConfig) {\n this.cfg = cfg;\n // apiBase set → talk to the backend; otherwise persist locally (prototype).\n this.store = cfg.apiBase\n ? new HttpAdapter(cfg.apiBase, cfg.user, cfg.userHmac, cfg.headers, cfg.credentials)\n : new LocalStorageAdapter();\n }\n\n private get url() { return location.pathname + location.search; }\n\n /** Chat is experimental: the tab stays dimmed and inert unless the host opts in. */\n private get chatOn() { return this.cfg.chat === true; }\n\n async start() {\n this.loadState();\n this.loadProject();\n this.buildDom();\n document.addEventListener(\"keydown\", this.onLauncherKey);\n document.addEventListener(\"click\", this.onDocumentClick, true);\n document.addEventListener(\"keydown\", this.onMenuKey);\n if (this.cfg.autoOpen) this.open = true;\n this.applyDockLayout();\n this.lastUrl = this.url;\n this.comments = await this.store.list(this.cfg.projectKey, this.url);\n this.renderPins();\n this.renderList();\n this.renderHome();\n this.startPresence();\n this.startLiveThreads();\n // Chat is off unless the host opts in, and then nothing listens for replies either.\n if (this.chatOn) this.startCompanionStream();\n void this.loadNotifications();\n void this.loadOrg();\n void this.loadActivity();\n this.syncActivityPoll();\n this.startSyncPoll();\n // The project-wide list feeds the \"All\" chip's count as well as the All scope, so it\n // is read on every start rather than only once the scope is switched.\n void this.loadAllComments();\n this.observe();\n this.watchNavigation();\n // First run: walk through the panel once. Skippable, never repeated, and off on\n // phones where the sheet is too small to spotlight anything useful.\n if (!this.tourDone && this.open && !this.isMobile()) this.startTour();\n if (this.cfg.autoOpen) this.setMode(this.cfg.tool === \"note\" ? \"free\" : \"inspect\");\n }\n\n /** Arm a tool from outside — the extension's context menus, or a host's own button. */\n openTool(tool: \"inspect\" | \"note\") {\n this.open = true;\n this.applyDockLayout();\n this.setMode(tool === \"note\" ? \"free\" : \"inspect\");\n }\n\n /**\n * Reload comments when the page URL changes without a full reload (SPA\n * navigation), so each page only ever shows its own comments.\n */\n private watchNavigation() {\n const onChange = () => {\n if (this.url === this.lastUrl) return;\n this.lastUrl = this.url;\n void this.reloadComments();\n };\n addEventListener(\"popstate\", onChange);\n // history.pushState/replaceState don't emit events — wrap them once.\n for (const key of [\"pushState\", \"replaceState\"] as const) {\n const original = history[key];\n history[key] = function (this: History, ...args: unknown[]) {\n const result = (original as (...a: unknown[]) => unknown).apply(this, args);\n dispatchEvent(new Event(\"loupe:locationchange\"));\n return result;\n } as History[typeof key];\n }\n addEventListener(\"loupe:locationchange\", onChange);\n }\n\n private async reloadComments() {\n try {\n this.comments = await this.store.list(this.cfg.projectKey, this.url);\n this.renderPins();\n this.renderList();\n } catch { /* keep the current view on transient errors */ }\n }\n\n /**\n * Keep the panel current without a reload.\n *\n * A status moved in another app (CRM approving a ticket), a reply relayed through Hub,\n * or a teammate's new pin otherwise appears only after the page reloads. The bridge's\n * SSE covers threads when one is configured; this covers everything else, for every\n * host. It pauses while the tab is hidden and catches up the moment it is shown again.\n */\n private startSyncPoll() {\n if (this.syncPoll) return;\n this.syncPoll = setInterval(() => void this.syncTick(), SYNC_POLL_MS);\n document.addEventListener(\"visibilitychange\", this.onSyncVisible);\n }\n\n private onSyncVisible = () => {\n if (document.visibilityState === \"visible\") void this.syncTick();\n };\n\n private async syncTick() {\n if (this.syncBusy || document.visibilityState === \"hidden\") return;\n // A re-render rebuilds the list, which would take the caret out of a reply box.\n const active = this.shadow?.activeElement;\n if (active && (active.tagName === \"TEXTAREA\" || active.tagName === \"INPUT\")) return;\n this.syncBusy = true;\n try {\n const url = this.url;\n const threads = [...this.messages.keys()];\n const [page, all, ...replies] = await Promise.all([\n this.store.list(this.cfg.projectKey, url).catch(() => null),\n this.allLoaded || this.scope === \"all\" ? this.store.listAll(this.cfg.projectKey).catch(() => null) : null,\n ...threads.map((id) => this.store.listMessages(id).catch(() => null)),\n ]);\n // Navigated while the reads were in flight: watchNavigation already reloaded.\n if (url !== this.url) return;\n let changed = false;\n if (Array.isArray(page) && JSON.stringify(page) !== JSON.stringify(this.comments)) {\n this.comments = page;\n changed = true;\n }\n if (Array.isArray(all) && JSON.stringify(all) !== JSON.stringify(this.allComments)) {\n this.allComments = all;\n changed = true;\n }\n threads.forEach((id, i) => {\n const list = replies[i];\n if (!Array.isArray(list)) return;\n // Replies still sending, or failed with a Retry, exist only here; keep them.\n const local = (this.messages.get(id) ?? []).filter((m) => this.msgPending.has(m.id) || this.msgFailed.has(m.id));\n const next = [...list, ...local];\n if (JSON.stringify(next) === JSON.stringify(this.messages.get(id))) return;\n this.messages.set(id, next);\n changed = true;\n });\n if (changed) {\n this.renderPins();\n this.renderList();\n this.renderHome();\n }\n } finally {\n this.syncBusy = false;\n }\n void this.loadNotifications();\n }\n\n // ---- DOM construction -----------------------------------------------------\n\n private buildDom() {\n this.root = document.createElement(\"div\");\n this.root.id = \"loupe-root\";\n document.body.appendChild(this.root);\n this.shadow = this.root.attachShadow({ mode: \"open\" });\n\n const style = document.createElement(\"style\");\n style.textContent = STYLES;\n this.shadow.appendChild(style);\n\n this.overlay = el(\"div\", \"overlay\");\n this.hl = el(\"div\", \"hl\");\n this.hl.appendChild(el(\"span\", \"tip\"));\n this.selbox = el(\"div\", \"selbox\");\n this.regionBox = el(\"div\", \"region-box\");\n this.overlay.append(this.hl, this.selbox, this.regionBox);\n this.shadow.appendChild(this.overlay);\n\n this.composer = el(\"div\", \"composer\");\n this.shadow.appendChild(this.composer);\n\n this.dock = this.buildDock();\n this.fabCluster = this.buildFabCluster();\n this.fabHandle = el(\"button\", \"fab-handle\") as HTMLButtonElement;\n this.fabHandle.type = \"button\";\n this.fabHandle.title = \"Show the launcher\";\n this.fabHandle.setAttribute(\"aria-label\", \"Show the launcher\");\n this.fabHandle.onclick = () => this.setLauncherHidden(false);\n this.recBar = this.buildRecBar();\n this.toastEl = el(\"div\", \"toast\");\n this.toastEl.setAttribute(\"role\", \"status\");\n this.toastEl.setAttribute(\"aria-live\", \"polite\");\n this.toastEl.onclick = () => this.toastEl.classList.remove(\"show\");\n\n // Guided tour overlay — click-through by design (see STYLES), so it can never\n // trap someone mid-task.\n this.tourEl = el(\"div\", \"tour\");\n this.tourSpot = el(\"div\", \"tour-spot\");\n this.tourCard = el(\"div\", \"tour-card\");\n this.tourEl.append(this.tourSpot, this.tourCard);\n\n this.shadow.append(this.dock, this.fabCluster, this.fabHandle, this.recBar, this.toastEl, this.tourEl);\n\n // A click anywhere outside a popover dismisses it.\n this.shadow.addEventListener(\"click\", (e) => {\n const t = e.target as HTMLElement | null;\n if (t?.closest && t.closest(\".menu-wrap\")) return;\n this.closeMenus();\n });\n }\n\n /**\n * The dockable control panel:\n * header (brand + dock controls) → tabs → [Comments view: tools + list + integrations]\n * and a [Connect view] with the Claude/MCP onboarding steps.\n */\n private buildDock(): HTMLElement {\n const dock = el(\"div\", \"dock\");\n\n // header ------------------------------------------------------------------\n const head = el(\"div\", \"dhead\");\n const brand = el(\"div\", \"brand\");\n brand.innerHTML = `<span class=\"logo\">◎</span><span class=\"title\"></span>`;\n (brand.querySelector(\".title\") as HTMLElement).textContent = this.cfg.label ?? \"Loupe\";\n head.addEventListener(\"pointerdown\", this.onHeadPointerDown); // drag in float mode\n\n const ctl = el(\"div\", \"dctl\");\n\n // Position menu — one button opening a 2x2 grid of the four layouts. Four\n // separate header buttons left no room once settings and minimize moved in.\n const posWrap = el(\"div\", \"menu-wrap\");\n const posBtn = el(\"button\") as HTMLButtonElement;\n posBtn.dataset.role = \"pos\";\n posBtn.title = \"Panel position\";\n posBtn.setAttribute(\"aria-label\", \"Panel position\");\n posBtn.innerHTML = I_DOCK_RIGHT;\n this.posMenu = el(\"div\", \"menu\");\n const posMeta: { mode: DockMode; icon: string; label: string }[] = [\n { mode: \"left\", icon: I_DOCK_LEFT, label: \"Left\" },\n { mode: \"bottom\", icon: I_DOCK_BOTTOM, label: \"Bottom\" },\n { mode: \"right\", icon: I_DOCK_RIGHT, label: \"Right\" },\n { mode: \"float\", icon: I_FLOAT, label: \"Float\" },\n ];\n this.posMenu.innerHTML = `<div class=\"menu-label\">Position</div><div class=\"pos-grid\">` +\n posMeta.map((m) => `<button data-pos=\"${m.mode}\">${m.icon}<span>${m.label}</span></button>`).join(\"\") +\n `</div>`;\n this.posMenu.querySelectorAll<HTMLElement>(\"[data-pos]\").forEach((b) => {\n b.onclick = () => { this.setDock(b.dataset.pos as DockMode); this.closeMenus(); };\n });\n posBtn.onclick = () => this.toggleMenu(this.posMenu);\n posWrap.append(posBtn, this.posMenu);\n\n this.themeBtn = el(\"button\") as HTMLButtonElement;\n this.themeBtn.dataset.role = \"theme\";\n this.themeBtn.onclick = () => this.toggleTheme();\n\n // Settings dropdown (theme accents, the help layer, replaying the tour).\n const setWrap = el(\"div\", \"menu-wrap\");\n const setBtn = el(\"button\") as HTMLButtonElement;\n setBtn.dataset.role = \"settings\";\n setBtn.title = \"Settings\";\n setBtn.setAttribute(\"aria-label\", \"Settings\");\n setBtn.innerHTML = I_GEAR;\n setBtn.onclick = () => this.toggleMenu(this.settingsMenu);\n // Built once and only ever reflected into — rewriting this menu's innerHTML on\n // every paint detached the row being clicked, so the outside-click handler saw\n // a detached target and closed the menu out from under the user.\n this.settingsMenu = el(\"div\", \"menu\");\n this.settingsMenu.innerHTML =\n `<div class=\"menu-label\">Appearance</div>` +\n `<div class=\"acc-dots\">` +\n ACCENTS.map((a) =>\n `<button class=\"acc-dot\" data-accent=\"${a.id}\" style=\"background:${a.dark}\" ` +\n `title=\"${a.id}\" aria-label=\"${a.id} accent\"></button>`).join(\"\") +\n `</div><div class=\"menu-sep\"></div><div class=\"menu-label\">Show</div>` +\n `<button class=\"menu-row\" data-set=\"hoverHints\" aria-pressed=\"true\"><span>Hover hints</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"markersHidden\" aria-pressed=\"true\"><span>Markers</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"showPaths\" aria-pressed=\"false\"><span>Page paths</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"launcherHidden\" aria-pressed=\"true\" title=\"The ◎ button shown while the panel is closed. ${LAUNCHER_SHORTCUT} toggles it too.\"><span>Launcher</span><span class=\"sw\"></span></button>` +\n `<div class=\"menu-sep\"></div>` +\n `<button class=\"menu-row\" data-set=\"fabReset\" hidden><span>Reset launcher position</span></button>` +\n `<button class=\"menu-row\" data-set=\"tour\"><span>Restart tour</span></button>` +\n `<div class=\"menu-ver\"><span>Loupe <b>v${escapeHtml(SDK_VERSION)}</b>${this.packageVersionNote()}</span>` +\n `<span class=\"menu-mode\">${this.cfg.apiBase ? \"server\" : \"offline\"}</span></div>`;\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-accent]\").forEach((b) => {\n b.onclick = () => this.setAccent(b.dataset.accent!);\n });\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-set]\").forEach((b) => {\n b.onclick = () => {\n const key = b.dataset.set!;\n if (key === \"tour\") { this.closeMenus(); this.startTour(); return; }\n if (key === \"fabReset\") { this.closeMenus(); this.resetLauncherPosition(); return; }\n this.toggleSetting(key as \"markersHidden\" | \"hoverHints\" | \"showPaths\" | \"launcherHidden\");\n };\n });\n setWrap.append(setBtn, this.settingsMenu);\n\n const minBtn = el(\"button\") as HTMLButtonElement;\n minBtn.dataset.role = \"min\";\n minBtn.title = \"Minimize\";\n minBtn.setAttribute(\"aria-label\", \"Minimize\");\n minBtn.innerHTML = I_MINIMIZE;\n minBtn.onclick = () => this.setMinimized(true);\n\n const closeBtn = el(\"button\") as HTMLButtonElement;\n closeBtn.dataset.role = \"close\";\n closeBtn.title = \"Close\";\n closeBtn.setAttribute(\"aria-label\", \"Close\");\n closeBtn.innerHTML = I_CLOSE;\n closeBtn.onclick = () => this.closeDock();\n ctl.append(posWrap, this.themeBtn, setWrap, minBtn, closeBtn);\n\n // Who else has this page open. Hidden entirely when there is no bridge — an empty\n // cluster would read as \"nobody is here\", which is a different claim from \"we\n // cannot know who is here\".\n this.peerEl = el(\"div\", \"peers\");\n // Hidden from the start when there is no bridge: waiting for the first render to\n // hide it would show an empty cluster in the meantime.\n if (!this.cfg.bridge) this.peerEl.style.display = \"none\";\n head.append(brand, this.peerEl, ctl);\n\n // The minimize bar: a one-line strip that keeps the panel's context on screen.\n this.minBar = el(\"div\", \"minbar\");\n this.minBar.onclick = () => this.setMinimized(false);\n\n // tabs (built-in pages, then whatever the host registered) -----------------\n this.tabList = [...BUILTIN_TABS, ...(this.cfg.tabs ?? []).map((t) => ({ id: t.id, label: t.label }))];\n const tabs = el(\"div\", \"tabs\");\n for (const t of this.tabList) {\n const off = t.id === \"chat\" && !this.chatOn;\n const b = el(\"button\", off ? \"tab off\" : \"tab\", t.label) as HTMLButtonElement;\n b.dataset.tab = t.id;\n if (off) {\n b.setAttribute(\"aria-disabled\", \"true\");\n b.title = \"Chat — coming soon\";\n }\n b.onclick = () => this.setTab(t.id);\n tabs.appendChild(b);\n }\n\n // tools -------------------------------------------------------------------\n const tools = el(\"div\", \"tools\");\n const inspectBtn = this.toolBtn(\"✛\", \"Inspect\", \"inspect\");\n inspectBtn.title = \"Inspect an element and comment on it\";\n inspectBtn.onclick = () => this.setMode(this.mode === \"inspect\" ? \"off\" : \"inspect\");\n const freeBtn = this.toolBtn(NOTE_ICON, \"Note\", \"free\");\n freeBtn.title = \"Drop a note anywhere on the page — no element, no screenshot\";\n freeBtn.onclick = () => this.setMode(this.mode === \"free\" ? \"off\" : \"free\");\n const regionBtn = this.toolBtn(REGION_ICON, \"Region\", \"region\");\n regionBtn.title = \"Drag a free-size box, screenshot it, and comment\";\n regionBtn.onclick = () => this.setMode(this.mode === \"region\" ? \"off\" : \"region\");\n const recordBtn = this.toolBtn(RECORD_ICON, \"Record\", \"record\");\n recordBtn.title = isTouchDevice()\n ? \"Record your screen, then describe the issue\"\n : \"Drag a box, record a screen video of it, and comment\";\n recordBtn.onclick = () => this.setMode(this.mode === \"record\" ? \"off\" : \"record\");\n\n // Screen recording is desktop-only: NO mobile browser supports getDisplayMedia\n // (iOS Safari never has; Chrome/Firefox on Android expose it in old versions but every\n // call fails — recorded as unsupported). So on a phone we cannot record the screen\n // from the page at all. What we can do is take the clip the phone already recorded\n // with its own screen recorder — so open the picker for it, and deliberately WITHOUT\n // a `capture` attribute: that would open the camera, and filming the room is not a\n // screen recording.\n if (canShareScreen()) {\n tools.append(inspectBtn, freeBtn, regionBtn, recordBtn);\n } else if (isTouchDevice()) {\n const videoBtn = this.toolBtn(VIDEO_ICON, \"Video\", \"video\");\n videoBtn.title = \"Attach a video — record your screen with your phone, then pick it here\";\n videoBtn.onclick = () => this.pickVideo();\n tools.append(inspectBtn, freeBtn, regionBtn, videoBtn);\n } else {\n tools.append(inspectBtn, freeBtn, regionBtn);\n }\n\n // list --------------------------------------------------------------------\n const listHead = el(\"div\", \"listhead\");\n listHead.append(document.createTextNode(\"Comments\"));\n this.countEl = el(\"span\", \"count\", \"0\");\n listHead.appendChild(this.countEl);\n const search = el(\"input\", \"search\") as HTMLInputElement;\n search.type = \"search\";\n search.placeholder = \"Search…\";\n search.value = this.search;\n search.oninput = () => { this.search = search.value; this.renderList(); };\n listHead.appendChild(search);\n this.listEl = el(\"div\", \"list\");\n\n // Home view = the overview surface the panel opens on.\n const homeView = el(\"div\", \"view home-view\");\n this.homeEl = homeView;\n\n // Comments view = hint card + tools + list + the \"integrates with\" footer.\n const commentsView = el(\"div\", \"view comments-view\");\n this.commentsHint = el(\"div\", \"hint-slot\");\n this.reviewBar = el(\"div\", \"reviewbar\");\n this.reviewBar.style.display = \"none\";\n commentsView.append(this.commentsHint, tools, listHead, this.reviewBar, this.listEl, this.buildIntegrations());\n\n // Activity view = the live monitor (status, summary, chips, feed). The hint slot\n // is part of this panel's own markup — appending it beforehand would be wiped by\n // the innerHTML below.\n const activityView = el(\"div\", \"view activity-view\");\n this.activityEl = activityView;\n\n // Chat view = the companion: a gather tray, a composer with dictation, and the\n // transcript of what was said to the agent and what it said back.\n const chatView = el(\"div\", \"view chat-view\");\n this.chatEl = chatView;\n\n // Host-registered tabs. `render` runs once, here, and gets a context object —\n // the panel never reaches into a tab, and a tab never reaches into the panel.\n const customViews = (this.cfg.tabs ?? []).map((t) => {\n const view = el(\"div\", \"view custom-view\");\n const slot = el(\"div\", \"hint-slot\");\n view.appendChild(slot);\n this.customHintSlots.set(t.id, slot);\n try {\n const out = t.render({\n projectKey: this.cfg.projectKey,\n apiBase: this.cfg.apiBase,\n user: this.cfg.user,\n comments: this.comments,\n url: this.url,\n version: SDK_VERSION,\n track: (event) => this.addActivity(event),\n open: (id) => this.setTab(id),\n close: () => this.closeDock(),\n });\n if (typeof out === \"string\") {\n // Built through innerHTML on a throwaway wrapper rather than\n // insertAdjacentHTML, which not every DOM implementation provides.\n const wrap = el(\"div\", \"tab-body\");\n wrap.innerHTML = out;\n view.append(...Array.from(wrap.childNodes));\n } else if (out) view.appendChild(out);\n } catch (e) {\n // A broken tab must not take the panel with it.\n view.appendChild(el(\"div\", \"empty\", `This tab failed to render: ${e instanceof Error ? e.message : String(e)}`));\n }\n return view;\n });\n\n const resize = el(\"div\", \"resize\");\n resize.addEventListener(\"pointerdown\", this.onResizeDown);\n\n // The navigation consent prompt. It lives above the tabs so an agent's request is\n // answered from wherever the user happens to be, not only on one page.\n this.consentEl = el(\"div\", \"consent\");\n this.consentEl.style.display = \"none\";\n\n dock.append(head, this.minBar, this.consentEl, tabs, homeView, commentsView, activityView, chatView, ...customViews, resize);\n for (const [id, view] of [[\"home\", homeView], [\"comments\", commentsView], [\"activity\", activityView], [\"chat\", chatView]] as [string, HTMLElement][]) {\n this.viewEls.set(id, view);\n }\n customViews.forEach((v, i) => this.viewEls.set((this.cfg.tabs ?? [])[i]!.id, v));\n this.buildHomePanel();\n this.buildActivityPanel();\n this.buildChatPanel();\n return dock;\n }\n\n /** The contextual hint cards live in a slot at the top of each view. */\n private commentsHint!: HTMLElement;\n private activityHint!: HTMLElement;\n /** The \"N waiting on your review\" strip above the list. */\n private reviewBar!: HTMLElement;\n /** Tab id → its hint slot (custom tabs only; the built-ins have named fields). */\n private customHintSlots = new Map<string, HTMLElement>();\n /** The tab strip, in order. */\n private tabList: { id: string; label: string }[] = [];\n /**\n * Each page's container, keyed by tab id. Display is driven by an \"on\" class\n * rather than a `.tab-<id>` selector, so host-registered ids need no CSS.\n */\n private viewEls = new Map<string, HTMLElement>();\n\n /**\n * The Activity view: a status row, a collapsible summary, the tool chips and the\n * live feed. Everything is re-derived from `activityEvents` on render, so the\n * summary and the micro-stats can never disagree with the feed below them.\n */\n // ---- companion chat (#28) -------------------------------------------------\n\n /** The chat page's root. */\n private chatEl!: HTMLElement;\n /** The gather tray: elements and screenshots collected into one message. */\n private chatTray: TrayState = emptyTray();\n /** Sent messages and received replies, in one ordered transcript. */\n private chatLog: { id: string; at: string; mine: boolean; author?: string; body: string; count?: number }[] = [];\n private chatUnread = 0;\n private chatSending = false;\n private chatError = \"\";\n private voiceOn = false;\n private voiceBase = \"\";\n private voiceStart = 0;\n private voiceTimer?: ReturnType<typeof setInterval>;\n private companionSource?: EventSource;\n\n private buildChatPanel() {\n this.chatEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-chint\"></div>` +\n `<div class=\"chat-tray\" id=\"loupe-tray\"></div>` +\n `<div class=\"chat-log\" id=\"loupe-chatlog\"></div>` +\n `<div class=\"chat-compose\">` +\n `<textarea class=\"chat-in\" id=\"loupe-chatin\" rows=\"2\" placeholder=\"Tell the agent what you see…\"></textarea>` +\n `<div class=\"chat-foot\">` +\n `<button class=\"chat-add\" id=\"loupe-chatadd\" title=\"Add what you have selected\">+ Selection</button>` +\n `<button class=\"chat-mic\" id=\"loupe-chatmic\" title=\"Dictate\">🎙</button>` +\n `<span class=\"chat-rec\" id=\"loupe-chatrec\" style=\"display:none\"><span class=\"chat-rec-dot\"></span><span id=\"loupe-chatrectime\">0:00</span></span>` +\n `<span class=\"chat-spacer\"></span>` +\n `<span class=\"chat-err\" id=\"loupe-chaterr\"></span>` +\n `<button class=\"chat-send\" id=\"loupe-chatsend\">Send</button>` +\n `</div></div>`;\n\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n input.addEventListener(\"click\", (e) => e.stopPropagation());\n input.oninput = () => { this.chatError = \"\"; this.renderChatError(); };\n input.onkeydown = (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) { e.preventDefault(); void this.sendCompanion(); }\n };\n\n (this.chatEl.querySelector(\"#loupe-chatadd\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n void this.addSelectionToTray();\n };\n (this.chatEl.querySelector(\"#loupe-chatsend\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n void this.sendCompanion();\n };\n (this.chatEl.querySelector(\"#loupe-chatmic\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n this.toggleVoice();\n };\n\n this.renderChatTray();\n this.renderChatLog();\n this.updateChatBadge();\n }\n\n /** The Chat tab label carries the unread count, so it is visible from any page. */\n private updateChatBadge() {\n if (!this.chatOn) return;\n const tab = this.tabList.findIndex((t) => t.id === \"chat\");\n const buttons = this.shadow?.querySelectorAll<HTMLElement>(\".tabs .tab\");\n const el2 = buttons?.[tab];\n if (!el2) return;\n el2.textContent = this.chatUnread ? `Chat · ${this.chatUnread > 9 ? \"9+\" : this.chatUnread}` : \"Chat\";\n }\n\n private renderChatError() {\n const box = this.chatEl?.querySelector(\"#loupe-chaterr\") as HTMLElement | null;\n if (box) box.textContent = this.chatError;\n }\n\n private renderChatTray() {\n const box = this.chatEl?.querySelector(\"#loupe-tray\") as HTMLElement | null;\n if (!box) return;\n box.textContent = \"\";\n if (!this.chatTray.items.length) { box.style.display = \"none\"; return; }\n box.style.display = \"\";\n\n const head = el(\"div\", \"tray-head\");\n head.append(\n el(\"span\", \"tray-title\", traySummary(this.chatTray)),\n el(\"span\", \"tray-spacer\"),\n );\n const clear = el(\"button\", \"tray-x\", \"Clear\") as HTMLButtonElement;\n clear.onclick = (e) => { e.stopPropagation(); this.chatTray = clearTray(); this.renderChatTray(); };\n head.appendChild(clear);\n box.appendChild(head);\n\n this.chatTray.items.forEach((item, i) => {\n const chip = el(\"div\", \"tray-chip\" + (item.include ? \"\" : \" off\"));\n\n const check = el(\"input\") as HTMLInputElement;\n check.type = \"checkbox\";\n check.checked = item.include;\n check.title = \"Include in the message\";\n check.onchange = (e) => {\n e.stopPropagation();\n this.chatTray = toggleInclude(this.chatTray, item.id);\n this.renderChatTray();\n };\n\n const label = el(\"span\", \"tray-label\", item.label);\n label.title = item.label + (item.url ? ` — ${item.url}` : \"\");\n\n const up = el(\"button\", \"tray-nudge\", \"↑\") as HTMLButtonElement;\n up.disabled = i === 0;\n up.onclick = (e) => { e.stopPropagation(); this.chatTray = nudgeInTray(this.chatTray, item.id, -1); this.renderChatTray(); };\n\n const down = el(\"button\", \"tray-nudge\", \"↓\") as HTMLButtonElement;\n down.disabled = i === this.chatTray.items.length - 1;\n down.onclick = (e) => { e.stopPropagation(); this.chatTray = nudgeInTray(this.chatTray, item.id, 1); this.renderChatTray(); };\n\n const x = el(\"button\", \"tray-x\", \"✕\") as HTMLButtonElement;\n x.title = \"Remove\";\n x.onclick = (e) => { e.stopPropagation(); this.chatTray = removeFromTray(this.chatTray, item.id); this.renderChatTray(); };\n\n chip.append(check, item.thumb ? (() => { const img = el(\"img\", \"tray-thumb\") as HTMLImageElement; img.src = item.thumb!; img.alt = \"\"; return img; })() : el(\"span\", \"tray-kind\", item.kind), label, up, down, x);\n box.appendChild(chip);\n });\n }\n\n private renderChatLog() {\n const box = this.chatEl?.querySelector(\"#loupe-chatlog\") as HTMLElement | null;\n if (!box) return;\n box.textContent = \"\";\n if (!this.chatLog.length) {\n box.appendChild(el(\"div\", \"chat-empty\",\n this.cfg.bridge\n ? \"Say what you see while the agent works — it lands on the agent’s very next step.\"\n : \"Connect a bridge to talk to the agent. Without one there is nothing to deliver to.\"));\n return;\n }\n for (const m of this.chatLog) {\n const row = el(\"div\", \"chat-msg\" + (m.mine ? \" mine\" : \"\"));\n const head = el(\"div\", \"chat-head\");\n head.append(\n el(\"b\", \"chat-who\", m.mine ? \"You\" : (m.author ?? \"Agent\")),\n el(\"span\", \"chat-when\", fmtAgo(m.at)),\n );\n if (m.count) head.appendChild(el(\"span\", \"chat-ctx\", `${m.count} context${m.count === 1 ? \"\" : \"s\"}`));\n const body = el(\"div\", \"chat-body\");\n for (const seg of mentionSegments(m.body, parseMentions(m.body))) {\n if (seg.mention) body.appendChild(el(\"span\", \"mention\", seg.text));\n else body.appendChild(document.createTextNode(seg.text));\n }\n row.append(head, body);\n box.appendChild(row);\n }\n box.scrollTop = box.scrollHeight;\n }\n\n /** Pull the current selection off the bridge and into the tray. */\n private async addSelectionToTray() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) { this.chatError = \"No bridge configured.\"; this.renderChatError(); return; }\n try {\n const res = await fetch(`${base}/selection/latest`);\n if (!res.ok) throw new Error(String(res.status));\n const { selection } = (await res.json()) as { selection?: any };\n if (!selection) { this.chatError = \"Nothing selected yet.\"; this.renderChatError(); return; }\n this.chatTray = addToTray(this.chatTray, {\n id: selection.correlationId ?? selection.selector ?? String(selection.at),\n kind: \"element\",\n // The selector is what identifies it; the text makes it recognisable.\n label: `${selection.selector ?? selection.tag ?? \"element\"}${selection.text ? ` — “${String(selection.text).slice(0, 24)}”` : \"\"}`,\n url: selection.url,\n ref: selection.correlationId ?? selection.selector,\n });\n this.chatError = \"\";\n this.renderChatError();\n this.renderChatTray();\n } catch (e) {\n this.chatError = e instanceof Error ? `Could not read the selection: ${e.message}` : \"Could not read the selection.\";\n this.renderChatError();\n }\n }\n\n private async sendCompanion() {\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n const body = input.value.trim();\n const contexts = trayPayload(this.chatTray);\n // A tray-only message is still a brief: showing three elements is a sentence.\n if (!body && !contexts.length) return;\n if (this.chatSending) return;\n\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) { this.chatError = \"No bridge configured — nothing to deliver to.\"; this.renderChatError(); return; }\n\n this.chatSending = true;\n this.chatError = \"\";\n this.renderChatError();\n const optimistic = {\n id: `pending-${Date.now().toString(36)}`,\n at: new Date().toISOString(),\n mine: true,\n body: body || \"(context only)\",\n count: contexts.length,\n };\n this.chatLog.push(optimistic);\n this.renderChatLog();\n\n try {\n const res = await fetch(`${base}/companion`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n body: body || \"(see the gathered context)\",\n author: { id: this.cfg.user.id, name: this.cfg.user.name },\n contexts,\n attachments: includedItems(this.chatTray)\n .filter((i) => i.kind === \"screenshot\" && i.thumb)\n .map((i) => ({ url: i.thumb!, kind: \"image\", name: i.label })),\n voice: this.voiceBase.length > 0,\n }),\n });\n if (!res.ok) throw new Error(`the bridge answered ${res.status}`);\n // Sent, so the tray has done its job.\n input.value = \"\";\n this.chatTray = clearTray();\n this.modelVoiceBase(\"\");\n this.renderChatTray();\n this.addActivity({ kind: \"message.create\", label: `Sent a brief to the agent${contexts.length ? ` (${contexts.length} contexts)` : \"\"}` });\n } catch (e) {\n this.chatError = e instanceof Error ? e.message : \"Could not send.\";\n this.renderChatError();\n this.addActivity({ kind: \"error\", level: \"error\", label: \"Companion message failed to send\" });\n } finally {\n this.chatSending = false;\n this.renderChatLog();\n }\n }\n\n private modelVoiceBase(v: string) { this.voiceBase = v; }\n\n /**\n * Dictation.\n *\n * Two different reasons the control can be unavailable, and they need different\n * words: an unsupported browser is a fact, while a non-secure page is something the\n * person can fix. Saying \"your browser cannot do this\" when the real problem is\n * `http://` sends them looking in the wrong place.\n */\n private toggleVoice() {\n const support = voiceSupport({\n hasCtor: typeof (globalThis as any).SpeechRecognition !== \"undefined\" || typeof (globalThis as any).webkitSpeechRecognition !== \"undefined\",\n isSecureContext: typeof isSecureContext === \"boolean\" ? isSecureContext : true,\n });\n if (support !== \"supported\") {\n this.chatError = voiceMessage(support) ?? \"Dictation is unavailable.\";\n this.renderChatError();\n return;\n }\n if (this.voiceOn) return this.stopChatVoice();\n\n const Ctor = (globalThis as any).SpeechRecognition ?? (globalThis as any).webkitSpeechRecognition;\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n try {\n // One recogniser for the whole panel: two running at once would fight over the\n // microphone and each would transcribe the other's session.\n this.stopChatVoice();\n const rec = new Ctor();\n rec.continuous = true;\n rec.interimResults = true;\n rec.lang = document.documentElement.lang || \"en-US\";\n // Dictation appends to whatever was already typed rather than replacing it.\n this.voiceBase = input.value ? `${input.value.trim()} ` : \"\";\n rec.onresult = (ev: any) => {\n let text = \"\";\n for (let i = ev.resultIndex; i < ev.results.length; i++) text += ev.results[i][0].transcript;\n input.value = `${this.voiceBase}${text}`;\n };\n rec.onerror = (ev: any) => {\n this.chatError = ev?.error === \"not-allowed\" ? \"Microphone permission was refused.\" : \"Dictation stopped.\";\n this.renderChatError();\n this.stopChatVoice();\n };\n rec.onend = () => { if (this.voiceOn) this.stopChatVoice(); };\n rec.start();\n this.voice = rec;\n this.voiceTarget = input;\n this.voiceOn = true;\n this.voiceStart = Date.now();\n const pill = this.chatEl.querySelector(\"#loupe-chatrec\") as HTMLElement;\n pill.style.display = \"\";\n this.voiceTimer = setInterval(() => {\n const t = this.chatEl.querySelector(\"#loupe-chatrectime\") as HTMLElement | null;\n if (t) t.textContent = elapsedLabel(Date.now() - this.voiceStart);\n }, 500);\n this.chatEl.querySelector(\"#loupe-chatmic\")!.classList.add(\"on\");\n this.renderChatTray();\n } catch (e) {\n this.chatError = e instanceof Error ? e.message : \"Could not start dictation.\";\n this.renderChatError();\n }\n }\n\n private stopChatVoice() {\n this.voiceOn = false;\n if (this.voiceTimer) clearInterval(this.voiceTimer);\n this.voiceTimer = undefined;\n // Release the shared recogniser, so the panel never holds the microphone after the\n // person stopped talking to it.\n this.stopVoice();\n const pill = this.chatEl?.querySelector(\"#loupe-chatrec\") as HTMLElement | null;\n if (pill) pill.style.display = \"none\";\n this.chatEl?.querySelector(\"#loupe-chatmic\")?.classList.remove(\"on\");\n }\n\n /**\n * Follow the bridge for replies.\n *\n * With SSE where it works and a poll where it does not, because a reply the person\n * never sees is the same as no reply — and the panel is the only place it appears.\n */\n private startCompanionStream() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base || this.companionSource) return;\n if (typeof EventSource === \"undefined\") return;\n try {\n const source = new EventSource(`${base}/events`);\n // Named event, for the same reason as the thread stream above.\n source.addEventListener(\"companion\", (ev) => {\n let parsed: any;\n try { parsed = JSON.parse((ev as MessageEvent).data); } catch { return; }\n if (parsed?.eventType === \"reply\") this.receiveReply(parsed.data);\n });\n source.onerror = () => {};\n this.companionSource = source;\n // The stream can die without an event (a sleeping laptop); a slow poll keeps the\n // replies arriving either way.\n this.companionPoll = setInterval(() => void this.pollReplies(), 5000);\n } catch {\n // No stream: the poll is the whole transport then.\n this.companionPoll = setInterval(() => void this.pollReplies(), 4000);\n }\n }\n\n private companionPoll?: ReturnType<typeof setInterval>;\n private lastReplyId = \"\";\n\n private async pollReplies() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) return;\n try {\n const res = await fetch(`${base}/companion?since=${encodeURIComponent(this.lastReplyId)}`);\n if (!res.ok) return;\n const { replies } = (await res.json()) as { replies?: any[] };\n for (const r of replies ?? []) this.receiveReply(r);\n } catch {\n // The bridge is gone; the next tick will try again.\n }\n }\n\n private receiveReply(reply: any) {\n if (!reply?.id || !reply.body) return;\n // Both transports deliver, so the same reply can arrive twice. The id is what keeps\n // one reply from appearing as two.\n if (this.chatLog.some((m) => m.id === reply.id)) return;\n this.lastReplyId = reply.id;\n this.chatLog.push({ id: reply.id, at: reply.at ?? new Date().toISOString(), mine: false, body: reply.body });\n // Unread only counts when the person is not looking at the page it lands on.\n if (this.tab !== \"chat\" || this.minimized) {\n this.chatUnread++;\n this.updateChatBadge();\n this.desktopNotify(\"Loupe — the agent replied\", reply.body);\n }\n this.addActivity({ kind: \"agent.reply\", label: \"The agent replied\" });\n this.renderChatLog();\n }\n\n /** A desktop notification, when the browser will show one. Never a prompt for it. */\n private desktopNotify(title: string, body: string) {\n try {\n const N = (globalThis as any).Notification;\n if (!N || N.permission !== \"granted\") return;\n new N(title, { body: String(body).slice(0, 200), tag: \"loupe-companion\" });\n } catch {\n // Notifications are a nicety; a browser that refuses them is not an error.\n }\n }\n\n private buildActivityPanel() {\n this.activityEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-ahint\"></div>` +\n `<div class=\"mon-status\" id=\"loupe-mon-status\">` +\n `<span class=\"mon-dot\"></span><span class=\"mon-status-label\"></span>` +\n `<span class=\"mon-live\" id=\"loupe-mon-live\"></span>` +\n `<span class=\"mon-spacer\"></span>` +\n `<button class=\"mon-clear\" data-role=\"mon-clear\" title=\"Clear the feed\">Clear</button>` +\n `</div>` +\n `<div class=\"mon-summary\" id=\"loupe-mon-summary\"></div>` +\n `<div class=\"mon-micro\" id=\"loupe-mon-micro\"></div>` +\n `<div class=\"mon-chips\" id=\"loupe-mon-chips\"></div>` +\n `<div class=\"mon-feed\" id=\"loupe-mon-feed\"></div>`;\n this.feedEl = this.activityEl.querySelector(\"#loupe-mon-feed\") as HTMLElement;\n this.activityHint = this.activityEl.querySelector(\"#loupe-ahint\") as HTMLElement;\n\n (this.activityEl.querySelector('[data-role=\"mon-clear\"]') as HTMLElement).onclick = () => this.clearActivity();\n // Reading back through the feed stops it jumping to the bottom; scrolling to the\n // end starts following again. That is the \"pause on scroll\" behaviour, without a\n // separate pause button to forget about.\n this.feedEl.addEventListener(\"scroll\", () => {\n const el = this.feedEl;\n this.activityFollow = el.scrollHeight - el.scrollTop - el.clientHeight < 24;\n this.renderActivityChrome();\n });\n\n // Paint anything reported before this panel existed (e.g. by a tab's render()).\n this.renderActivity();\n }\n\n // ---- activity feed --------------------------------------------------------\n\n /** Push one event. Called by Loupe itself and by the public trackActivity(). */\n addActivity(input: ActivityEventInput) {\n const event: ActivityEvent = {\n id: input.id ?? `a${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n at: input.at ?? new Date().toISOString(),\n kind: input.kind,\n label: input.label,\n detail: input.detail,\n level: input.level ?? \"info\",\n files: input.files,\n };\n this.activityEvents.push(event);\n // Cap the ring so a long session cannot grow without bound.\n if (this.activityEvents.length > 500) this.activityEvents = this.activityEvents.slice(-500);\n // A reported error flips the status dot; progress resets it to working.\n this.activityStatus = event.level === \"error\" ? \"error\" : \"working\";\n this.renderActivity();\n }\n\n setActivityStatus(status: ActivityStatus) {\n this.activityStatus = status;\n this.renderActivity();\n }\n\n clearActivity() {\n this.activityEvents = [];\n this.activityFilter = \"\";\n this.activityStatus = \"idle\";\n this.renderActivity();\n }\n\n /**\n * Read the server's feed and merge it in by id. A backend without a feed answers\n * null once, and the panel stops asking.\n */\n private async loadActivity() {\n if (this.activityNone) return;\n let events: ActivityEvent[] | null;\n try {\n const read = this.store.listActivity?.bind(this.store);\n events = read ? await read(this.cfg.projectKey, this.activitySince || undefined) : null;\n } catch {\n if (this.activityRemote === \"live\") {\n this.activityRemote = \"offline\";\n this.renderActivity();\n }\n return;\n }\n if (events === null) {\n // Remember the answer, so neither the poll nor a tab switch asks again.\n this.activityRemote = \"unsupported\";\n this.activityNone = true;\n this.syncActivityPoll();\n this.renderActivity();\n return;\n }\n this.activityRemote = \"live\";\n const known = new Set(this.activityEvents.map((e) => e.id));\n const fresh = events.filter((e) => e && typeof e.id === \"string\" && !known.has(e.id));\n if (fresh.length) {\n this.activityEvents = [...this.activityEvents, ...fresh]\n .sort((a, b) => a.at.localeCompare(b.at))\n .slice(-500);\n const newest = fresh.reduce((m, e) => (e.at > m ? e.at : m), this.activitySince);\n this.activitySince = newest;\n // A recent server-side error is worth the red dot; an old one is history.\n const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString();\n if (fresh.some((e) => e.level === \"error\" && e.at >= tenMinutesAgo)) this.activityStatus = \"error\";\n }\n this.renderActivity();\n }\n\n /** Poll the server's feed every 15s, but only while the Activity view is on screen. */\n private syncActivityPoll() {\n const want = this.tab === \"activity\" && !this.activityNone && !!this.store.listActivity;\n if (want && !this.activityPoll) {\n this.activityPoll = setInterval(() => void this.loadActivity(), 15_000);\n } else if (!want && this.activityPoll) {\n clearInterval(this.activityPoll);\n this.activityPoll = undefined;\n }\n }\n\n /** The summary, status row, micro-stats and chips — derived, never stored. */\n private renderActivityChrome() {\n if (!this.activityEl) return;\n const status = this.activityEl.querySelector(\"#loupe-mon-status\") as HTMLElement | null;\n // A host tab's render() may report events while the panel is still being built,\n // before this markup exists. Those events are kept and painted once it does.\n if (!status) return;\n const s = summarizeActivity(this.activityEvents, this.activityStatus);\n\n status.querySelector(\".mon-status-label\")!.textContent = ACTIVITY_STATUS_LABELS[s.status];\n status.className = `mon-status st-${s.status}`;\n const live = status.querySelector(\"#loupe-mon-live\") as HTMLElement | null;\n if (live) {\n live.textContent = this.activityRemote === \"live\" ? \"Live\" : this.activityRemote === \"offline\" ? \"Offline\" : \"\";\n live.className = `mon-live ${this.activityRemote}`;\n }\n\n const summary = this.activityEl.querySelector(\"#loupe-mon-summary\") as HTMLElement;\n if (!s.events) {\n summary.innerHTML = \"\";\n summary.style.display = \"none\";\n } else {\n summary.style.display = \"\";\n const rows: [string, string][] = [\n [\"Status\", ACTIVITY_STATUS_LABELS[s.status]],\n [\"Events\", String(s.events)],\n [\"Duration\", formatDuration(s.durationMs)],\n [\"Files touched\", String(s.files)],\n [\"Errors\", String(s.errors)],\n [\"Tools\", s.byKind.map((k) => `${k.kind} ×${k.count}`).join(\", \") || \"—\"],\n ];\n summary.innerHTML =\n `<button class=\"mon-sum-head\" data-role=\"mon-toggle\" aria-expanded=\"${this.summaryOpen}\">` +\n `<span class=\"mon-sum-title\">Session summary</span>` +\n `<span class=\"mon-sum-peek\">${s.events} events · ${formatDuration(s.durationMs)} · ${s.files} files</span>` +\n `<span class=\"mon-caret\">${this.summaryOpen ? \"▾\" : \"▸\"}</span></button>` +\n `<div class=\"mon-sum-body\"${this.summaryOpen ? \"\" : ' style=\"display:none\"'}>` +\n rows.map(([k, v]) => `<div class=\"mon-kv\"><span>${escapeHtml(k)}</span><b>${escapeHtml(v)}</b></div>`).join(\"\") +\n `<div class=\"mon-preview\"></div></div>`;\n\n // Last event as the preview line. (`.at(-1)` is ES2022; the SDK targets ES2020.)\n summary.querySelector(\".mon-preview\")!.textContent =\n this.activityEvents[this.activityEvents.length - 1]?.label ?? \"\";\n (summary.querySelector('[data-role=\"mon-toggle\"]') as HTMLElement).onclick = () => {\n this.summaryOpen = !this.summaryOpen;\n this.renderActivityChrome();\n };\n }\n\n const micro = this.activityEl.querySelector(\"#loupe-mon-micro\") as HTMLElement;\n micro.textContent = \"\";\n if (s.events) {\n micro.append(\n el(\"span\", \"mon-micro-i\", `⏱ ${formatDuration(s.durationMs)}`),\n el(\"span\", \"mon-micro-i\", `◦ ${s.events} events`),\n el(\"span\", \"mon-micro-i\", `⧉ ${s.files} files`),\n );\n }\n\n const chips = this.activityEl.querySelector(\"#loupe-mon-chips\") as HTMLElement;\n chips.textContent = \"\";\n if (s.events) {\n const chip = (kind: string, label: string, count: number) => {\n const b = el(\"button\", \"mon-chip\" + (this.activityFilter === kind ? \" on\" : \"\"), `${label} ${count}`);\n b.dataset.kind = kind;\n b.onclick = () => {\n this.activityFilter = this.activityFilter === kind ? \"\" : kind;\n this.renderActivity();\n };\n return b;\n };\n chips.appendChild(chip(\"\", \"All\", s.events));\n for (const { kind, count } of s.byKind) chips.appendChild(chip(kind, kind, count));\n }\n }\n\n /** The feed itself, newest last (so it grows downward like a log). */\n private renderActivity() {\n if (!this.activityEl) return;\n this.renderActivityChrome();\n if (!this.feedEl) return;\n\n const events = this.activityFilter\n ? this.activityEvents.filter((e) => e.kind === this.activityFilter)\n : this.activityEvents;\n\n if (!events.length) {\n this.feedEl.innerHTML =\n `<div class=\"mon-empty\">` +\n (this.activityEvents.length\n ? `Nothing from <b>${escapeHtml(this.activityFilter)}</b> yet.`\n : this.activityRemote === \"live\"\n ? `No activity yet. Comments, status changes and forwarded tickets appear here.`\n : `<b>Monitor unavailable.</b> Nothing is feeding this view yet.<br>` +\n `A bridge or your app can push events with <code>Loupe.trackActivity({ kind, label })</code>, ` +\n `and Loupe reports its own operations here as you work.`) +\n `</div>`;\n return;\n }\n\n this.feedEl.innerHTML = events.map((e) => {\n const time = new Date(e.at).toLocaleTimeString(undefined, { hour12: false });\n return `<div class=\"mon-row lv-${e.level ?? \"info\"}\">` +\n `<span class=\"mon-time\">${escapeHtml(time)}</span>` +\n `<span class=\"mon-kind\">${escapeHtml(e.kind)}</span>` +\n `<span class=\"mon-label\">${escapeHtml(e.label)}` +\n (e.detail ? `<span class=\"mon-detail\">${escapeHtml(e.detail)}</span>` : \"\") +\n `</span></div>`;\n }).join(\"\");\n\n if (this.activityFollow) this.feedEl.scrollTop = this.feedEl.scrollHeight;\n }\n\n /**\n * The Home overview: four stat tiles over the current scope, a scope switch\n * (this page ↔ the whole project), a one-click way into capture, and the\n * most recent feedback. Every tile is a button that narrows the list.\n */\n private buildHomePanel() {\n const title = this.cfg.label ?? \"Loupe\";\n this.homeEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-hhint\"></div>` +\n `<div class=\"hstat\" id=\"loupe-hstats\"></div>` +\n `<div class=\"hscope\">` +\n `<button class=\"hscope-b\" data-scope=\"page\">This page <b class=\"hscope-n\"></b></button>` +\n `<button class=\"hscope-b\" data-scope=\"all\">All <b class=\"hscope-n\"></b></button>` +\n `<button class=\"hrefresh\" title=\"Refresh\" aria-label=\"Refresh\">⟳</button>` +\n `</div>` +\n `<button class=\"hpin\" data-role=\"home-pin\">✛ Pin feedback on this page</button>` +\n `<div class=\"projbar\">` +\n `<span class=\"proj-label\">Project</span>` +\n `<button class=\"proj-chip\" data-role=\"proj-open\" aria-haspopup=\"dialog\" aria-expanded=\"false\">` +\n `<span class=\"proj-name\"></span><span class=\"proj-caret\">▾</span></button>` +\n // The popover lives INSIDE .projbar: absolute positioning resolves against the\n // nearest positioned ancestor, and as a sibling it anchored to the panel\n // instead — landing off the bottom of the view.\n `<div class=\"proj-pop\" id=\"loupe-proj\" role=\"dialog\" aria-label=\"Project settings\"></div>` +\n `</div>` +\n `<div class=\"hnotif\" id=\"loupe-hnotif\"></div>` +\n `<div class=\"hlabel\">Recent</div>` +\n `<div class=\"hfeed\" id=\"loupe-hfeed\"></div>` +\n `<div class=\"hfoot\">${escapeHtml(title)} · <span class=\"hver\">v${escapeHtml(SDK_VERSION)}</span>${this.packageVersionNote()}</div>`;\n\n (this.homeEl.querySelector('[data-role=\"proj-open\"]') as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n this.setProjectOpen(!this.projOpen);\n };\n\n this.homeEl.querySelectorAll<HTMLElement>(\".hscope-b\").forEach((b) => {\n b.onclick = () => this.setScope(b.dataset.scope === \"all\" ? \"all\" : \"page\");\n });\n (this.homeEl.querySelector('[data-role=\"home-pin\"]') as HTMLElement | null)!.onclick = () => {\n this.setTab(\"comments\");\n this.setMode(\"inspect\");\n };\n (this.homeEl.querySelector(\".hrefresh\") as HTMLElement | null)!.onclick = () => {\n void this.reloadComments();\n if (this.scope === \"all\") void this.loadAllComments();\n };\n }\n\n /** The comments the panel is currently looking at (page scope or project scope). */\n private get visibleComments(): Comment[] {\n return this.scope === \"all\" ? this.allComments : this.comments;\n }\n\n /** Switch the panel between \"this page\" and the whole project. */\n private setScope(scope: Scope) {\n this.scope = scope;\n this.saveState();\n // The project scope costs a fetch; do it once, then keep it fresh.\n if (scope === \"all\" && !this.allComments.length) void this.loadAllComments();\n this.renderHome();\n this.renderList();\n }\n\n private async loadAllComments() {\n try {\n this.allComments = await this.store.listAll(this.cfg.projectKey);\n this.allLoaded = true;\n this.renderHome();\n this.renderList();\n } catch { /* keep whatever we have */ }\n }\n\n /**\n * The four buckets a triager actually asks about. \"Stale\" is open work older\n * than a week — the thing that quietly rots on a board.\n */\n private homeStats(): { key: StatFilter; label: string; n: number }[] {\n const list = this.visibleComments;\n const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;\n return [\n { key: \"open\", label: \"Open\", n: list.filter((c) => normalizeStatus(c.status) !== \"resolved\").length },\n // The shared predicate, so the panel and the dashboard cannot disagree about\n // what \"needs you\" means. Only the stage is available here — the reasons that\n // depend on the last message are computed where the messages are loaded.\n { key: \"needs_you\", label: \"Needs you\", n: list.filter((c) => needsYou({ status: c.status }).needs).length },\n { key: \"resolved\", label: \"Resolved\", n: list.filter((c) => normalizeStatus(c.status) === \"resolved\").length },\n {\n key: \"stale\",\n label: \"Stale\",\n n: list.filter((c) => normalizeStatus(c.status) !== \"resolved\" && Date.parse(c.createdAt) < weekAgo).length,\n },\n ];\n }\n\n private renderHome() {\n if (!this.homeEl) return;\n const stats = this.homeStats();\n const statsEl = this.homeEl.querySelector(\"#loupe-hstats\") as HTMLElement | null;\n if (statsEl) {\n statsEl.innerHTML = stats\n .map((s) =>\n `<button class=\"hstat-b${this.statFilter === s.key ? \" on\" : \"\"}\" data-stat=\"${s.key}\">` +\n `<span class=\"hstat-n\">${s.n}</span><span class=\"hstat-l\">${s.label}</span></button>`)\n .join(\"\");\n statsEl.querySelectorAll<HTMLElement>(\".hstat-b\").forEach((b) => {\n b.onclick = () => {\n const key = b.dataset.stat as StatFilter;\n // Clicking the active tile clears the filter.\n this.statFilter = this.statFilter === key ? \"\" : key;\n this.setTab(\"comments\");\n };\n });\n }\n\n // Scope chips carry the counts, so \"All\" is a decision, not a guess. The project\n // total is only known once the project list has been read; until then it shows ⋯\n // rather than a number we would be inventing.\n const allKnown = this.allLoaded || this.scope === \"all\";\n const counts: Record<Scope, string> = {\n page: String(this.comments.length),\n all: allKnown ? String(this.allComments.length) : \"⋯\",\n };\n const labels: Record<Scope, string> = { page: \"This page\", all: \"All\" };\n this.homeEl.querySelectorAll<HTMLElement>(\".hscope-b\").forEach((b) => {\n const scope = (b.dataset.scope === \"all\" ? \"all\" : \"page\") as Scope;\n b.classList.toggle(\"on\", scope === this.scope);\n b.setAttribute(\"aria-pressed\", String(scope === this.scope));\n b.setAttribute(\"aria-label\", `${labels[scope]} — ${counts[scope]} comments`);\n (b.querySelector(\".hscope-n\") as HTMLElement).textContent = counts[scope];\n });\n this.renderProject();\n this.renderNotifications();\n\n const feed = this.homeEl.querySelector(\"#loupe-hfeed\") as HTMLElement | null;\n if (!feed) return;\n const recent = [...this.visibleComments]\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, 8);\n feed.innerHTML = recent.length\n ? recent.map((c) => {\n const stage = STAGE_LABELS[normalizeStatus(c.status)];\n const prio = normalizePriority(c.priority);\n return `<button class=\"hfeed-i\" data-id=\"${escapeAttr(c.id)}\">` +\n `<span class=\"hfeed-t\">${escapeHtml(c.title || (c.body.split(\"\\n\")[0] ?? \"\").slice(0, 60))}</span>` +\n `<span class=\"hfeed-m\">${escapeHtml(c.author?.name ?? \"\")} · <span title=\"${escapeAttr(this.fmtWhen(c.createdAt))}\">${fmtAgo(c.createdAt)}</span> · ` +\n `<span class=\"hfeed-s hfeed-s-${normalizeStatus(c.status)}\">${stage}</span>` +\n `<span class=\"hfeed-p hfeed-p-${prio}\">${PRIORITY_LABELS[prio]}</span></span></button>`;\n }).join(\"\")\n : `<div class=\"hempty\">Nothing here yet.</div>`;\n feed.querySelectorAll<HTMLElement>(\".hfeed-i\").forEach((b) => {\n b.onclick = () => {\n const id = b.dataset.id!;\n this.statFilter = \"\";\n this.setTab(\"comments\");\n this.expanded.add(id);\n this.renderList();\n this.flash(id);\n };\n });\n }\n\n /** In-app notifications: mentions of you, newest first. */\n private notifications: { id: string; threadId: string; body: string; actorName?: string; createdAt: string; readAt?: string }[] = [];\n\n\n private async loadNotifications() {\n try {\n // Guarded at the boundary rather than trusted: an adapter (or a server) that\n // answers with something other than a list must not leave `notifications`\n // undefined and take the whole Home render down with it.\n const list = await this.store.listNotifications(this.cfg.projectKey, this.cfg.user.id);\n this.notifications = Array.isArray(list) ? list : [];\n } catch {\n this.notifications = [];\n }\n this.renderNotifications();\n }\n\n /**\n * The mentions block. Rendered only when there are unread ones — a permanent empty\n * \"0 unread\" is noise, and the whole point is that it appears when it matters.\n */\n private renderNotifications() {\n const box = this.homeEl?.querySelector(\"#loupe-hnotif\") as HTMLElement | null;\n if (!box) return;\n const unread = this.notifications.filter((n) => !n.readAt);\n if (!unread.length) { box.innerHTML = \"\"; box.style.display = \"none\"; return; }\n box.style.display = \"\";\n box.innerHTML =\n `<div class=\"nf-head\"><span class=\"nf-dot\"></span><b>${unread.length}</b> mention${unread.length === 1 ? \"\" : \"s\"} waiting</div>` +\n unread.slice(0, 3).map((n) =>\n `<button class=\"nf-i\" data-thread=\"${escapeAttr(n.threadId)}\">` +\n `<span class=\"nf-b\">${escapeHtml(n.body)}</span>` +\n `<span class=\"nf-w\">${escapeHtml(fmtAgo(n.createdAt))}</span></button>`).join(\"\") +\n `<button class=\"nf-read\">Mark as read</button>`;\n\n box.querySelectorAll<HTMLElement>(\".nf-i\").forEach((b) => {\n b.onclick = () => {\n const id = b.dataset.thread!;\n this.scope = \"all\";\n if (!this.allComments.length) void this.loadAllComments();\n this.statFilter = \"\";\n this.setTab(\"comments\");\n this.expanded.add(id);\n this.renderList();\n this.flash(id);\n };\n });\n (box.querySelector(\".nf-read\") as HTMLElement).onclick = async () => {\n try {\n await this.store.markNotificationsRead(this.cfg.projectKey, this.cfg.user.id);\n } catch { /* the badge will clear on the next load if this failed */ }\n void this.loadNotifications();\n };\n }\n\n // ---- project manager (#60) ------------------------------------------------\n\n private setProjectOpen(open: boolean) {\n this.projOpen = open;\n this.projError = \"\";\n this.renderProject();\n }\n\n /** Read the organization once. A backend without the endpoint, or offline mode, leaves it null. */\n private async loadOrg() {\n try {\n this.org = (await this.store.getOrg?.()) ?? null;\n } catch {\n this.org = null;\n }\n this.renderProject();\n }\n\n /** \"Project · Organization\", or the project key when there is no organization to show. */\n private projectLabel(): string {\n const org = this.org;\n const name = org?.project.name || this.cfg.projectKey;\n return org?.organization ? `${name} · ${org.organization.name}` : name;\n }\n\n /** The Organization section of the project popover. Read-only: Hub owns this. */\n private orgSectionHtml(): string {\n const org = this.org;\n const head = `<div class=\"pp-head\"><span>Organization</span><button class=\"pp-x\" data-role=\"pp-close\" aria-label=\"Close\">✕</button></div>`;\n if (!org?.organization) {\n return head + `<div class=\"pp-cur\">` + (org?.error\n ? \"Could not reach Loupe Hub. Your organization's projects will show here when it is back.\"\n : \"This project is not connected to an organization. Connect it to Loupe Hub to see the \" +\n \"organization's projects and where its tickets go.\") + `</div>`;\n }\n const dest = org.project.destination;\n const others = org.projects;\n return head +\n `<div class=\"pp-cur\"><b>${escapeHtml(org.project.name || this.cfg.projectKey)}</b> in ` +\n `<b>${escapeHtml(org.organization.name)}</b>.</div>` +\n `<div class=\"pp-cur pp-dest\">${dest\n ? `Tickets go to <b>${escapeHtml(dest.name)}</b>.`\n : \"Tickets stay in this project.\"}</div>` +\n `<div class=\"pp-list pp-org\">` + (others.length\n ? others.map((p) =>\n `<div class=\"pp-proj${p.isDestination ? \" on\" : \"\"}\"><span class=\"pp-proj-n\">${escapeHtml(p.name)}</span>` +\n (p.receives ? `<span class=\"pp-badge\">receives tickets</span>` : \"\") + `</div>`).join(\"\")\n : `<div class=\"pp-empty\">No other projects in this organization yet.</div>`) + `</div>`;\n }\n\n private renderProjectError() {\n const box = this.homeEl?.querySelector(\"#loupe-pp-err\") as HTMLElement | null;\n if (!box) return;\n box.textContent = this.projError;\n box.style.display = this.projError ? \"\" : \"none\";\n }\n\n private renderProject() {\n if (!this.homeEl) return;\n const chip = this.homeEl.querySelector(\".proj-chip\") as HTMLElement | null;\n const pop = this.homeEl.querySelector(\"#loupe-proj\") as HTMLElement | null;\n if (!chip || !pop) return;\n (chip.querySelector(\".proj-name\") as HTMLElement).textContent = this.projectLabel();\n chip.classList.toggle(\"unset\", !this.org?.organization);\n chip.setAttribute(\"aria-expanded\", String(this.projOpen));\n\n if (!this.projOpen) { pop.classList.remove(\"open\"); pop.innerHTML = \"\"; return; }\n pop.classList.add(\"open\");\n\n const envs = this.project.environments;\n pop.innerHTML =\n this.orgSectionHtml() +\n `<div class=\"pp-sep\"></div>` +\n `<div class=\"pp-head\"><span>Environments</span></div>` +\n `<div class=\"pp-list\">` + (envs.length\n ? envs.map((u, i) =>\n `<div class=\"pp-env\"><span class=\"pp-env-u\" title=\"${escapeAttr(u)}\">${escapeHtml(u)}</span>` +\n `<button class=\"pp-x\" data-env-rm=\"${i}\" aria-label=\"Remove environment\">✕</button></div>`).join(\"\")\n : `<div class=\"pp-empty\">No environment URLs yet.</div>`) + `</div>` +\n `<div class=\"pp-add\"><input class=\"pp-env-url\" type=\"url\" placeholder=\"https://staging.example.com\" ` +\n `value=\"${escapeAttr(this.envDraft)}\" aria-label=\"Environment URL\">` +\n `<button class=\"pp-add-b\" data-role=\"env-add\">Add</button></div>` +\n `<div class=\"pp-sep\"></div>` +\n `<div class=\"pp-head\"><span>Local AI</span></div>` +\n `<div class=\"pp-empty\">Any OpenAI-compatible server — used by the Generate pane.</div>` +\n `<div class=\"pp-add\"><input class=\"pp-ai-url\" type=\"url\" placeholder=\"http://localhost:11434\" ` +\n `value=\"${escapeAttr(this.project.localAi?.url ?? \"\")}\" aria-label=\"Local AI endpoint\"></div>` +\n `<div class=\"pp-add\"><input class=\"pp-ai-model\" type=\"text\" placeholder=\"llama3.2\" ` +\n `value=\"${escapeAttr(this.project.localAi?.model ?? \"\")}\" aria-label=\"Model name\">` +\n `<button class=\"pp-add-b\" data-role=\"ai-save\">Save</button></div>` +\n `<div class=\"pp-add\"><button class=\"pp-clear\" data-role=\"ai-test\">Test connection</button></div>` +\n `<div class=\"pp-ai-out\" id=\"loupe-pp-ai\"></div>` +\n `<div class=\"pp-err\" id=\"loupe-pp-err\"></div>`;\n\n this.renderProjectError();\n\n (pop.querySelector('[data-role=\"pp-close\"]') as HTMLElement).onclick = () => this.setProjectOpen(false);\n\n pop.querySelectorAll<HTMLElement>(\"[data-env-rm]\").forEach((b) => {\n b.onclick = () => {\n const i = Number(b.dataset.envRm);\n this.project.environments = this.project.environments.filter((_, n) => n !== i);\n this.saveProject();\n this.renderProject();\n };\n });\n\n const url = pop.querySelector(\".pp-env-url\") as HTMLInputElement | null;\n if (url) {\n url.addEventListener(\"click\", (e) => e.stopPropagation());\n url.oninput = () => { this.envDraft = url.value; };\n url.onkeydown = (e) => { if (e.key === \"Enter\") (pop.querySelector('[data-role=\"env-add\"]') as HTMLElement).click(); };\n }\n (pop.querySelector('[data-role=\"env-add\"]') as HTMLElement).onclick = () => {\n const normalized = normalizeEnvUrl(this.envDraft);\n if (!normalized) {\n this.projError = \"Enter a full http:// or https:// URL.\";\n this.renderProjectError();\n return;\n }\n if (this.project.environments.includes(normalized)) {\n this.projError = \"That environment is already listed.\";\n this.renderProjectError();\n return;\n }\n this.project.environments = [...this.project.environments, normalized];\n this.envDraft = \"\";\n this.projError = \"\";\n this.saveProject();\n this.renderProject();\n (pop.querySelector(\".pp-env-url\") as HTMLInputElement | null)?.focus();\n };\n\n // Local AI: saved per browser, and checked against the real endpoint.\n for (const sel of [\".pp-ai-url\", \".pp-ai-model\"]) {\n pop.querySelector(sel)?.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n (pop.querySelector('[data-role=\"ai-save\"]') as HTMLElement).onclick = () => {\n const url = normalizeEnvUrl((pop.querySelector(\".pp-ai-url\") as HTMLInputElement).value);\n const model = (pop.querySelector(\".pp-ai-model\") as HTMLInputElement).value.trim();\n if (!url || !model) {\n this.setLocalAiStatus(this.project.localAi\n ? `Saved: ${this.project.localAi.model} at ${this.project.localAi.url}`\n : \"Nothing saved yet.\");\n this.projError = !url ? \"Enter a full http:// or https:// endpoint URL.\" : \"Enter a model name.\";\n this.renderProjectError();\n return;\n }\n this.projError = \"\";\n this.setLocalAi({ url, model });\n this.setLocalAiStatus(`Saved: ${model} at ${url}`);\n };\n (pop.querySelector('[data-role=\"ai-test\"]') as HTMLElement).onclick = () => {\n void this.testLocalAi(pop);\n };\n }\n\n /** Per-browser project settings, keyed separately from the dock's UI state. */\n private loadProject() {\n const fromConfig = (this.cfg.environments ?? []).filter((u): u is string => typeof u === \"string\");\n try {\n const raw = localStorage.getItem(`loupe:project:${this.cfg.projectKey}`);\n // A `repo` stored by an older version is ignored; repo linking is gone.\n const p = raw ? JSON.parse(raw) : null;\n const stored = Array.isArray(p?.environments)\n ? (p.environments as unknown[]).filter((u): u is string => typeof u === \"string\")\n : null;\n const localAi = p?.localAi && typeof p.localAi.url === \"string\" && typeof p.localAi.model === \"string\"\n ? { url: p.localAi.url as string, model: p.localAi.model as string }\n : undefined;\n this.project = { environments: stored ?? fromConfig, localAi };\n } catch {\n this.project = { environments: fromConfig };\n }\n }\n\n private saveProject() {\n try {\n localStorage.setItem(`loupe:project:${this.cfg.projectKey}`, JSON.stringify(this.project));\n } catch { /* storage unavailable */ }\n }\n\n /** The \"INTEGRATES WITH\" footer on the Comments page (visual only for now). */\n private buildIntegrations(): HTMLElement {\n const wrap = el(\"div\", \"integrations\");\n wrap.append(el(\"div\", \"ilabel\", \"INTEGRATES WITH\"));\n const row = el(\"div\", \"irow\");\n const icons: [string, string][] = [\n [\"GitHub\", I_GITHUB],\n [\"Slack\", I_SLACK],\n [\"Telegram\", I_TELEGRAM],\n [\"Linear\", I_LINEAR],\n ];\n for (const [name, icon] of icons) {\n const b = el(\"span\", \"ibtn\");\n b.title = `${name} — connect (coming soon)`;\n b.setAttribute(\"aria-label\", name);\n b.innerHTML = icon;\n row.appendChild(b);\n }\n wrap.appendChild(row);\n return wrap;\n }\n\n /** The floating \"recording…\" pill with a Stop button (shown only while recording). */\n private buildRecBar(): HTMLElement {\n const bar = el(\"button\", \"recbar\") as HTMLButtonElement;\n bar.title = \"Stop recording\";\n bar.setAttribute(\"aria-label\", \"Stop recording\");\n bar.onclick = () => this.stopRecording?.();\n return bar;\n }\n\n /**\n * The collapsed-state FAB cluster. The primary brand button carries the comment\n * count and OPENS the panel — one tap, the thing most people came for. A drag on\n * it moves the whole cluster anywhere on screen (persisted). The chevron beside it\n * is its own button and toggles the quick actions: pin a comment, drop a note,\n * hide/show the markers already on the page, hide the launcher itself, and — when\n * the host registered one — jump straight to the Connect tab.\n */\n private buildFabCluster(): HTMLElement {\n const cluster = el(\"div\", \"fab-cluster\");\n\n const minis = el(\"div\", \"fab-minis\");\n const mini = (role: string, icon: string, label: string, title: string) => {\n const b = el(\"button\", \"fab-mini\") as HTMLButtonElement;\n b.dataset.fab = role;\n b.title = title;\n b.setAttribute(\"aria-label\", title);\n b.innerHTML = `${icon}<span class=\"fab-tip\">${label}</span>`;\n return b;\n };\n const comment = mini(\"comment\", I_COMMENT, \"Pin comment\", \"Pin feedback on any element\");\n comment.onclick = () => { this.collapseFab(); this.openDock(); this.setMode(\"inspect\"); };\n const note = mini(\"note\", I_NOTE, \"Note\", \"Drop a note anywhere on the page\");\n note.onclick = () => { this.collapseFab(); this.openDock(); this.setMode(\"free\"); };\n const markers = mini(\"markers\", I_EYE, \"Markers\", \"Show or hide the markers on this page\");\n markers.onclick = () => this.toggleMarkers();\n const hide = mini(\"hide\", I_EYE_OFF, \"Hide launcher\",\n isTouchDevice() ? \"Hide this launcher — the tab at the screen edge brings it back\" : `Hide this launcher — ${LAUNCHER_SHORTCUT} brings it back`);\n hide.onclick = () => this.setLauncherHidden(true);\n minis.append(comment, note, markers, hide);\n // The Connect shortcut only exists when a \"connect\" tab is registered — the\n // panel no longer ships one, so it is opt-in via connectTab().\n if (this.tabList.some((t) => t.id === \"connect\")) {\n const connect = mini(\"connect\", I_PLUG, \"Connect Claude\", \"Set up the Claude/MCP connection\");\n connect.onclick = () => { this.collapseFab(); this.openDock(); this.setTab(\"connect\"); };\n minis.appendChild(connect);\n }\n\n const label = this.cfg.label ?? \"Loupe\";\n const primary = el(\"button\", \"launcher\") as HTMLButtonElement;\n primary.title = `Open ${label} — drag to move`;\n primary.setAttribute(\"aria-label\", `Open ${label}`);\n primary.innerHTML = `<span class=\"logo\">◎</span><span class=\"lcount\"></span>`;\n this.fabBadge = primary.querySelector(\".lcount\") as HTMLElement;\n // A tap opens the panel; a drag moves the launcher. Distance tells them apart, so\n // a shaky tap still opens and a real drag never opens by accident.\n primary.onclick = () => { if (this.fabSuppressClick) return; this.openDock(); };\n primary.addEventListener(\"pointerdown\", this.onFabPointerDown);\n primary.addEventListener(\"pointermove\", this.onFabPointerMove);\n primary.addEventListener(\"pointerup\", this.onFabPointerUp);\n primary.addEventListener(\"pointercancel\", this.onFabPointerUp);\n\n // The chevron is a separate button so the quick actions stay one tap away without\n // costing the primary tap, which now opens the panel.\n const more = el(\"button\", \"fab-more\") as HTMLButtonElement;\n more.dataset.fab = \"more\";\n more.title = \"Quick actions\";\n more.setAttribute(\"aria-label\", \"Quick actions\");\n more.setAttribute(\"aria-expanded\", \"false\");\n more.innerHTML = I_FAB_CHEVRON;\n more.onclick = (e) => { e.stopPropagation(); this.toggleFab(); };\n\n const main = el(\"div\", \"fab-main\");\n main.append(primary, more);\n cluster.append(minis, main);\n this.fabMinis = minis;\n return cluster;\n }\n\n /** Expand/collapse the quick actions out of the primary FAB. */\n private toggleFab() {\n this.fabExpanded = !this.fabExpanded;\n this.applyFab();\n }\n\n // ---- launcher: drag anywhere, hide, bring back ------------------------------\n\n private onFabPointerDown = (e: PointerEvent) => {\n if (e.pointerType === \"mouse\" && e.button !== 0) return;\n const target = e.currentTarget as HTMLElement;\n const r = target.getBoundingClientRect();\n this.fabDrag = { px: e.clientX, py: e.clientY, ox: r.left, oy: r.top, moved: false };\n // Capture the pointer so a fast drag that leaves the button keeps reporting to the\n // button's own listeners. Without capture support, follow the pointer on window.\n let captured = false;\n try {\n if (typeof target.setPointerCapture === \"function\") { target.setPointerCapture(e.pointerId); captured = true; }\n } catch { captured = false; /* pointer already up — a tap */ }\n if (!captured) {\n window.addEventListener(\"pointermove\", this.onFabPointerMove);\n window.addEventListener(\"pointerup\", this.onFabPointerUp);\n window.addEventListener(\"pointercancel\", this.onFabPointerUp);\n }\n };\n\n private onFabPointerMove = (e: PointerEvent) => {\n const d = this.fabDrag;\n if (!d) return;\n const dx = e.clientX - d.px, dy = e.clientY - d.py;\n if (!d.moved && Math.hypot(dx, dy) < FAB_DRAG_THRESHOLD) return;\n if (!d.moved) {\n d.moved = true;\n this.fabCluster.classList.add(\"dragging\");\n this.collapseFab();\n }\n e.preventDefault();\n this.fabPos = this.clampFabPos(d.ox + dx, d.oy + dy);\n this.applyFabPosition();\n };\n\n private onFabPointerUp = () => {\n window.removeEventListener(\"pointermove\", this.onFabPointerMove);\n window.removeEventListener(\"pointerup\", this.onFabPointerUp);\n window.removeEventListener(\"pointercancel\", this.onFabPointerUp);\n const d = this.fabDrag;\n this.fabDrag = null;\n if (!d?.moved) return;\n this.fabCluster.classList.remove(\"dragging\");\n this.saveState();\n this.renderSettings();\n // The browser fires a click right after this pointerup; that one must not open the panel.\n this.fabSuppressClick = true;\n window.setTimeout(() => { this.fabSuppressClick = false; }, 0);\n };\n\n /** Keep the launcher fully on screen, with a small margin so it never kisses the edge. */\n private clampFabPos(x: number, y: number): { x: number; y: number } {\n const m = 8;\n return {\n x: clampPx(Math.round(x), m, Math.max(m, window.innerWidth - FAB_SIZE - m)),\n y: clampPx(Math.round(y), m, Math.max(m, window.innerHeight - FAB_SIZE - m)),\n };\n }\n\n /**\n * Place the cluster. A dragged launcher is anchored to the viewport edge it is\n * nearest, so the quick actions always grow INTO the page: minis open upward from\n * the lower half and downward from the upper half, and their labels point away\n * from the nearest side. With no saved position the cluster sits in the default\n * corner on the dock's side, so reopening feels like the panel sliding back in.\n */\n private applyFabPosition() {\n const s = this.fabCluster.style;\n if (this.fabPos) {\n const { x, y } = this.clampFabPos(this.fabPos.x, this.fabPos.y);\n const atTop = y + FAB_SIZE / 2 < window.innerHeight / 2;\n const atLeft = x + FAB_SIZE / 2 < window.innerWidth / 2;\n s.left = atLeft ? `${x}px` : \"auto\";\n s.right = atLeft ? \"auto\" : `${Math.max(0, window.innerWidth - x - FAB_SIZE)}px`;\n s.top = atTop ? `${y}px` : \"auto\";\n s.bottom = atTop ? \"auto\" : `${Math.max(0, window.innerHeight - y - FAB_SIZE)}px`;\n this.fabCluster.classList.toggle(\"at-top\", atTop);\n this.fabCluster.classList.toggle(\"at-left\", atLeft);\n return;\n }\n const leftSide = this.dockMode === \"left\";\n s.left = leftSide ? \"20px\" : \"auto\";\n s.right = leftSide ? \"auto\" : \"20px\";\n s.top = \"auto\";\n s.bottom = \"\"; // the stylesheet's corner offset (20px, 16px on phones)\n this.fabCluster.classList.remove(\"at-top\");\n this.fabCluster.classList.toggle(\"at-left\", leftSide);\n }\n\n private resetLauncherPosition() {\n this.fabPos = null;\n this.saveState();\n this.applyDockLayout();\n this.renderSettings();\n }\n\n /**\n * Hide or show the collapsed launcher. Hidden is persisted, and the way back is\n * announced at the moment of hiding — a control that vanishes with no stated way\n * to return is a support ticket, not a feature.\n */\n private setLauncherHidden(hidden: boolean) {\n if (this.launcherHidden === hidden) return;\n this.launcherHidden = hidden;\n this.fabExpanded = false;\n this.saveState();\n this.applyDockLayout();\n this.renderSettings();\n const label = this.cfg.label ?? \"Loupe\";\n const back = isTouchDevice() ? \"tap the tab at the right edge of the screen\" : `press <kbd>${LAUNCHER_SHORTCUT}</kbd>`;\n this.toast(hidden\n ? `${escapeHtml(label)} launcher hidden — ${back} to bring it back`\n : `${escapeHtml(label)} launcher is back`);\n }\n\n /** Public seam for the host (`Loupe.showLauncher()`). */\n showLauncher() { this.setLauncherHidden(false); }\n\n /** Public seam for the host (`Loupe.hideLauncher()`). */\n hideLauncher() { this.setLauncherHidden(true); }\n\n /** A short notice at the bottom of the viewport. `html` is trusted markup built by the caller. */\n private toast(html: string, ms = 6000) {\n this.toastEl.innerHTML = html;\n this.toastEl.classList.add(\"show\");\n window.clearTimeout(this.toastTimer);\n this.toastTimer = window.setTimeout(() => this.toastEl.classList.remove(\"show\"), ms);\n }\n\n private collapseFab() {\n if (!this.fabExpanded) return;\n this.fabExpanded = false;\n this.applyFab();\n }\n\n /** Hide/show every pin on the page without losing them (persisted). */\n private toggleMarkers() {\n this.markersHidden = !this.markersHidden;\n this.saveState();\n this.applyFab();\n }\n\n /** Reflect cluster expansion + marker visibility into the DOM. */\n private applyFab() {\n this.fabCluster.classList.toggle(\"expanded\", this.fabExpanded);\n const more = this.fabCluster.querySelector('[data-fab=\"more\"]') as HTMLElement | null;\n more?.setAttribute(\"aria-expanded\", String(this.fabExpanded));\n more?.setAttribute(\"aria-label\", this.fabExpanded ? \"Close quick actions\" : \"Quick actions\");\n const markers = this.fabCluster.querySelector('[data-fab=\"markers\"]') as HTMLElement | null;\n markers?.classList.toggle(\"on\", this.markersHidden);\n markers?.setAttribute(\"aria-pressed\", String(this.markersHidden));\n // !important in CSS so it beats the inline display set by position().\n this.overlay.classList.toggle(\"hide-pins\", this.markersHidden);\n }\n\n /** A tool button with a uniform icon + label layout. `icon` may be an SVG string. */\n private toolBtn(icon: string, label: string, role: string): HTMLButtonElement {\n const b = el(\"button\") as HTMLButtonElement;\n b.dataset.role = role;\n b.setAttribute(\"aria-label\", label);\n b.innerHTML = `<span class=\"ico\">${icon}</span><span class=\"label\">${label}</span>`;\n return b;\n }\n\n // ---- inspector ------------------------------------------------------------\n\n // Pointer Events, not mouse events: a touch drag on a phone never fires\n // mousemove/mouseup, so Region/Record selection was impossible on touch devices.\n // Pointer events cover mouse, touch and pen with one handler each.\n\n private onMove = (e: PointerEvent) => {\n if (this.mode !== \"inspect\") return;\n const target = this.pick(e.clientX, e.clientY);\n if (!target) { this.hl.style.display = \"none\"; return; }\n const r = target.getBoundingClientRect();\n Object.assign(this.hl.style, {\n display: \"block\", left: r.left + \"px\", top: r.top + \"px\",\n width: r.width + \"px\", height: r.height + \"px\",\n });\n (this.hl.firstChild as HTMLElement).textContent =\n target.tagName.toLowerCase() + (target.id ? \"#\" + target.id : \"\");\n };\n\n private onClick = (e: MouseEvent) => {\n if (this.mode !== \"inspect\") return;\n const target = this.pick(e.clientX, e.clientY);\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n const r = target.getBoundingClientRect();\n this.targetOffset = {\n x: r.width ? clamp((e.clientX - r.left) / r.width) : 0.5,\n y: r.height ? clamp((e.clientY - r.top) / r.height) : 0.5,\n };\n this.setMode(\"off\");\n this.openComposer({ kind: \"element\", element: target }, e.clientX, e.clientY);\n };\n\n private onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") { this.cancelDrag(); this.setMode(\"off\"); this.closeComposer(); }\n };\n\n /**\n * Alt+Shift+L toggles the launcher — the way back once it has been hidden, so it is\n * listened for the whole time the widget is mounted (unlike Escape, which only\n * matters while a tool is armed). `code` is checked too: on some keyboard layouts\n * Alt+Shift+L yields a different `key`.\n */\n private onLauncherKey = (e: KeyboardEvent) => {\n if (!e.altKey || !e.shiftKey || e.ctrlKey || e.metaKey) return;\n if (e.code !== \"KeyL\" && (e.key ?? \"\").toLowerCase() !== \"l\") return;\n e.preventDefault();\n this.setLauncherHidden(!this.launcherHidden);\n };\n\n /**\n * The header popovers (position, settings) close on a click anywhere. The shadow-root\n * click listener in buildDom() only sees clicks inside the widget, so a click on the\n * host page used to leave the menu open over it. Capture phase, so a host that stops\n * propagation on its own controls still dismisses the menu.\n */\n private onDocumentClick = (e: MouseEvent) => {\n if (e.composedPath().includes(this.root)) return; // inside the widget: buildDom()'s listener decides\n this.closeMenus();\n };\n\n /** Escape closes an open popover, whether or not a tool is armed (onKey covers tools). */\n private onMenuKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") this.closeMenus();\n };\n\n // ---- region (\"free-size screenshot\") selection ----------------------------\n\n private onRegionDown = (e: PointerEvent) => {\n if (this.mode !== \"region\" && this.mode !== \"record\") return;\n // A mouse must use the primary button; touch/pen always start with button 0.\n if (e.pointerType !== \"touch\" && e.pointerType !== \"pen\" && e.button !== 0) return;\n // Ignore drags that start on our own UI (the panel overlays the page).\n const t = e.target as Element | null;\n if (t && (t.id === \"loupe-root\" || t.closest?.(\"#loupe-root\"))) return;\n e.preventDefault();\n e.stopPropagation();\n this.dragStart = { x: e.clientX, y: e.clientY };\n document.addEventListener(\"pointermove\", this.onRegionMove, true);\n document.addEventListener(\"pointerup\", this.onRegionUp, true);\n document.addEventListener(\"pointercancel\", this.onRegionCancel, true);\n this.drawSelection(e.clientX, e.clientY);\n };\n\n private onRegionMove = (e: PointerEvent) => {\n if (!this.dragStart) return;\n e.preventDefault();\n this.drawSelection(e.clientX, e.clientY);\n };\n\n private onRegionUp = (e: PointerEvent) => {\n if (!this.dragStart) return;\n e.preventDefault();\n e.stopPropagation();\n const start = this.dragStart;\n const wasRecord = this.mode === \"record\";\n this.cancelDrag();\n const vp: RegionRect = {\n x: Math.min(start.x, e.clientX), y: Math.min(start.y, e.clientY),\n w: Math.abs(e.clientX - start.x), h: Math.abs(e.clientY - start.y),\n };\n if (vp.w < 8 || vp.h < 8) { this.selbox.style.display = \"none\"; return; } // stray tap\n this.setMode(\"off\");\n if (wasRecord) void this.finishRecording(vp);\n else this.finishRegion(vp);\n };\n\n /** The OS took over the gesture (e.g. a system swipe): drop the selection. */\n private onRegionCancel = () => {\n this.cancelDrag();\n this.selbox.style.display = \"none\";\n };\n\n private drawSelection(curX: number, curY: number) {\n const s = this.dragStart!;\n Object.assign(this.selbox.style, {\n display: \"block\",\n left: Math.min(s.x, curX) + \"px\", top: Math.min(s.y, curY) + \"px\",\n width: Math.abs(curX - s.x) + \"px\", height: Math.abs(curY - s.y) + \"px\",\n });\n }\n\n private cancelDrag() {\n this.dragStart = null;\n document.removeEventListener(\"pointermove\", this.onRegionMove, true);\n document.removeEventListener(\"pointerup\", this.onRegionUp, true);\n document.removeEventListener(\"pointercancel\", this.onRegionCancel, true);\n }\n\n /**\n * Anchor a dragged viewport rect to the smallest element that covers most of it, so it\n * survives reflow. The rule used to take the element under the region's CENTER, which\n * for a large region is some small control inside it: the stored fractions then ran to\n * −7 and +15, and on any other viewport the pin landed far from the area. `rel`\n * (element-relative fractions) is preferred when an anchor is found; document coords\n * are the fallback. Shared by both the Region (screenshot) and Record (video) tools.\n */\n private regionFromViewport(vp: RegionRect): { region: RegionRect; element: Element | null } {\n const centerEl = this.pick(vp.x + vp.w / 2, vp.y + vp.h / 2);\n const anchorEl = regionContainer(centerEl, vp);\n let rel: RegionRect[\"rel\"];\n if (anchorEl) {\n const er = anchorEl.getBoundingClientRect();\n rel = {\n fx: (vp.x - er.left) / er.width, fy: (vp.y - er.top) / er.height,\n fw: vp.w / er.width, fh: vp.h / er.height,\n };\n }\n const region: RegionRect = { x: vp.x + window.scrollX, y: vp.y + window.scrollY, w: vp.w, h: vp.h, rel };\n return { region, element: anchorEl };\n }\n\n /**\n * Touch path for the Region tool: capture what is on screen right now and open the\n * composer with it already attached. The reporter scrolls to the part of the page they\n * mean FIRST, then taps Region — no drag, so nothing fights the page scroll.\n */\n private async captureViewportForComposer() {\n const vp: RegionRect = { x: 0, y: 0, w: window.innerWidth, h: window.innerHeight };\n const capture = this.cfg.captureRegion ?? captureRegionScreenshot;\n let shot: string | undefined;\n try {\n shot = await capture(vp);\n } catch {\n shot = undefined;\n }\n const file = shot ? dataUrlToFile(shot, \"screenshot.png\") : null;\n const docX = window.scrollX + vp.w / 2;\n const docY = window.scrollY + vp.h / 2;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.setMode(\"off\");\n this.openComposer(\n { kind: \"free\", offset, point: { x: docX, y: docY }, label: \"Screenshot · attached\" },\n 8,\n window.innerHeight / 2,\n file ? [file] : []\n );\n }\n\n /**\n * Attach a video on a phone, where the page cannot record the screen: the reporter\n * records it with the phone's own screen recorder first, then picks the clip here. No\n * `capture` attribute on purpose — that would force the camera open, and a video of the\n * room is not a screen recording.\n */\n private pickVideo() {\n this.setMode(\"off\");\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"video/*\";\n input.style.display = \"none\";\n input.onchange = () => {\n const file = input.files?.[0];\n input.remove();\n if (!file) return;\n const docX = window.scrollX + window.innerWidth / 2;\n const docY = window.scrollY + window.innerHeight / 2;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.openComposer(\n { kind: \"free\", offset, point: { x: docX, y: docY }, label: \"Video · attached\" },\n 8,\n window.innerHeight / 2,\n [file]\n );\n };\n // In the shadow root: keeps the host page's DOM untouched.\n this.shadow.appendChild(input);\n input.click();\n }\n\n /** Capture the selected viewport rect, then open the composer for a region comment. */\n private async finishRegion(vp: RegionRect) {\n this.selbox.style.display = \"none\";\n const { region, element } = this.regionFromViewport(vp);\n const target: ComposeTarget = { kind: \"region\", region, element };\n // Open the composer immediately; capture the screenshot in the background so a\n // slow capture never blocks the UI. It attaches to the comment on submit.\n this.openComposer(target, vp.x + vp.w, vp.y);\n const capture = this.cfg.captureRegion ?? captureRegionScreenshot;\n this.pendingShot = capture(vp);\n void this.pendingShot.then((shot) => {\n if (shot && this.pending === target) target.screenshot = shot;\n }).catch(() => undefined);\n }\n\n /**\n * Record a screen video of the selected rect (same drag-select as Region), then\n * open the composer with the recording attached. Unlike the screenshot flow this\n * is interactive — the browser share prompt and a Stop button drive it — so the\n * composer opens only once recording has finished.\n */\n private async finishRecording(vp: RegionRect) {\n this.selbox.style.display = \"none\";\n const { region, element } = this.regionFromViewport(vp);\n const capture = this.cfg.captureRecording ?? captureRegionRecording;\n this.showRecBar();\n let recording: string | undefined;\n try {\n // Call the capture synchronously (getDisplayMedia needs the click gesture).\n recording = await capture(vp, {\n maxMs: RECORD_MAX_MS,\n register: (stop) => { this.stopRecording = stop; },\n });\n } catch {\n recording = undefined;\n }\n this.hideRecBar();\n if (!recording) return; // user cancelled the share prompt or capture failed\n const target: ComposeTarget = { kind: \"region\", region, element, recording };\n const x = Math.min(vp.x + vp.w, window.innerWidth - 320);\n this.openComposer(target, x, vp.y);\n }\n\n private showRecBar() {\n this.stopRecording = undefined;\n this.recBar.innerHTML = `<span class=\"recdot\"></span><span>Recording… <b>Stop</b></span>`;\n this.recBar.classList.add(\"show\");\n }\n private hideRecBar() {\n this.recBar.classList.remove(\"show\");\n this.stopRecording = undefined;\n }\n\n /** elementFromPoint, ignoring our own UI. */\n private pick(x: number, y: number): Element | null {\n const hitHl = this.hl.style.display;\n this.hl.style.display = \"none\"; // never let the highlight itself be the hit\n const elAt = document.elementFromPoint(x, y);\n this.hl.style.display = hitHl;\n if (!elAt) return null;\n if (elAt.id === \"loupe-root\" || (elAt as Element).closest?.(\"#loupe-root\")) return null;\n return elAt;\n }\n\n private setMode(mode: Mode) {\n // Tools live on the Comments page — entering a mode implies the panel is open there.\n if (mode !== \"off\") {\n if (!this.open) this.open = true;\n if (this.tab !== \"comments\") { this.tab = \"comments\"; this.saveState(); }\n this.applyDockLayout();\n }\n this.mode = mode;\n this.hl.style.display = \"none\";\n this.selbox.style.display = \"none\";\n this.cancelDrag();\n document.body.style.cursor = mode === \"off\" ? \"\" : \"crosshair\";\n (this.dock.querySelector('[data-role=\"inspect\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"inspect\");\n (this.dock.querySelector('[data-role=\"free\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"free\");\n (this.dock.querySelector('[data-role=\"region\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"region\");\n (this.dock.querySelector('[data-role=\"record\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"record\");\n // On mobile this shrinks the bottom sheet to just header + tools (see styles)\n // so most of the page stays visible while picking an element/region.\n this.dock.classList.toggle(\"inspecting\", mode !== \"off\");\n\n document.removeEventListener(\"pointermove\", this.onMove, true);\n document.removeEventListener(\"pointerdown\", this.onMove, true);\n document.removeEventListener(\"click\", this.onClick, true);\n document.removeEventListener(\"click\", this.onFreeClick, true);\n document.removeEventListener(\"pointerdown\", this.onRegionDown, true);\n\n if (mode === \"off\") return;\n document.addEventListener(\"keydown\", this.onKey, true);\n this.closeComposer();\n if (mode === \"inspect\") {\n document.addEventListener(\"pointermove\", this.onMove, true);\n // Touch has no hover: highlight on finger-down so the user can see what a tap\n // will select before lifting (the tap itself still arrives as a click).\n document.addEventListener(\"pointerdown\", this.onMove, true);\n document.addEventListener(\"click\", this.onClick, true);\n } else if (mode === \"free\") {\n document.addEventListener(\"click\", this.onFreeClick, true);\n } else if (mode === \"region\" && isTouchDevice()) {\n // No drag-select on touch — a finger covers the area it is drawing, and the drag\n // fights the page scroll. Grab the visible viewport instead (the reporter scrolls\n // to what they mean first, then taps Region) and hand it to the composer.\n void this.captureViewportForComposer();\n } else if (mode === \"record\" && isTouchDevice()) {\n // Same one-tap idea for video: nothing to drag with a finger, so record the whole\n // screen. Called synchronously from the tap — getDisplayMedia needs that gesture.\n const vp: RegionRect = { x: 0, y: 0, w: window.innerWidth, h: window.innerHeight };\n this.setMode(\"off\");\n void this.finishRecording(vp);\n } else if (mode === \"region\" || mode === \"record\") {\n document.addEventListener(\"pointerdown\", this.onRegionDown, true);\n }\n }\n\n // ---- free note (drop a comment anywhere, no element / no screenshot) -------\n\n private onFreeClick = (e: MouseEvent) => {\n if (this.mode !== \"free\") return;\n const t = e.target as Element | null;\n if (t && (t.id === \"loupe-root\" || t.closest?.(\"#loupe-root\"))) return; // ignore our own UI\n e.preventDefault();\n e.stopPropagation();\n const docX = e.clientX + window.scrollX;\n const docY = e.clientY + window.scrollY;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n // Store the drop point as a fraction of the document so it survives reloads\n // and reasonable reflow without needing any element anchor.\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.setMode(\"off\");\n this.openComposer({ kind: \"free\", offset, point: { x: docX, y: docY } }, e.clientX, e.clientY);\n };\n\n // ---- composer -------------------------------------------------------------\n\n private openComposer(target: ComposeTarget, x: number, y: number, seedFiles: File[] = []) {\n this.pending = target;\n const isRecording = target.kind === \"region\" && !!target.recording;\n const c = this.composer;\n c.innerHTML = \"\";\n const label = el(\"div\", \"target\",\n target.kind === \"element\" ? describe(target.element)\n : target.kind === \"region\"\n ? (isRecording\n ? `⏺ Recording · ${Math.round(target.region.w)}×${Math.round(target.region.h)} px`\n : `Region · ${Math.round(target.region.w)}×${Math.round(target.region.h)} px`)\n : target.label ?? \"Free note · anywhere on the page\");\n const title = el(\"input\", \"title\") as HTMLInputElement;\n title.type = \"text\";\n title.placeholder = \"Title — one line: what's wrong, or what you need\";\n\n const ta = el(\"textarea\") as HTMLTextAreaElement;\n ta.placeholder = isRecording ? \"Describe the issue in this recording…\"\n : target.kind === \"region\" ? \"Describe the issue in this area…\"\n : target.kind === \"free\" ? \"Describe this note…\"\n : \"Describe what should change here…\";\n\n // Attachments: images and/or videos, several of each. A touch screenshot capture is\n // seeded here so it needs no extra tap to attach.\n const files: File[] = seedFiles.slice();\n const attach = el(\"div\", \"attach\");\n const pick = el(\"button\", \"pick\", \"+ Attach images / videos\") as HTMLButtonElement;\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*,video/*\";\n input.multiple = true;\n input.style.display = \"none\";\n const chips = el(\"div\", \"chips\");\n const err = el(\"div\", \"err\");\n const drawChips = () => {\n chips.innerHTML = \"\";\n files.forEach((f, idx) => {\n const chip = el(\"span\", \"chip\", `${attachmentKind(f.type) === \"video\" ? \"🎬\" : \"🖼\"} ${f.name}`);\n const x = el(\"button\", \"x\", \"×\") as HTMLButtonElement;\n x.onclick = () => { files.splice(idx, 1); drawChips(); };\n chip.appendChild(x);\n chips.appendChild(chip);\n });\n };\n input.onchange = () => {\n err.textContent = \"\";\n for (const f of Array.from(input.files ?? [])) {\n if (files.length >= MAX_FILES) { err.textContent = `Up to ${MAX_FILES} files.`; break; }\n const cap = attachmentKind(f.type) === \"video\" ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES;\n if (f.size > cap) { err.textContent = `${f.name} is too large.`; continue; }\n files.push(f);\n }\n input.value = \"\";\n drawChips();\n };\n pick.onclick = () => input.click();\n attach.append(pick, input, chips, err);\n if (files.length) drawChips();\n\n const row = el(\"div\", \"row\");\n // Triage metadata. Both default sensibly so a reporter can ignore them and\n // still file something the team can find and rank.\n const meta = el(\"div\", \"meta2\");\n const prioSel = document.createElement(\"select\");\n prioSel.className = \"mini\";\n prioSel.title = \"Priority\";\n prioSel.setAttribute(\"aria-label\", \"Priority\");\n for (const p of COMMENT_PRIORITIES) {\n prioSel.append(optionEl(PRIORITY_LABELS[p], p, p === DEFAULT_PRIORITY));\n }\n const typeSel = document.createElement(\"select\");\n typeSel.className = \"mini\";\n typeSel.title = \"Change type\";\n typeSel.setAttribute(\"aria-label\", \"Change type\");\n for (const t of CHANGE_TYPES) {\n typeSel.append(optionEl(CHANGE_TYPE_LABELS[t], t, t === DEFAULT_CHANGE_TYPE));\n }\n meta.append(prioSel, typeSel);\n // Free notes carry nothing; recordings always attach the video — both skip the checkbox.\n let box: HTMLInputElement | null = null;\n if (target.kind !== \"free\" && !isRecording) {\n const chk = el(\"label\", \"chk\") as HTMLLabelElement;\n box = document.createElement(\"input\"); box.type = \"checkbox\";\n // Default to attaching. Element shots are captured on submit; region shots are\n // captured in the background and awaited on submit (see pendingShot).\n box.checked = true;\n chk.append(box, document.createTextNode(\"Attach screenshot\"));\n row.append(chk);\n } else {\n row.style.justifyContent = \"flex-end\";\n }\n const btns = el(\"div\", \"btns\");\n const cancel = el(\"button\", \"ghost\", \"Cancel\") as HTMLButtonElement;\n cancel.onclick = () => this.closeComposer();\n const save = el(\"button\", \"primary\", \"Comment\") as HTMLButtonElement;\n save.disabled = true;\n const sync = () => { save.disabled = !title.value.trim() || !ta.value.trim(); };\n title.oninput = sync;\n ta.oninput = sync;\n sync();\n save.onclick = () => this.submit(\n target, title.value.trim(), ta.value.trim(), box ? box.checked : false, files.slice(),\n prioSel.value as CommentPriority, typeSel.value as ChangeType,\n );\n btns.append(this.voiceButton(ta), cancel, save);\n row.append(btns);\n c.append(label, title, ta, attach, meta, row);\n\n // Position near the click, clamped to the viewport.\n const w = 320, h = 380;\n const left = Math.min(Math.max(8, x + 12), window.innerWidth - w - 8);\n const top = Math.min(Math.max(8, y + 12), window.innerHeight - h - 8);\n Object.assign(c.style, { display: \"block\", left: left + \"px\", top: top + \"px\" });\n // Do not grab focus on touch: it throws the on-screen keyboard up over the very page\n // the reporter is describing (and over our own form).\n if (!isTouchDevice()) ta.focus();\n }\n\n private closeComposer() {\n this.composer.style.display = \"none\";\n this.pending = null;\n this.pendingShot = undefined;\n }\n\n private async submit(\n target: ComposeTarget,\n title: string,\n body: string,\n withShot: boolean,\n files: File[],\n priority: CommentPriority = DEFAULT_PRIORITY,\n changeType: ChangeType = DEFAULT_CHANGE_TYPE,\n ) {\n if (!title || !body) return;\n const saveBtn = this.composer.querySelector(\".primary\") as HTMLButtonElement;\n if (saveBtn) { saveBtn.disabled = true; saveBtn.textContent = \"Saving…\"; }\n\n let anchor: Anchor, context: Comment[\"context\"], offset: Comment[\"offset\"];\n let screenshot: string | undefined;\n let recording: string | undefined;\n let region: RegionRect | undefined;\n let anchoredEl: Element | null = null;\n\n if (target.kind === \"element\") {\n const capture = this.cfg.captureScreenshot ?? captureScreenshot;\n screenshot = withShot ? await capture(target.element) : undefined;\n anchor = captureAnchor(target.element);\n context = captureElementContext(target.element);\n offset = this.targetOffset;\n anchoredEl = target.element;\n } else if (target.kind === \"free\") {\n // A page-level note: no element, no screenshot. Its position lives in\n // `offset` as a fraction of the document (see onFreeClick + position()).\n screenshot = undefined;\n anchor = pageAnchor(target.point);\n context = { html: \"\", styles: {} };\n offset = target.offset;\n } else {\n // A recording carries its own visuals; a plain region uses the background\n // screenshot (awaited only if it hasn't attached yet).\n recording = target.recording;\n screenshot = !recording && withShot ? (target.screenshot ?? await this.pendingShot) : undefined;\n region = target.region;\n offset = { x: 0, y: 0 };\n // Prefer the real center-element anchor (survives reflow + gives Claude a\n // real element); fall back to a synthetic region anchor when there's none.\n if (target.element) {\n anchor = captureAnchor(target.element);\n context = captureElementContext(target.element);\n anchoredEl = target.element;\n } else {\n anchor = regionAnchor(region);\n context = { html: regionNote(region), styles: {} };\n }\n }\n\n const comment: Comment = {\n id: uid(),\n projectKey: this.cfg.projectKey,\n url: this.url,\n author: this.cfg.user,\n title,\n body,\n status: \"queue\",\n priority,\n changeType,\n kind: target.kind,\n anchor,\n context,\n offset,\n region,\n screenshot,\n recording,\n attachments: await this.uploadAttachments(files),\n // The screen this was captured on, plus enough to tell a stale bundle from a real\n // bug when someone reports \"it still doesn't work\" (see Comment.viewport).\n viewport: {\n w: window.innerWidth,\n h: window.innerHeight,\n v: SDK_VERSION,\n touch: isTouchDevice(),\n coarse: coarsePointer(),\n gdm: canShareScreen(),\n },\n createdAt: new Date().toISOString(),\n };\n await this.store.save(comment);\n this.comments.push(comment);\n this.resolved.set(comment.id, anchoredEl);\n this.closeComposer();\n this.renderPins();\n this.renderList();\n this.flash(comment.id);\n // Loupe's own work joins the same feed an agent bridge writes to.\n this.addActivity({\n kind: \"comment.create\",\n label: `Created “${comment.title || comment.body.split(\"\\n\")[0] || \"comment\"}”`,\n detail: [normalizePriority(comment.priority), comment.kind ?? \"element\", shortPath(comment.url)].join(\" · \"),\n });\n }\n\n /** Upload the reporter's picked files. A file that fails is skipped, not fatal. */\n private async uploadAttachments(files: File[]): Promise<Attachment[] | undefined> {\n if (!files.length) return undefined;\n const out: Attachment[] = [];\n for (const f of files) {\n try {\n out.push(await this.store.upload(this.cfg.projectKey, f));\n } catch (e) {\n console.warn(\"[loupe] attachment upload failed\", f.name, e);\n }\n }\n return out.length ? out : undefined;\n }\n\n // ---- pins + re-anchoring --------------------------------------------------\n\n private renderPins() {\n // Remove pins for deleted comments.\n for (const [id, pin] of this.pins) {\n if (!this.comments.find((c) => c.id === id)) { pin.remove(); this.pins.delete(id); }\n }\n this.comments.forEach((c, i) => {\n // A ticket another project sent here was filed on that project's page, not this one.\n if (c.source) return;\n let pin = this.pins.get(c.id);\n if (!pin) {\n pin = el(\"button\", \"pin\") as HTMLButtonElement;\n pin.onclick = () => { this.openDock(); this.flash(c.id); };\n this.overlay.appendChild(pin);\n this.pins.set(c.id, pin);\n }\n pin.textContent = String(i + 1);\n pin.classList.toggle(\"done\", isResolved(c));\n pin.classList.toggle(\"free\", c.kind === \"free\");\n });\n this.updateCount();\n this.position();\n }\n\n private updateCount(shown = this.comments.length) {\n this.countEl.textContent = String(shown);\n const n = this.comments.length;\n this.fabBadge.textContent = n ? String(n) : \"\";\n }\n\n /** Reposition every pin, re-resolving anchors whose element has gone. */\n private position = () => {\n for (const c of this.comments) {\n const pin = this.pins.get(c.id);\n if (!pin) continue;\n\n if (c.kind === \"free\") {\n // Page-level note: position from the stored document-fraction offset.\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const px = c.offset.x * docW - window.scrollX;\n const py = c.offset.y * docH - window.scrollY;\n const onScreen = px > -24 && px < window.innerWidth + 24 && py > -24 && py < window.innerHeight + 24;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.remove(\"detached\");\n continue;\n }\n\n let elx = this.resolved.get(c.id) ?? null;\n if (!elx || !elx.isConnected) {\n // A malformed stored anchor (older client, or a row someone hand-wrote)\n // must detach that one pin, not abort the render for every other comment.\n let r: ResolveResult | null = null;\n try { r = resolveAnchor(c.anchor); } catch { r = null; }\n elx = r?.element ?? null;\n this.resolved.set(c.id, elx);\n }\n\n if (c.kind === \"region\") {\n // Compute the region's live viewport rect from its anchor element; fall\n // back to stored document coords (older data / no anchor found). A region\n // that was page-level from the start (synthetic anchor) is not \"moved\".\n const box = this.regionRect(c, elx);\n if (box) {\n const onScreen = box.x + box.w > 0 && box.x < window.innerWidth && box.y + box.h > 0 && box.y < window.innerHeight;\n // Keep the marker on the visible part of a large area: its top-left corner is\n // often scrolled off while most of the area is still on screen.\n const px = box.x < 4 ? Math.min(4, box.x + box.w - 30) : box.x;\n const py = box.y < 4 ? Math.min(4, box.y + box.h - 30) : box.y;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.toggle(\"detached\", !(elx && relUsable(c.region?.rel)) && c.anchor.tag !== \"region\");\n } else {\n pin.style.display = \"none\";\n pin.classList.add(\"detached\");\n }\n continue;\n }\n\n if (elx) {\n const rect = elx.getBoundingClientRect();\n const px = rect.left + c.offset.x * rect.width;\n const py = rect.top + c.offset.y * rect.height;\n const onScreen = rect.bottom > 0 && rect.top < window.innerHeight &&\n rect.right > 0 && rect.left < window.innerWidth && rect.width > 0;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.remove(\"detached\");\n } else {\n pin.style.display = \"none\";\n pin.classList.add(\"detached\");\n }\n }\n\n // Keep the highlighted region outline glued to its live rect while scrolling.\n if (this.activeRegionId) {\n const c = this.comments.find((x) => x.id === this.activeRegionId);\n const box = c && this.regionRect(c, this.resolved.get(c.id) ?? null);\n if (box) {\n Object.assign(this.regionBox.style, {\n display: \"block\", left: box.x + \"px\", top: box.y + \"px\", width: box.w + \"px\", height: box.h + \"px\",\n });\n }\n }\n };\n\n /**\n * The current viewport rect for a region comment. Prefers the element-relative\n * fractions (so it tracks reflow across viewports); falls back to the stored\n * document coordinates minus scroll. Returns null if neither is available.\n */\n private regionRect(c: Comment, elx: Element | null): { x: number; y: number; w: number; h: number } | null {\n const rel = c.region?.rel;\n if (elx && relUsable(rel)) {\n const r = elx.getBoundingClientRect();\n return { x: r.left + rel.fx * r.width, y: r.top + rel.fy * r.height, w: rel.fw * r.width, h: rel.fh * r.height };\n }\n if (c.region) {\n return { x: c.region.x - window.scrollX, y: c.region.y - window.scrollY, w: c.region.w, h: c.region.h };\n }\n return null;\n }\n\n private observe() {\n const reposition = () => {\n cancelAnimationFrame(this.raf);\n this.raf = requestAnimationFrame(this.position);\n };\n window.addEventListener(\"scroll\", reposition, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"resize\", this.onWinResize);\n let debounce = 0;\n this.mo = new MutationObserver(() => {\n clearTimeout(debounce);\n debounce = window.setTimeout(() => { this.position(); this.renderList(); }, 120);\n });\n this.mo.observe(document.body, { childList: true, subtree: true, attributes: true, characterData: true });\n // Safety net for animated / late-loading layouts.\n this.tick = window.setInterval(this.position, 800);\n }\n\n // ---- dock: open / close / mode / theme ------------------------------------\n\n private openDock() {\n this.open = true;\n this.fabExpanded = false; // the panel replaces the quick actions\n this.saveState();\n this.applyDockLayout();\n this.renderList();\n }\n\n private closeDock() {\n this.open = false;\n this.setMode(\"off\");\n this.closeComposer();\n this.saveState();\n this.applyDockLayout();\n }\n\n private setDock(mode: DockMode) {\n this.dockMode = mode;\n this.open = true;\n this.saveState();\n this.applyDockLayout();\n }\n\n /** Switch the sidebar page (Home ↔ Comments ↔ Connect Claude). */\n private setTab(tab: Tab) {\n if (this.tab === tab) return;\n if (tab === \"chat\" && !this.chatOn) return;\n // Leaving the Comments page cancels any active picking tool.\n if (tab !== \"comments\") this.setMode(\"off\");\n this.tab = tab;\n this.hintFor = null; // a fresh view is a fresh chance for its hint card\n this.saveState();\n if (tab === \"home\") {\n this.renderHome();\n if (this.scope === \"all\" && !this.allComments.length) void this.loadAllComments();\n }\n if (tab === \"comments\") this.renderList();\n if (tab === \"activity\") {\n this.renderActivity();\n void this.loadActivity();\n }\n this.syncActivityPoll();\n this.applyDockLayout();\n }\n\n private toggleTheme() {\n this.theme = this.theme === \"dark\" ? \"light\" : \"dark\";\n this.saveState();\n this.applyDockLayout();\n }\n\n private onWinResize = () => this.applyDockLayout();\n\n // ---- panel shell: popovers, minimize, accent ------------------------------\n\n private toggleMenu(menu: HTMLElement) {\n const wasOpen = menu.classList.contains(\"open\");\n this.closeMenus();\n if (!wasOpen) menu.classList.add(\"open\");\n }\n\n private closeMenus() {\n this.posMenu?.classList.remove(\"open\");\n this.settingsMenu?.classList.remove(\"open\");\n }\n\n private setAccent(id: string) {\n if (!ACCENT_IDS.includes(id)) return;\n this.accent = id;\n this.saveState();\n this.applyDockLayout();\n }\n\n private setMinimized(v: boolean) {\n this.minimized = v;\n this.closeMenus();\n this.saveState();\n this.applyDockLayout();\n }\n\n /** Flip one of the \"Show …\" settings and repaint whatever it governs. */\n private toggleSetting(key: \"markersHidden\" | \"hoverHints\" | \"showPaths\" | \"launcherHidden\") {\n if (key === \"launcherHidden\") { this.setLauncherHidden(!this.launcherHidden); return; }\n if (key === \"markersHidden\") this.markersHidden = !this.markersHidden;\n else if (key === \"hoverHints\") this.hoverHints = !this.hoverHints;\n else this.showPaths = !this.showPaths;\n this.saveState();\n if (key === \"markersHidden\") this.renderPins();\n if (key === \"showPaths\") { this.renderList(); this.renderHome(); }\n if (key === \"hoverHints\") this.hintFor = null; // the visible card must go too\n this.applyDockLayout();\n }\n\n /** Reflect the current state into the settings menu (never rebuild it). */\n private renderSettings() {\n if (!this.settingsMenu) return;\n const on: Record<string, boolean> = {\n hoverHints: this.hoverHints,\n markersHidden: !this.markersHidden,\n showPaths: this.showPaths,\n launcherHidden: !this.launcherHidden,\n };\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-set]\").forEach((b) => {\n const key = b.dataset.set!;\n if (key in on) b.setAttribute(\"aria-pressed\", String(on[key]));\n // Only offered once there is a custom position to reset.\n if (key === \"fabReset\") b.hidden = !this.fabPos;\n });\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-accent]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.accent === this.accent));\n }\n\n /**\n * The contextual hint card for the active view. Shown at most once per view and\n * never again after that — dismissed, or switched off wholesale with \"Turn off\n * hints\" (the same switch as Settings → Hover hints).\n */\n private renderHints() {\n if (!this.homeEl) return;\n if (this.hintFor === this.tab) return;\n this.hintFor = this.tab;\n const slots: Record<string, HTMLElement | null> = {\n home: this.homeEl.querySelector(\"#loupe-hhint\"),\n comments: this.commentsHint ?? null,\n activity: this.activityHint ?? null,\n };\n for (const [id, slot] of this.customHintSlots) slots[id] = slot;\n const slot = slots[this.tab];\n if (!slot) return;\n slot.innerHTML = \"\";\n const hint = this.hintForTab(this.tab);\n if (!hint || !this.hoverHints || this.minimized || this.hintsSeen.has(this.tab)) return;\n\n // Mark it seen the moment it is painted, so a reload does not replay it.\n this.hintsSeen.add(this.tab);\n this.saveState();\n slot.innerHTML =\n `<div class=\"hint\"><div class=\"hint-t\">${escapeHtml(hint.title)}</div>` +\n `<div class=\"hint-b\">${escapeHtml(hint.body)}</div>` +\n `<button class=\"hint-off\" data-role=\"hint-off\">Turn off hints</button>` +\n `<button class=\"hint-x\" aria-label=\"Dismiss hint\">✕</button></div>`;\n (slot.querySelector('[data-role=\"hint-off\"]') as HTMLElement).onclick = () => {\n this.hoverHints = false;\n // Force the next paint to re-evaluate this view, otherwise the early-return\n // above would leave the card it was clicked from on screen.\n this.hintFor = null;\n this.saveState();\n this.applyDockLayout();\n };\n (slot.querySelector(\".hint-x\") as HTMLElement).onclick = () => { slot.innerHTML = \"\"; };\n }\n\n /** Which view's hint has been handled this session (so it is not re-painted). */\n private hintFor: Tab | null = null;\n\n /** The built-in hints, plus any a registered tab declared for itself. */\n private hintForTab(id: string): { title: string; body: string } | undefined {\n if (id in HINTS) return HINTS[id as BuiltinTab];\n return (this.cfg.tabs ?? []).find((t) => t.id === id)?.hint;\n }\n\n // ---- guided tour ----------------------------------------------------------\n\n private startTour() {\n this.tourStep = 0;\n this.open = true;\n this.minimized = false;\n this.applyDockLayout();\n this.renderTour();\n }\n\n private stopTour() {\n this.tourStep = -1;\n this.tourDone = true;\n this.saveState();\n this.tourEl.classList.remove(\"open\");\n this.applyDockLayout();\n }\n\n private gotoTour(step: number) {\n if (step < 0) { this.stopTour(); return; }\n this.tourStep = step;\n this.renderTour();\n }\n\n /** Position the spotlight over the current step's target and lay out the card. */\n private renderTour() {\n if (this.tourStep < 0 || this.tourStep >= TOUR.length) {\n this.tourEl.classList.remove(\"open\");\n return;\n }\n const step = TOUR[this.tourStep]!;\n if (this.tab !== step.tab) this.setTab(step.tab);\n this.tourEl.classList.add(\"open\");\n\n const pad = 4;\n const target = this.shadow.querySelector(step.sel) as HTMLElement | null;\n const box = target?.getBoundingClientRect();\n const r = box && box.width\n ? { left: box.left - pad, top: box.top - pad, width: box.width + pad * 2, height: box.height + pad * 2 }\n // No on-screen target (panel closed, or the view is hidden) — centre the card.\n : { left: window.innerWidth / 2, top: window.innerHeight / 2, width: 0, height: 0 };\n this.tourSpot.style.left = `${r.left}px`;\n this.tourSpot.style.top = `${r.top}px`;\n this.tourSpot.style.width = `${r.width}px`;\n this.tourSpot.style.height = `${r.height}px`;\n\n const last = this.tourStep === TOUR.length - 1;\n this.tourCard.innerHTML =\n `<div class=\"tour-title\">${escapeHtml(step.title)}</div>` +\n `<div class=\"tour-body\">${escapeHtml(step.body)}</div>` +\n `<div class=\"tour-foot\">` +\n `<span class=\"tour-dots\">${TOUR.map((_, i) => `<i class=\"${i === this.tourStep ? \"on\" : \"\"}\"></i>`).join(\"\")}</span>` +\n (this.tourStep > 0 ? `<button class=\"t-back\">Back</button>` : \"\") +\n `<button class=\"t-skip\">Skip</button>` +\n `<button class=\"t-next\">${last ? \"Done\" : \"Next\"}</button>` +\n `</div>`;\n\n // Place the card below the spotlight, else above, else beside it — rejecting any\n // spot that would land on the very thing it points at, and clamping the rest\n // into the viewport. (Clamping alone used to push the card back onto the target.)\n const W = 252;\n const H = this.tourCard.offsetHeight || 130;\n const overlapsTarget = (x: number, y: number) =>\n x < r.left + r.width + 8 && x + W > r.left - 8 && y < r.top + r.height + 8 && y + H > r.top - 8;\n const candidates: [number, number][] = [\n [r.left + r.width / 2 - W / 2, r.top + r.height + 12], // below\n [r.left + r.width / 2 - W / 2, r.top - H - 12], // above\n [r.left - W - 12, r.top + r.height / 2 - H / 2], // beside (left)\n [r.left + r.width + 12, r.top + r.height / 2 - H / 2], // beside (right)\n ];\n let cx = clampPx(candidates[0]![0], 8, Math.max(8, window.innerWidth - W - 8));\n let cy = clampPx(candidates[0]![1], 8, Math.max(8, window.innerHeight - H - 8));\n for (const [x, y] of candidates) {\n const px = clampPx(x, 8, Math.max(8, window.innerWidth - W - 8));\n const py = clampPx(y, 8, Math.max(8, window.innerHeight - H - 8));\n cx = px; cy = py;\n if (!overlapsTarget(px, py)) break;\n }\n this.tourCard.style.left = `${cx}px`;\n this.tourCard.style.top = `${cy}px`;\n\n (this.tourCard.querySelector(\".t-back\") as HTMLElement | null)?.addEventListener(\"click\", () => this.gotoTour(this.tourStep - 1));\n (this.tourCard.querySelector(\".t-skip\") as HTMLElement)!.addEventListener(\"click\", () => this.stopTour());\n (this.tourCard.querySelector(\".t-next\") as HTMLElement)!.addEventListener(\"click\", () => {\n if (last) this.stopTour(); else this.gotoTour(this.tourStep + 1);\n });\n }\n\n /** Narrow viewports render the panel as a bottom sheet, not a side/float dock. */\n private isMobile() { return window.innerWidth <= 640; }\n\n private loadState() {\n try {\n const s = localStorage.getItem(\"loupe:dock\");\n if (!s) return;\n const p = JSON.parse(s);\n if (DOCK_MODES.includes(p?.mode)) this.dockMode = p.mode;\n if (typeof p?.open === \"boolean\") this.open = p.open;\n if (p?.theme === \"light\" || p?.theme === \"dark\") this.theme = p.theme;\n const known = [...BUILTIN_TABS.map((t) => t.id).filter((id) => id !== \"chat\" || this.chatOn), ...(this.cfg.tabs ?? []).map((t) => t.id)];\n if (typeof p?.tab === \"string\" && known.includes(p.tab)) this.tab = p.tab;\n if (p?.scope === \"page\" || p?.scope === \"all\") this.scope = p.scope;\n if (typeof p?.statFilter === \"string\") this.statFilter = p.statFilter as StatFilter;\n if (p?.float && typeof p.float.w === \"number\") this.floatRect = { ...this.floatRect, ...p.float };\n if (typeof p?.markersHidden === \"boolean\") this.markersHidden = p.markersHidden;\n if (typeof p?.launcherHidden === \"boolean\") this.launcherHidden = p.launcherHidden;\n if (p?.fab && typeof p.fab.x === \"number\" && typeof p.fab.y === \"number\") this.fabPos = { x: p.fab.x, y: p.fab.y };\n if (p?.accent && ACCENT_IDS.includes(p.accent)) this.accent = p.accent;\n if (typeof p?.minimized === \"boolean\") this.minimized = p.minimized;\n if (typeof p?.hoverHints === \"boolean\") this.hoverHints = p.hoverHints;\n if (typeof p?.showPaths === \"boolean\") this.showPaths = p.showPaths;\n if (typeof p?.tourDone === \"boolean\") this.tourDone = p.tourDone;\n if (Array.isArray(p?.hintsSeen)) this.hintsSeen = new Set(p.hintsSeen.filter((x: unknown) => typeof x === \"string\"));\n } catch { /* storage unavailable → defaults */ }\n }\n\n private saveState() {\n try {\n localStorage.setItem(\"loupe:dock\", JSON.stringify({\n mode: this.dockMode, open: this.open, theme: this.theme, tab: this.tab, float: this.floatRect,\n markersHidden: this.markersHidden, launcherHidden: this.launcherHidden, fab: this.fabPos,\n scope: this.scope, statFilter: this.statFilter,\n accent: this.accent, minimized: this.minimized, hoverHints: this.hoverHints,\n showPaths: this.showPaths, tourDone: this.tourDone, hintsSeen: [...this.hintsSeen],\n }));\n } catch { /* ignore */ }\n }\n\n /** Reflect all control-panel state (theme, dock mode, geometry, launcher) into the DOM. */\n private applyDockLayout() {\n this.root.classList.toggle(\"theme-light\", this.theme === \"light\");\n this.themeBtn.title = this.theme === \"dark\" ? \"Switch to light theme\" : \"Switch to dark theme\";\n this.themeBtn.innerHTML = this.theme === \"dark\" ? I_SUN : I_MOON;\n\n // The accent is an inline custom property on the host, so it beats both token\n // blocks and follows the theme.\n const accent = ACCENTS.find((a) => a.id === this.accent) ?? ACCENTS[0]!;\n this.root.style.setProperty(\"--accent\", this.theme === \"light\" ? accent.light : accent.dark);\n this.root.style.setProperty(\"--accent-soft\", accent.soft);\n\n const d = this.dock;\n d.classList.toggle(\"open\", this.open);\n for (const m of DOCK_MODES) d.classList.toggle(\"mode-\" + m, this.dockMode === m);\n d.classList.toggle(\"minimized\", this.minimized);\n // The minimize bar keeps the panel's context — and a way back — on one line.\n const openCount = this.comments.filter((c) => !isResolved(c)).length;\n this.minBar.innerHTML =\n `<span class=\"logo\">◎</span>` +\n `<span class=\"mtext\"><b>${openCount}</b> open ${this.scope === \"all\" ? \"in this project\" : \"on this page\"}</span>` +\n `<span class=\"mrestore\" aria-hidden=\"true\">▸</span>`;\n for (const t of this.tabList) d.classList.toggle(`tab-${t.id}`, this.tab === t.id);\n for (const [id, view] of this.viewEls) view.classList.toggle(\"on\", id === this.tab);\n this.renderConsent();\n this.renderHome();\n d.querySelectorAll<HTMLElement>(\".tabs .tab\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.tab === this.tab));\n this.posMenu.querySelectorAll<HTMLElement>(\"[data-pos]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.pos === this.dockMode));\n this.renderSettings();\n this.renderHints();\n\n if (this.dockMode === \"float\") {\n const vw = window.innerWidth, vh = window.innerHeight;\n let { x, y, w, h } = this.floatRect;\n w = clampPx(w, 280, Math.min(760, vw - 24));\n h = clampPx(h, 220, vh - 24);\n if (x <= 0 && y <= 0) { x = Math.max(12, vw - w - 24); y = 64; } // first placement\n x = clampPx(x, 8, Math.max(8, vw - w - 8));\n y = clampPx(y, 8, Math.max(8, vh - h - 8));\n this.floatRect = { x, y, w, h };\n Object.assign(d.style, { left: x + \"px\", top: y + \"px\", width: w + \"px\", height: h + \"px\", right: \"auto\", bottom: \"auto\" });\n } else {\n for (const p of [\"left\", \"top\", \"right\", \"bottom\", \"width\", \"height\"] as const) d.style[p] = \"\";\n }\n\n d.querySelectorAll<HTMLElement>(\".dctl [data-dock]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.dock === this.dockMode));\n\n // FAB cluster: visible only while the panel is closed and the user has not hidden\n // it; placed where it was dragged, or on the dock's side by default.\n this.fabCluster.classList.toggle(\"show\", !this.open && !this.launcherHidden);\n // A touch screen has no Alt+Shift+L: while the launcher is hidden and the panel is\n // closed, a slim tab at the screen edge is the only way back, so it has to exist.\n this.fabHandle.classList.toggle(\"show\", !this.open && this.launcherHidden && isTouchDevice());\n this.applyFabPosition();\n this.applyFab();\n\n this.pushPage();\n }\n\n /**\n * Push the host page over so the docked panel never covers content (like real\n * DevTools). We shrink the <html> box with a margin on the docked edge — the\n * panel is `position: fixed` (relative to the viewport), so it sits in the\n * gutter the margin frees up. Float mode and the closed state reserve nothing.\n * Only inline styles are touched, so clearing them restores the host exactly.\n */\n private pushPage() {\n const de = document.documentElement;\n de.style.marginLeft = de.style.marginRight = de.style.marginBottom = \"\";\n // On mobile the panel is a bottom-sheet overlay (see styles) — reserving page\n // space would squeeze content to a sliver, so we never push there.\n if (!this.open || this.dockMode === \"float\" || this.isMobile()) return;\n const r = this.dock.getBoundingClientRect();\n if (this.dockMode === \"left\") de.style.marginLeft = r.width + \"px\";\n else if (this.dockMode === \"right\") de.style.marginRight = r.width + \"px\";\n else if (this.dockMode === \"bottom\") de.style.marginBottom = r.height + \"px\";\n }\n\n // ---- float-mode drag + resize ---------------------------------------------\n\n private onHeadPointerDown = (e: PointerEvent) => {\n if (this.dockMode !== \"float\" || e.button !== 0 || this.isMobile()) return;\n if ((e.target as HTMLElement)?.closest(\".dctl\")) return; // let control buttons work\n this.floatDrag = { px: e.clientX, py: e.clientY, ox: this.floatRect.x, oy: this.floatRect.y };\n this.dock.classList.add(\"dragging\");\n window.addEventListener(\"pointermove\", this.onHeadPointerMove);\n window.addEventListener(\"pointerup\", this.onHeadPointerUp);\n };\n private onHeadPointerMove = (e: PointerEvent) => {\n if (!this.floatDrag) return;\n e.preventDefault();\n this.floatRect.x = this.floatDrag.ox + (e.clientX - this.floatDrag.px);\n this.floatRect.y = this.floatDrag.oy + (e.clientY - this.floatDrag.py);\n this.applyDockLayout();\n };\n private onHeadPointerUp = () => {\n if (!this.floatDrag) return;\n this.floatDrag = null;\n this.dock.classList.remove(\"dragging\");\n window.removeEventListener(\"pointermove\", this.onHeadPointerMove);\n window.removeEventListener(\"pointerup\", this.onHeadPointerUp);\n this.saveState();\n };\n\n private onResizeDown = (e: PointerEvent) => {\n if (this.dockMode !== \"float\") return;\n e.preventDefault(); e.stopPropagation();\n this.floatResize = { px: e.clientX, py: e.clientY, ow: this.floatRect.w, oh: this.floatRect.h };\n window.addEventListener(\"pointermove\", this.onResizeMove);\n window.addEventListener(\"pointerup\", this.onResizeUp);\n };\n private onResizeMove = (e: PointerEvent) => {\n if (!this.floatResize) return;\n e.preventDefault();\n this.floatRect.w = this.floatResize.ow + (e.clientX - this.floatResize.px);\n this.floatRect.h = this.floatResize.oh + (e.clientY - this.floatResize.py);\n this.applyDockLayout();\n };\n private onResizeUp = () => {\n if (!this.floatResize) return;\n this.floatResize = null;\n window.removeEventListener(\"pointermove\", this.onResizeMove);\n window.removeEventListener(\"pointerup\", this.onResizeUp);\n this.saveState();\n };\n\n // ---- comment list ---------------------------------------------------------\n\n private renderList() {\n this.listEl.innerHTML = \"\";\n const q = this.search.trim().toLowerCase();\n const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;\n\n let items = this.visibleComments.filter((c) => {\n const stage = normalizeStatus(c.status);\n if (this.statFilter === \"open\" && stage === \"resolved\") return false;\n if (this.statFilter === \"needs_you\" && !needsYou({ status: c.status }).needs) return false;\n if (this.statFilter === \"resolved\" && stage !== \"resolved\") return false;\n if (this.statFilter === \"stale\" && (stage === \"resolved\" || !(Date.parse(c.createdAt) < weekAgo))) return false;\n return !q || `${c.title ?? \"\"} ${c.body} ${c.author?.name ?? \"\"}`.toLowerCase().includes(q);\n });\n\n // The project scope is a timeline — newest first, grouped by day. The page\n // scope keeps file order, which follows the pins down the page.\n if (this.scope === \"all\") items = [...items].sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n\n this.renderReviewBar();\n\n if (!items.length) {\n this.listEl.appendChild(el(\"div\", \"empty\",\n this.statFilter\n ? \"Nothing in this bucket.\"\n : q\n ? \"No comments match your search.\"\n : this.scope === \"all\"\n ? \"No feedback in this project yet.\"\n : \"No comments yet. Use Inspect to pick an element, or Note to drop a comment anywhere on the page.\"));\n }\n\n let lastDay = \"\";\n items.forEach((c, i) => {\n if (this.scope === \"all\") {\n const day = dayLabel(c.createdAt);\n if (day !== lastDay) {\n this.listEl.appendChild(el(\"div\", \"daylabel\", day));\n lastDay = day;\n }\n }\n this.listEl.appendChild(this.itemView(c, i));\n });\n this.updateCount(items.length);\n }\n\n private itemView(c: Comment, i: number): HTMLElement {\n const detached = this.pins.get(c.id)?.classList.contains(\"detached\") && !isResolved(c);\n const open = this.expanded.has(c.id);\n const item = el(\"div\", \"item\" + (open ? \"\" : \" collapsed\"));\n const top = el(\"div\", \"top\");\n const num = el(\"span\", \"num\" + (isResolved(c) ? \" done\" : detached ? \" detached\" : \"\"), String(i + 1));\n top.append(num);\n if (c.recording) top.appendChild(el(\"span\", \"rectag\", \"⏺ recording\"));\n const vw = c.viewport?.w;\n if (vw) {\n const kind = vw < 768 ? \"mobile\" : vw < 1024 ? \"tablet\" : \"desktop\";\n const icon = vw < 768 ? \"📱\" : vw < 1024 ? \"▦\" : \"🖥\";\n top.appendChild(el(\"span\", \"device\", `${icon} ${kind}`));\n }\n if (c.source) {\n const from = el(\"span\", \"srcchip\", `from ${c.source.projectName || c.source.projectId}`);\n from.title = c.source.reporter\n ? `Sent by ${c.source.reporter.name || c.source.reporter.email}`\n : \"Sent from another project\";\n top.appendChild(from);\n }\n const fwd = c.forwarded;\n if (fwd && fwd.status !== \"none\") {\n const where = fwd.destinationName || (fwd.status === \"ok\" ? \"webhook\" : \"Hub\");\n const ok = fwd.status === \"ok\";\n const remote = ok ? fwd.remote : undefined;\n if (remote) {\n // The receiver reported back: show where the ticket is over there.\n const said = remote.label || STAGE_LABELS[normalizeStatus(remote.status)];\n const text = [`→ ${where}`, remote.reference, said].filter(Boolean).join(\" · \");\n const link = remote.url && /^https?:\\/\\//i.test(remote.url) ? remote.url : null;\n const chip = el(link ? \"a\" : \"span\", `fwdchip st-${normalizeStatus(remote.status)}`, text);\n chip.title = `${where}: ${said}${remote.at ? ` — updated ${fmtAgo(remote.at)}` : \"\"}`;\n if (link) {\n (chip as HTMLAnchorElement).href = link;\n chip.setAttribute(\"target\", \"_blank\");\n chip.setAttribute(\"rel\", \"noreferrer\");\n chip.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n top.appendChild(chip);\n } else {\n const chip = el(\"span\", ok ? \"fwdchip\" : \"fwdchip bad\", ok ? `→ ${where}` : `→ ${where} failed`);\n chip.title = ok ? `Sent to ${where}` : `Could not send to ${where}${fwd.error ? `: ${fwd.error}` : \"\"}`;\n top.appendChild(chip);\n }\n }\n if (isResolved(c)) top.appendChild(el(\"span\", \"badge done\", \"resolved\"));\n else if (detached) {\n // Short label, full explanation on hover — the long form ate a third of the\n // row on its own and pushed the lifecycle chips past the card edge.\n const b = el(\"span\", \"badge detached\", \"moved\");\n b.title = \"element moved or removed\";\n top.appendChild(b);\n }\n\n // Where this thread's change has got to: sent to an agent, in a PR, or waiting\n // on a review. A thread with nothing attached stays unbadged.\n const lc = lifecycle(c);\n if (lc) {\n // A resolved thread already wears the \"resolved\" badge, so a second green pill\n // saying \"Reviewed\" is noise. Its PR chip and checks meter are still worth\n // showing — that is the part you cannot read off the badge.\n if (lc.stage !== \"reviewed\") top.appendChild(el(\"span\", `lifechip st-${lc.stage}`, lc.label));\n if (lc.pr) {\n const pr = el(lc.pr.url ? \"a\" : \"span\", `prchip${lc.pr.state ? ` st-${lc.pr.state}` : \"\"}`, `#${lc.pr.number}`);\n pr.title = `Pull request #${lc.pr.number}${lc.pr.state ? ` — ${lc.pr.state}` : \"\"}`;\n if (lc.pr.url) {\n (pr as HTMLAnchorElement).href = lc.pr.url;\n pr.setAttribute(\"target\", \"_blank\");\n pr.setAttribute(\"rel\", \"noreferrer\");\n pr.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n top.appendChild(pr);\n }\n if (lc.checks) {\n const meter = el(\"span\", \"checks\");\n meter.title = `Checks — ${lc.checks.text} passed`;\n meter.innerHTML =\n `<span class=\"checks-n\">${escapeHtml(lc.checks.text)}</span>` +\n `<span class=\"checks-bar\"><i style=\"width:${Math.round(lc.checks.ratio * 100)}%\"></i></span>`;\n top.appendChild(meter);\n }\n // Only when a URL is actually known — a preview is never guessed, so there is\n // no \"deploying…\" state to sit in limbo here.\n if (lc.pr?.previewUrl) {\n const preview = el(\"a\", \"previewchip\", \"Preview\") as HTMLAnchorElement;\n preview.href = lc.pr.previewUrl;\n preview.target = \"_blank\";\n preview.rel = \"noreferrer\";\n preview.title = `Preview live at ${lc.pr.previewUrl}`;\n preview.addEventListener(\"click\", (e) => e.stopPropagation());\n top.appendChild(preview);\n }\n }\n\n // A revision says which thread it revises — the conversation carried over, and a\n // reviewer needs to know that rather than seeing an unconnected duplicate.\n const iteration = iterationLabel(c);\n if (iteration) {\n const chip = el(\"span\", \"iterchip\", iteration);\n chip.title = `Revision of thread #${c.parentThreadId}`;\n top.appendChild(chip);\n }\n\n // Page paths only mean something once the list spans more than one page.\n if (this.showPaths && this.scope === \"all\" && c.url) {\n top.appendChild(el(\"span\", \"pathtag\", shortPath(c.url)));\n }\n top.appendChild(el(\"span\", \"caret\", open ? \"▾\" : \"▸\"));\n item.appendChild(top);\n\n // Collapsed, the item is a single summary line; expanding reveals the detail.\n const summary = c.title || (c.body.split(\"\\n\")[0] ?? \"\").slice(0, 140) || \"(no description)\";\n item.appendChild(el(\"div\", \"summary\", summary));\n\n // Who raised it and when, in the configured time zone — shown collapsed too, so a\n // reporter can find their own thread in the list without opening every card.\n // (This used to be withheld from the widget; teams asked for it back.)\n const who = el(\"div\", \"who\");\n const when = this.fmtWhen(c.createdAt);\n who.innerHTML =\n `<b>${escapeHtml(c.author?.name?.trim() || \"Unknown\")}</b>` +\n (when ? ` · <time datetime=\"${escapeAttr(c.createdAt)}\" title=\"${escapeAttr(fmtAgo(c.createdAt))}\">${escapeHtml(when)}</time>` : \"\");\n item.appendChild(who);\n\n const detail = el(\"div\", \"detail\");\n // With the messages loaded, the predicate can see the two reasons the stage cannot\n // express: an agent's unanswered question, and a failed run. A routine review\n // needs no line — it has the banner below.\n const repliesForState = this.messages.get(c.id) ?? [];\n const lastMsg = repliesForState.length ? repliesForState[repliesForState.length - 1] : undefined;\n const attention = needsYou({\n status: c.status,\n last: lastMsg ? { fromAgent: lastMsg.author.type === \"agent\", body: lastMsg.body } : null,\n agentFailed: this.msgFailed.has(lastMsg?.id ?? \"\"),\n });\n if (c.status !== \"resolved\" && attention.needs && attention.reason !== \"review\") {\n const line = el(\"div\", \"needsline\");\n line.append(el(\"span\", \"needs-dot\"), el(\"span\", \"\", attention.label ?? \"Needs you\"));\n detail.appendChild(line);\n }\n // A thread in review leads with its banner: this is the one place a human is\n // being asked to decide something, so it goes above everything else.\n if (c.status === \"in_review\") detail.appendChild(this.reviewBanner(c));\n // Claude's proposed change, with the original request beside it on demand.\n if (c.proposal) detail.appendChild(this.proposalView(c));\n // With a title, the body is the full description; without one the first line is\n // already the summary, so only multi-line bodies repeat it here.\n if (c.title || c.body.includes(\"\\n\")) detail.appendChild(el(\"div\", \"body\", c.body));\n detail.appendChild(el(\"div\", \"meta\", describeAnchor(c)));\n\n if (c.recording) {\n const v = el(\"video\", \"shot\") as HTMLVideoElement;\n v.src = c.recording;\n v.controls = true;\n v.playsInline = true;\n if (c.screenshot) v.poster = c.screenshot;\n detail.appendChild(v);\n } else if (c.screenshot) {\n const img = el(\"img\", \"shot\") as HTMLImageElement;\n img.src = c.screenshot;\n detail.appendChild(img);\n }\n\n // Files the reporter attached (images and videos).\n for (const a of c.attachments ?? []) {\n if (a.kind === \"video\") {\n const v = el(\"video\", \"shot\") as HTMLVideoElement;\n v.src = a.url;\n v.controls = true;\n v.playsInline = true;\n detail.appendChild(v);\n } else {\n const img = el(\"img\", \"shot\") as HTMLImageElement;\n img.src = a.url;\n img.alt = a.name ?? \"attachment\";\n detail.appendChild(img);\n }\n }\n\n const actions = el(\"div\", \"actions\");\n const doneBtn = el(\"button\", \"\", isResolved(c) ? \"Reopen\" : \"Resolve\") as HTMLButtonElement;\n doneBtn.onclick = async (e) => {\n e.stopPropagation();\n const status = isResolved(c) ? \"queue\" : \"resolved\";\n c.status = status; await this.store.update(c.id, { status });\n this.renderPins(); this.renderList();\n this.addActivity({\n kind: status === \"resolved\" ? \"comment.resolve\" : \"comment.reopen\",\n label: `${status === \"resolved\" ? \"Resolved\" : \"Reopened\"} “${c.title || c.body.split(\"\\n\")[0] || \"comment\"}”`,\n });\n };\n const del = el(\"button\", \"\", \"Delete\") as HTMLButtonElement;\n del.onclick = async (e) => {\n e.stopPropagation();\n await this.store.remove(c.id);\n this.comments = this.comments.filter((x) => x.id !== c.id);\n this.resolved.delete(c.id);\n this.renderPins(); this.renderList();\n this.addActivity({\n kind: \"comment.delete\",\n label: `Deleted “${c.title || c.body.split(\"\\n\")[0] || \"comment\"}”`,\n level: \"warn\",\n });\n };\n actions.append(doneBtn, del);\n detail.appendChild(actions);\n // The conversation: replies, a reply box, the timeline and the copy actions.\n detail.appendChild(this.conversationView(c));\n // Generating a change for this thread, and its iteration history.\n detail.appendChild(this.generateView(c));\n item.appendChild(detail);\n\n item.onclick = () => {\n if (open) this.expanded.delete(c.id);\n else {\n this.expanded.add(c.id);\n // Replies are fetched the first time a card is opened, not for the whole list.\n void this.loadMessages(c);\n }\n this.renderList();\n };\n return item;\n }\n\n /**\n * The review banner. This is the one place the panel asks a human to decide\n * something, so it sits above everything else in the detail.\n *\n * Approving resolves the thread. That asymmetry is the rule the whole flow rests\n * on: an agent moves work to In Review, only a person closes it.\n */\n private reviewBanner(c: Comment): HTMLElement {\n const label = c.title || c.body.split(\"\\n\")[0] || \"this thread\";\n const banner = el(\"div\", \"revbanner\");\n banner.innerHTML = `<span class=\"rev-dot\"></span><span class=\"rev-t\">Waiting on your review</span><span class=\"rev-spacer\"></span>`;\n\n const approve = el(\"button\", \"rev-approve\", \"Approve\") as HTMLButtonElement;\n approve.onclick = async (e) => {\n e.stopPropagation();\n approve.disabled = true;\n approve.textContent = \"Approving…\";\n await this.store.update(c.id, { status: \"resolved\" });\n c.status = \"resolved\";\n this.renderPins();\n this.renderList();\n this.renderHome();\n this.addActivity({ kind: \"review.approve\", label: `Approved “${label}”` });\n };\n\n const discuss = el(\"button\", \"rev-comment\", \"Add comment\") as HTMLButtonElement;\n discuss.onclick = (e) => {\n e.stopPropagation();\n // Comment on the same element when it is still on the page; otherwise drop a\n // page-level note rather than refusing the action.\n const target = this.resolved.get(c.id);\n if (target && target.isConnected) {\n const r = target.getBoundingClientRect();\n this.openComposer({ kind: \"element\", element: target }, r.left + r.width / 2, r.top + r.height);\n } else {\n this.setMode(\"free\");\n }\n };\n\n banner.append(approve, discuss);\n\n // The origin toggle only means something once there is a change to compare to.\n if (c.proposal) {\n const origin = el(\"button\", \"rev-origin\", \"Show original\") as HTMLButtonElement;\n origin.onclick = (e) => {\n e.stopPropagation();\n const view = banner.parentElement?.querySelector(\".origin\") as HTMLElement | null;\n if (!view) return;\n const shown = view.classList.toggle(\"show\");\n view.style.display = shown ? \"\" : \"none\";\n origin.textContent = shown ? \"Hide original\" : \"Show original\";\n };\n banner.appendChild(origin);\n }\n return banner;\n }\n\n /**\n * The original request beside Claude's proposed change. Hidden until the review\n * banner's toggle asks for it — a reviewer who does not care should not pay for\n * the markup.\n */\n private proposalView(c: Comment): HTMLElement {\n const p = c.proposal!;\n const wrap = el(\"div\", \"origin\");\n wrap.style.display = \"none\";\n wrap.innerHTML =\n `<div class=\"or-col\"><div class=\"or-h\">Original request</div>` +\n `<div class=\"or-b\">${escapeHtml(c.title ? `${c.title}\\n\\n${c.body}` : c.body)}</div>` +\n (c.context?.html ? `<pre class=\"or-code\">${escapeHtml(c.context.html)}</pre>` : \"\") +\n `</div>` +\n `<div class=\"or-col\"><div class=\"or-h\">Proposed change${p.author ? ` · ${escapeHtml(p.author)}` : \"\"}</div>` +\n (p.notes ? `<div class=\"or-b\">${escapeHtml(p.notes)}</div>` : \"\") +\n (p.html ? `<pre class=\"or-code\">${escapeHtml(p.html)}</pre>` : \"\") +\n (p.css ? `<pre class=\"or-code\">${escapeHtml(p.css)}</pre>` : \"\") +\n `</div>`;\n return wrap;\n }\n\n /** The strips above the list: how many threads are waiting on a human. */\n private renderReviewBar() {\n if (!this.reviewBar) return;\n const waiting = awaitingReview(this.visibleComments);\n if (!waiting.length) {\n this.reviewBar.innerHTML = \"\";\n this.reviewBar.style.display = \"none\";\n return;\n }\n const on = this.statFilter === \"needs_you\";\n this.reviewBar.style.display = \"\";\n this.reviewBar.innerHTML =\n `<span class=\"rb-dot\"></span>` +\n `<span class=\"rb-t\"><b>${waiting.length}</b> waiting on your review</span>` +\n `<button class=\"rb-b\" data-role=\"rb-toggle\">${on ? \"Show all\" : \"Review\"}</button>`;\n (this.reviewBar.querySelector('[data-role=\"rb-toggle\"]') as HTMLElement).onclick = () => {\n this.statFilter = on ? \"\" : \"needs_you\";\n this.renderList();\n this.renderHome();\n };\n }\n\n // ---- generate + iterate ---------------------------------------------------\n\n /**\n * The generate pane for one thread: the preview plane, its opacity comparison\n * against the original capture, the iteration stack and the iterate input.\n *\n * The panel owns all of that; producing the markup is the host's `generate`\n * function. Without one there is nothing to preview, so the pane offers the\n * access gate instead of a dead button.\n */\n private generateView(c: Comment): HTMLElement {\n const wrap = el(\"div\", \"genwrap\");\n const state = this.iterations.get(c.id) ?? emptyIterations();\n const cur = currentIteration(state);\n const busy = this.genBusy.has(c.id);\n\n if (this.genOpen !== c.id) {\n const open = el(\"button\", \"gen-open\", cur ? \"✦ Change preview\" : \"✦ Generate a change\") as HTMLButtonElement;\n open.onclick = (e) => {\n e.stopPropagation();\n this.genOpen = c.id;\n this.renderList();\n };\n wrap.appendChild(open);\n return wrap;\n }\n\n if (!this.cfg.generate) {\n // The access gate. Ties to whatever the host does with the request — the Team\n // tab does not exist yet, so this is the seam it will land on.\n const gate = el(\"div\", \"gengate\");\n gate.innerHTML =\n `<div class=\"gate-t\">Generating needs access</div>` +\n `<div class=\"gate-b\">This project has no generator configured for you yet. ` +\n `Ask for access and an owner can switch it on.</div>`;\n const ask = el(\"button\", \"gate-ask\", \"Request access to generate\") as HTMLButtonElement;\n ask.onclick = async (e) => {\n e.stopPropagation();\n ask.disabled = true;\n ask.textContent = \"Request sent\";\n await this.cfg.onRequestAccess?.({\n capability: \"generate\", user: this.cfg.user, projectKey: this.cfg.projectKey,\n });\n this.addActivity({\n kind: \"access.request\", label: \"Requested access to generate\",\n detail: this.cfg.projectKey, level: \"warn\",\n });\n };\n gate.appendChild(ask);\n if (!this.cfg.onRequestAccess) {\n gate.appendChild(el(\"div\", \"gate-hint\", \"Pass onRequestAccess to init() to route this somewhere.\"));\n }\n wrap.appendChild(gate);\n wrap.appendChild(this.genClose(c));\n return wrap;\n }\n\n const head = el(\"div\", \"genhead\");\n head.innerHTML = `<span class=\"gen-t\">Generate</span>`;\n const nav = el(\"span\", \"gen-nav\");\n const prev = el(\"button\", \"gen-step\", \"‹\") as HTMLButtonElement;\n prev.disabled = !canMove(state, -1);\n prev.setAttribute(\"aria-label\", \"Previous iteration\");\n prev.onclick = (e) => { e.stopPropagation(); this.setIterations(c.id, moveIteration(state, -1)); };\n const label = el(\"span\", \"gen-n\", stackLabel(state));\n const next = el(\"button\", \"gen-step\", \"›\") as HTMLButtonElement;\n next.disabled = !canMove(state, 1);\n next.setAttribute(\"aria-label\", \"Next iteration\");\n next.onclick = (e) => { e.stopPropagation(); this.setIterations(c.id, moveIteration(state, 1)); };\n nav.append(prev, label, next);\n head.appendChild(nav);\n\n const undo = el(\"button\", \"gen-undo\", \"Undo\") as HTMLButtonElement;\n undo.disabled = !canUndo(state) || busy;\n undo.onclick = (e) => {\n e.stopPropagation();\n this.setIterations(c.id, undoIteration(state));\n this.addActivity({ kind: \"generate.undo\", label: \"Undid a generated change\" });\n };\n head.append(undo, this.genClose(c));\n wrap.appendChild(head);\n\n if (busy) {\n wrap.appendChild(el(\"div\", \"genbusy\", \"Generating…\"));\n } else if (cur) {\n // The preview plane. Sandboxed: generated markup must never reach the host page,\n // and `allow-scripts` is deliberately absent.\n const plane = el(\"div\", \"genplane\");\n if (c.screenshot) {\n const base = el(\"img\", \"genbase\") as HTMLImageElement;\n base.src = c.screenshot;\n base.alt = \"Original capture\";\n plane.appendChild(base);\n }\n const frame = el(\"iframe\", \"genframe\") as HTMLIFrameElement;\n frame.setAttribute(\"sandbox\", \"\");\n frame.setAttribute(\"title\", \"Generated change preview\");\n // A generated change is usually a *fragment*, so the plane needs a surface under\n // it or it reads as an empty dark box. White, like any other design preview.\n frame.srcdoc = `<!doctype html><meta charset=\"utf-8\"><style>html,body{margin:0;padding:10px;` +\n `background:#fff;font:13px -apple-system,system-ui,sans-serif;color:#111}${cur.css ?? \"\"}</style>${cur.html}`;\n frame.style.opacity = String(this.genOpacity);\n plane.appendChild(frame);\n wrap.appendChild(plane);\n\n const slider = el(\"div\", \"genslider\");\n slider.innerHTML = `<span class=\"gs-lab\">Compare</span>`;\n const range = el(\"input\", \"gs-range\") as HTMLInputElement;\n range.type = \"range\";\n range.min = \"0\";\n range.max = \"100\";\n range.value = String(Math.round(this.genOpacity * 100));\n range.setAttribute(\"aria-label\", \"Generated change opacity\");\n // No re-render on input: only the plane's opacity changes, so the slider keeps\n // its grip while dragging.\n range.oninput = () => {\n this.genOpacity = Number(range.value) / 100;\n frame.style.opacity = String(this.genOpacity);\n };\n slider.append(range, el(\"span\", \"gs-n\", `${Math.round(this.genOpacity * 100)}%`));\n wrap.appendChild(slider);\n\n if (cur.notes) wrap.appendChild(el(\"div\", \"gennotes\", cur.notes));\n } else {\n wrap.appendChild(el(\"div\", \"genempty\", \"Nothing generated yet.\"));\n }\n\n // The iterate input. Sending is the only thing that re-renders, so typing is safe.\n const iter = el(\"div\", \"geniter\");\n const kind = document.createElement(\"select\");\n kind.className = \"mini\";\n kind.title = \"How to treat your follow-up\";\n kind.setAttribute(\"aria-label\", \"Iteration kind\");\n kind.append(\n optionEl(\"Refine\", \"refine\", true),\n optionEl(\"Revise\", \"revise\", false),\n );\n const input = el(\"input\", \"iter-in\") as HTMLInputElement;\n input.type = \"text\";\n input.placeholder = cur ? \"Refine it, e.g. “larger button”\" : \"What should change?\";\n input.value = this.iterDraft.get(c.id) ?? \"\";\n input.oninput = () => this.iterDraft.set(c.id, input.value);\n // Keep clicks inside the pane from toggling the card.\n for (const n of [kind, input]) n.addEventListener(\"click\", (e) => e.stopPropagation());\n const send = el(\"button\", \"iter-send\", \"Send\") as HTMLButtonElement;\n send.disabled = busy;\n send.onclick = (e) => {\n e.stopPropagation();\n const prompt = (this.iterDraft.get(c.id) ?? \"\").trim();\n if (!prompt) return;\n this.iterDraft.delete(c.id);\n void this.runGenerate(c, prompt, kind.value as \"refine\" | \"revise\");\n };\n input.onkeydown = (e) => { if (e.key === \"Enter\") send.click(); };\n iter.append(kind, input, send);\n wrap.appendChild(iter);\n return wrap;\n }\n\n private genClose(c: Comment): HTMLElement {\n const x = el(\"button\", \"gen-x\", \"✕\") as HTMLButtonElement;\n x.setAttribute(\"aria-label\", \"Close\");\n x.onclick = (e) => { e.stopPropagation(); this.genOpen = null; this.renderList(); };\n return x;\n }\n\n private setIterations(id: string, state: IterationState) {\n this.iterations.set(id, state);\n this.renderList();\n }\n\n /** Draft follow-ups, kept out of the render path so the input never loses focus. */\n private iterDraft = new Map<string, string>();\n\n /** Ask the host's generator for a change, and stack the result. */\n private async runGenerate(c: Comment, prompt: string, kind: \"generate\" | \"refine\" | \"revise\") {\n const generate = this.cfg.generate;\n if (!generate) return;\n const state = this.iterations.get(c.id) ?? emptyIterations();\n this.genBusy.add(c.id);\n this.genOpen = c.id;\n this.renderList();\n const started = Date.now();\n try {\n const out = await generate({\n comment: c,\n prompt,\n kind,\n previous: currentIteration(state) ?? undefined,\n localAi: this.project.localAi,\n });\n const next = addIteration(state, {\n id: `it${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n at: new Date().toISOString(),\n html: out.html,\n css: out.css,\n notes: out.notes,\n prompt,\n kind,\n });\n this.genBusy.delete(c.id);\n this.iterations.set(c.id, next);\n this.addActivity({\n kind: `generate.${kind}`,\n label: `${kind === \"generate\" ? \"Generated\" : \"Iterated on\"} “${c.title || prompt}”`,\n detail: `${Math.round((Date.now() - started) / 1000)}s · ${stackLabel(next)}`,\n });\n } catch (e) {\n this.genBusy.delete(c.id);\n this.addActivity({\n kind: \"generate.error\",\n label: `Generation failed: ${e instanceof Error ? e.message : String(e)}`,\n level: \"error\",\n });\n }\n this.renderList();\n }\n\n // ---- agent navigation (consent-gated) -------------------------------------\n\n /**\n * An agent asks to move the browser. Nothing navigates here — the request is\n * queued and the user answers it. `decide()` is the only thing that ever yields a\n * URL, and it yields one only on an explicit grant.\n */\n requestNavigation(url: string, opts: { reason?: string; requester?: string } = {}) {\n const next = requestNav(this.consent, { url, ...opts });\n if (next === this.consent) return; // not a navigable URL — refused outright\n this.consent = next;\n this.open = true;\n this.saveState();\n this.applyDockLayout();\n this.renderConsent();\n this.addActivity({\n kind: \"nav.request\",\n label: `Asked to open ${url}`,\n detail: opts.requester,\n level: \"warn\",\n });\n }\n\n /** Local-AI settings, used as the default in GenerateRequest.localAi. */\n setLocalAi(config: LocalAiConfig | null) {\n this.project = { ...this.project, localAi: config ?? undefined };\n this.saveProject();\n this.renderProject();\n }\n\n private setLocalAiStatus(text: string) {\n const box = this.homeEl?.querySelector(\"#loupe-pp-ai\") as HTMLElement | null;\n if (box) box.textContent = text;\n }\n\n /**\n * Ask the configured endpoint what it serves. A real check against the real\n * server — an OpenAI-compatible `/v1/models` is what Ollama, llama.cpp and the\n * rest all expose — with a timeout, so a wrong port reports rather than hangs.\n */\n private async testLocalAi(pop: HTMLElement) {\n const url = normalizeEnvUrl((pop.querySelector(\".pp-ai-url\") as HTMLInputElement).value);\n const model = (pop.querySelector(\".pp-ai-model\") as HTMLInputElement).value.trim();\n if (!url) {\n this.projError = \"Enter a full http:// or https:// endpoint URL.\";\n this.renderProjectError();\n return;\n }\n this.projError = \"\";\n this.setLocalAiStatus(\"Checking…\");\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), 4000);\n try {\n const res = await fetch(`${url}/v1/models`, { signal: ctl.signal });\n if (!res.ok) {\n this.setLocalAiStatus(`Reachable, but it answered ${res.status}.`);\n return;\n }\n const body: any = await res.json().catch(() => null);\n const ids: string[] = Array.isArray(body?.data)\n ? body.data.map((m: any) => String(m?.id ?? \"\")).filter(Boolean)\n : [];\n // If a model is named and the server lists models, say when it is not among them\n // — a typo'd model name is the most common way this silently does nothing.\n if (model && ids.length && !ids.some((i) => i === model || i.startsWith(`${model}:`))) {\n const shown = ids.slice(0, 4).join(\", \");\n this.setLocalAiStatus(`Connected, but no “${model}” — it serves: ${shown}${ids.length > 4 ? \", …\" : \"\"}`);\n return;\n }\n this.setLocalAiStatus(\n ids.length ? `Connected — ${ids.length} model${ids.length === 1 ? \"\" : \"s\"} available.` : \"Connected.\",\n );\n } catch (e) {\n this.setLocalAiStatus((e as Error)?.name === \"AbortError\"\n ? \"Timed out. Is the server running, and does it allow this origin (CORS)?\"\n : \"Could not reach it. Check the URL, and that the server allows this origin (CORS).\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private renderConsent() {\n if (!this.consentEl) return;\n if (!consentPending(this.consent)) {\n this.consentEl.innerHTML = \"\";\n this.consentEl.style.display = \"none\";\n return;\n }\n const r = this.consent.request!;\n this.consentEl.style.display = \"\";\n this.consentEl.innerHTML =\n `<div class=\"cs-head\"><span class=\"cs-dot\"></span>` +\n `<b>${escapeHtml(r.requester ?? \"An agent\")}</b> wants to open a page</div>` +\n `<div class=\"cs-url\">${escapeHtml(r.url)}</div>` +\n (r.reason ? `<div class=\"cs-why\">${escapeHtml(r.reason)}</div>` : \"\") +\n `<div class=\"cs-btns\"><button class=\"cs-deny\">Stay here</button><button class=\"cs-go\">Go there</button></div>`;\n\n (this.consentEl.querySelector(\".cs-deny\") as HTMLElement).onclick = () => {\n const { record } = decideConsent(this.consent, false);\n this.consent = record;\n this.renderConsent();\n this.addActivity({ kind: \"nav.deny\", label: `Declined opening ${r.url}` });\n };\n (this.consentEl.querySelector(\".cs-go\") as HTMLElement).onclick = () => {\n const { record, navigateTo } = decideConsent(this.consent, true);\n this.consent = record;\n this.renderConsent();\n this.addActivity({ kind: \"nav.grant\", label: `Opened ${navigateTo}` });\n // The only line in the SDK that navigates, and it cannot run without a grant.\n if (navigateTo) window.location.assign(navigateTo);\n };\n }\n\n /** Drop a pending request without deciding it — e.g. the panel is closing. */\n private abandonNavigation() {\n this.consent = withdrawConsent(this.consent);\n this.renderConsent();\n }\n\n /** The dictation button, or nothing at all where the browser has no speech API. */\n private voiceButton(target: HTMLTextAreaElement): HTMLElement {\n const Ctor = (window as any).SpeechRecognition ?? (window as any).webkitSpeechRecognition;\n const b = el(\"button\", \"voice\", \"\") as HTMLButtonElement;\n this.voiceEl = b;\n if (!Ctor) {\n // No API: say so rather than offering a button that cannot work.\n b.textContent = \"🎤\";\n b.disabled = true;\n b.title = \"Dictation is not available in this browser\";\n b.setAttribute(\"aria-label\", \"Dictation unavailable\");\n return b;\n }\n const idle = () => {\n b.classList.remove(\"on\");\n b.textContent = \"🎤\";\n b.setAttribute(\"aria-label\", \"Dictate\");\n b.title = \"Dictate\";\n };\n const listening = () => {\n b.classList.add(\"on\");\n b.textContent = \"⏺\";\n b.setAttribute(\"aria-label\", \"Stop dictating\");\n b.title = \"Listening — click to stop\";\n };\n idle();\n b.onclick = (e) => {\n e.stopPropagation();\n if (this.voice) { this.stopVoice(); idle(); return; }\n const rec = new Ctor();\n rec.continuous = true;\n rec.interimResults = true;\n rec.lang = document.documentElement.lang || \"en-US\";\n let base = target.value ? `${target.value} ` : \"\";\n rec.onresult = (ev: any) => {\n let text = \"\";\n for (let i = ev.resultIndex; i < ev.results.length; i++) text += ev.results[i][0].transcript;\n target.value = (base + text).replace(/\\s+/g, \" \").trimStart();\n target.dispatchEvent(new Event(\"input\", { bubbles: true }));\n };\n rec.onerror = (ev: any) => {\n this.stopVoice();\n idle();\n this.addActivity({ kind: \"voice.error\", label: `Dictation failed: ${ev?.error ?? \"unknown\"}`, level: \"error\" });\n };\n rec.onend = () => { this.voice = null; idle(); };\n this.voice = rec;\n this.voiceTarget = target;\n try {\n rec.start();\n listening();\n } catch {\n this.voice = null;\n idle();\n }\n };\n return b;\n }\n\n private voiceTarget: HTMLTextAreaElement | null = null;\n\n private stopVoice() {\n try { this.voice?.stop(); } catch { /* already stopped */ }\n this.voice = null;\n this.voiceTarget = null;\n }\n\n /** Replies per thread, loaded lazily when a card is expanded. */\n private messages = new Map<string, ThreadMessage[]>();\n /** Reply drafts, kept out of the render path so the textarea keeps focus. */\n private msgDrafts = new Map<string, string>();\n /** Optimistic replies awaiting the store. */\n private msgPending = new Set<string>();\n /** Optimistic replies the store rejected — offered for retry rather than lost. */\n private msgFailed = new Set<string>();\n private msgErr = new Map<string, string>();\n\n /**\n * The conversation: the replies, a reply box, the activity timeline and the copy\n * actions. Loaded lazily — a list of twenty cards should not fire twenty requests.\n */\n private conversationView(c: Comment): HTMLElement {\n const wrap = el(\"div\", \"convo\");\n const replies = this.messages.get(c.id);\n\n if (replies === undefined) {\n wrap.appendChild(el(\"div\", \"convo-loading\", \"Loading conversation…\"));\n return wrap;\n }\n\n const asRows = replies.map((m) => ({\n at: m.createdAt, authorName: m.author.name, body: m.body, fromAgent: m.author.type === \"agent\",\n }));\n const conversation = threadConversation(c, replies);\n\n const list = el(\"div\", \"msgs\");\n for (const m of conversation) {\n const fromAgent = m.author.type === \"agent\";\n const state = this.msgPending.has(m.id) ? \" pending\" : this.msgFailed.has(m.id) ? \" failed\" : \"\";\n const row = el(\"div\", \"msg\" + (fromAgent ? \" agent\" : \"\") + state);\n const initials = (m.author.name || \"?\").trim().slice(0, 1).toUpperCase();\n const head = el(\"div\", \"msg-head\");\n head.append(\n el(\"span\", \"msg-av\" + (fromAgent ? \" agent\" : \"\"), initials),\n el(\"b\", \"msg-name\", m.author.name),\n el(\"span\", \"msg-when\", fmtAgo(m.createdAt)),\n );\n (head.lastElementChild as HTMLElement).title = this.fmtWhen(m.createdAt);\n if (fromAgent) head.appendChild(el(\"span\", \"msg-tag\", \"agent\"));\n if (m.origin) head.appendChild(el(\"span\", \"msg-tag origin\", `from ${m.origin.projectName || m.origin.projectId}`));\n // The body is rendered as segments so a mentioned name is highlightable — and\n // so the highlight lands on the right occurrence rather than the first.\n const body = el(\"div\", \"msg-body\");\n for (const seg of mentionSegments(m.body, parseMentions(m.body))) {\n if (seg.mention) body.appendChild(el(\"span\", \"mention\", seg.text));\n else body.appendChild(document.createTextNode(seg.text));\n }\n row.append(head, body);\n\n // Reaction pills. The picker is a popup rather than an always-visible row of six\n // emoji, because a permanent picker under every message is visual noise for a\n // thing most people do occasionally.\n const pills = el(\"div\", \"rxns\");\n for (const r of summarizeReactions(this.reactionsOf(c.id, m.id), this.cfg.user.id)) {\n const pill = el(\"button\", \"rxn\" + (r.mine ? \" mine\" : \"\")) as HTMLButtonElement;\n pill.append(document.createTextNode(r.emoji), el(\"span\", \"rxn-n\", String(r.count)));\n pill.title = r.users.join(\", \");\n pill.onclick = (e) => { e.stopPropagation(); void this.react(c, m.id, r.emoji); };\n pills.appendChild(pill);\n }\n const add = el(\"button\", \"rxn-add\", \"+\") as HTMLButtonElement;\n add.title = \"Add a reaction\";\n add.onclick = (e) => {\n e.stopPropagation();\n const open = pills.querySelector(\".rxn-pick\");\n pills.querySelectorAll(\".rxn-pick\").forEach((n) => n.remove());\n if (open) return;\n const pick = el(\"div\", \"rxn-pick\");\n for (const emoji of REACTION_CHOICES) {\n const b = el(\"button\", \"rxn-opt\", emoji) as HTMLButtonElement;\n b.onclick = (ev) => { ev.stopPropagation(); void this.react(c, m.id, emoji); };\n pick.appendChild(b);\n }\n pills.appendChild(pick);\n };\n pills.appendChild(add);\n row.appendChild(pills);\n\n // A message's own attachments, inline. Images and video only — the accept list\n // already limits the picker, and anything else would have no way to render.\n if (m.attachments?.length) {\n const strip = el(\"div\", \"msg-atts\");\n for (const a of m.attachments) {\n if (a.kind === \"image\") {\n const img = el(\"img\", \"msg-att\") as HTMLImageElement;\n img.src = a.url;\n img.alt = a.name ?? \"attachment\";\n img.loading = \"lazy\";\n img.onclick = (e) => { e.stopPropagation(); window.open(a.url, \"_blank\", \"noopener\"); };\n strip.appendChild(img);\n } else if (a.kind === \"video\") {\n const video = el(\"video\", \"msg-att\") as HTMLVideoElement;\n video.src = a.url;\n video.controls = true;\n video.preload = \"metadata\";\n video.onclick = (e) => e.stopPropagation();\n strip.appendChild(video);\n }\n }\n if (strip.childElementCount) row.appendChild(strip);\n }\n\n if (this.msgPending.has(m.id)) row.appendChild(el(\"div\", \"msg-state\", \"Sending…\"));\n if (this.msgFailed.has(m.id)) {\n const failed = el(\"div\", \"msg-state failed\");\n failed.append(document.createTextNode(this.msgErr.get(m.id) ?? \"Could not send.\"));\n const retry = el(\"button\", \"msg-retry\", \"Retry\") as HTMLButtonElement;\n retry.onclick = (e) => { e.stopPropagation(); void this.resend(c, m.id); };\n failed.appendChild(retry);\n row.appendChild(failed);\n }\n list.appendChild(row);\n }\n wrap.appendChild(list);\n\n // ---- reply box ---------------------------------------------------------\n const reply = el(\"div\", \"reply\");\n const input = el(\"textarea\", \"reply-in\") as HTMLTextAreaElement;\n input.rows = 2;\n input.placeholder = \"Reply… use @ to mention\";\n input.value = this.msgDrafts.get(c.id) ?? \"\";\n // Typing must not re-render, or the caret jumps on every keystroke.\n input.oninput = () => this.msgDrafts.set(c.id, input.value);\n input.addEventListener(\"click\", (e) => e.stopPropagation());\n input.onkeydown = (e) => {\n // Enter sends; Shift+Enter is a newline. Attachments ride along.\n if (e.key === \"Enter\" && !e.shiftKey) { e.preventDefault(); void this.sendReply(c, input.value, [...pending]); }\n };\n const foot = el(\"div\", \"reply-foot\");\n const send = el(\"button\", \"reply-send\", \"➤ Send\") as HTMLButtonElement;\n send.setAttribute(\"aria-label\", \"Send reply\");\n send.onclick = (e) => { e.stopPropagation(); void this.sendReply(c, input.value, [...pending]); };\n // Attachments on a reply, through the same blob seam the comment form uses.\n const fileIn = el(\"input\") as HTMLInputElement;\n fileIn.type = \"file\";\n fileIn.multiple = true;\n fileIn.accept = \"image/*,video/*\";\n fileIn.style.display = \"none\";\n const attachBtn = el(\"button\", \"reply-attach\", \"📎\") as HTMLButtonElement;\n attachBtn.title = \"Attach an image or video\";\n attachBtn.setAttribute(\"aria-label\", \"Attach a file\");\n attachBtn.onclick = (e) => { e.stopPropagation(); fileIn.click(); };\n const pending: File[] = [];\n const chips = el(\"div\", \"reply-chips\");\n const repaintChips = () => {\n chips.textContent = \"\";\n pending.forEach((f, i) => {\n const chip = el(\"span\", \"chip\", `${attachmentKind(f.type) === \"video\" ? \"🎬\" : \"🖼\"} ${f.name}`);\n const x = el(\"button\", \"chip-x\", \"✕\") as HTMLButtonElement;\n x.title = \"Remove\";\n x.onclick = (ev) => { ev.stopPropagation(); pending.splice(i, 1); repaintChips(); };\n chip.appendChild(x);\n chips.appendChild(chip);\n });\n };\n fileIn.onchange = () => {\n for (const f of Array.from(fileIn.files ?? [])) {\n const cap = attachmentKind(f.type) === \"video\" ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES;\n if (f.size > cap) {\n this.addActivity({ kind: \"error\", level: \"error\", label: `${f.name} is too large to attach` });\n continue;\n }\n pending.push(f);\n }\n fileIn.value = \"\";\n repaintChips();\n };\n // Typing and the picker must not bubble into the card's own click handling.\n chips.addEventListener(\"click\", (e) => e.stopPropagation());\n foot.append(el(\"span\", \"reply-hint\", \"@ to mention\"), attachBtn, send);\n // Autocomplete: shown while a handle is being typed, hidden otherwise. The list is\n // replaced in place rather than re-rendering the card, so the caret never moves.\n const suggest = el(\"div\", \"mention-list\");\n suggest.style.display = \"none\";\n const refreshSuggestions = () => {\n const matches = mentionSuggestions(input.value, input.selectionStart ?? input.value.length, this.people.get(this.cfg.projectKey) ?? []);\n suggest.textContent = \"\";\n if (!matches.length) { suggest.style.display = \"none\"; return; }\n suggest.style.display = \"\";\n for (const person of matches) {\n const b = el(\"button\", \"mention-pick\", person.name) as HTMLButtonElement;\n b.onclick = (e) => {\n e.stopPropagation();\n const before = input.value.slice(0, input.selectionStart ?? input.value.length);\n const at = before.lastIndexOf(\"@\");\n const after = input.value.slice(input.selectionStart ?? input.value.length);\n // Insert the squashed name so it resolves against the same person later.\n input.value = `${before.slice(0, at)}@${person.name.replace(/\\s+/g, \"\")} ${after}`;\n this.msgDrafts.set(c.id, input.value);\n suggest.style.display = \"none\";\n input.focus();\n };\n suggest.appendChild(b);\n }\n };\n input.oninput = () => { this.msgDrafts.set(c.id, input.value); refreshSuggestions(); };\n input.onkeyup = () => refreshSuggestions();\n input.onblur = () => setTimeout(() => { suggest.style.display = \"none\"; }, 150);\n reply.append(input, suggest, chips, fileIn, foot);\n wrap.appendChild(reply);\n\n // ---- timeline ----------------------------------------------------------\n const timeline = threadTimeline(c, asRows);\n const tl = el(\"div\", \"tl\");\n tl.appendChild(el(\"div\", \"tl-h\", \"Activity\"));\n for (const entry of timeline) {\n const item = el(\"div\", `tl-i tl-${entry.kind}`);\n item.append(el(\"span\", \"tl-dot\"), el(\"span\", \"tl-l\", entry.label));\n if (entry.detail) item.appendChild(el(\"span\", \"tl-d\", entry.detail));\n tl.appendChild(item);\n }\n wrap.appendChild(tl);\n\n // ---- copy --------------------------------------------------------------\n const copyRow = el(\"div\", \"copyrow\");\n const copyTextBtn = el(\"button\", \"copy-b\", \"Copy thread text\") as HTMLButtonElement;\n copyTextBtn.onclick = (e) => {\n e.stopPropagation();\n const text = threadAsText(\n {\n id: c.id, body: c.body, title: c.title, url: c.url, status: c.status, createdAt: c.createdAt,\n kind: c.kind, anchor: { tag: c.anchor?.tag, selector: c.anchor?.cssPath },\n proposal: c.proposal, pr: c.pr,\n },\n asRows,\n );\n void this.copyText(copyTextBtn, text);\n };\n const copyImagesBtn = el(\"button\", \"copy-b\", \"Copy images\") as HTMLButtonElement;\n copyImagesBtn.onclick = (e) => { e.stopPropagation(); void this.copyImages(copyImagesBtn, c); };\n copyRow.append(copyTextBtn, copyImagesBtn);\n wrap.appendChild(copyRow);\n\n return wrap;\n }\n\n /** Other people on this page. Empty unless a bridge is configured. */\n private peers: Peer[] = [];\n private peerId?: string;\n private peerEl!: HTMLElement;\n private peerTimer?: ReturnType<typeof setInterval>;\n\n /**\n * Join, then keep talking.\n *\n * Presence is a heartbeat, not a flag, because a browser that is closed or crashes\n * sends no goodbye. The bridge expires anything silent past the TTL, and the panel\n * re-joins on a 404 rather than assuming it is still known.\n */\n private startPresence() {\n const bridge = this.cfg.bridge;\n if (!bridge) return;\n const base = bridge.replace(/\\/$/, \"\");\n const pageUrl = location.pathname + location.search;\n\n const tick = async () => {\n try {\n if (!this.peerId) {\n const res = await fetch(`${base}/presence`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ url: pageUrl, userId: this.cfg.user.id, name: this.cfg.user.name }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as { peer?: Peer };\n this.peerId = data.peer?.id;\n } else {\n const res = await fetch(`${base}/presence/${encodeURIComponent(this.peerId)}/heartbeat`, { method: \"POST\" });\n // The bridge forgot us (it restarted, or we were swept). Re-join rather than\n // beating forever against an id it does not know.\n if (res.status === 404) this.peerId = undefined;\n }\n const listed = await fetch(\n `${base}/presence?url=${encodeURIComponent(pageUrl)}&viewer=${encodeURIComponent(this.peerId ?? \"\")}`,\n );\n if (listed.ok) {\n const data = (await listed.json()) as { peers?: Peer[] };\n this.peers = Array.isArray(data.peers) ? data.peers : [];\n this.renderPeers();\n }\n } catch {\n // A bridge that went away is not an error worth surfacing; the list empties.\n this.peers = [];\n this.renderPeers();\n }\n };\n\n void tick();\n this.peerTimer = setInterval(() => void tick(), PEER_HEARTBEAT_MS);\n }\n\n private renderPeers() {\n if (!this.peerEl) return;\n this.peerEl.textContent = \"\";\n if (!this.peers.length) { this.peerEl.style.display = \"none\"; return; }\n this.peerEl.style.display = \"\";\n for (const p of this.peers.slice(0, 4)) {\n const av = el(\"span\", \"peer-av\", initialsOf(p.name));\n av.title = `${p.name} is on this page`;\n this.peerEl.appendChild(av);\n }\n if (this.peers.length > 4) this.peerEl.appendChild(el(\"span\", \"peer-more\", `+${this.peers.length - 4}`));\n }\n\n private stopPresence() {\n if (this.peerTimer) clearInterval(this.peerTimer);\n this.peerTimer = undefined;\n // Best-effort goodbye; the TTL covers us if this never lands.\n if (this.cfg.bridge && this.peerId) {\n const base = this.cfg.bridge.replace(/\\/$/, \"\");\n void fetch(`${base}/presence/${encodeURIComponent(this.peerId)}`, { method: \"DELETE\", keepalive: true }).catch(() => {});\n }\n this.peerId = undefined;\n this.peers = [];\n }\n\n private liveSource?: EventSource;\n\n /**\n * Follow the bridge's thread channel while the panel is open.\n *\n * The SSE channel lives in the MCP process, so a reply posted by anyone — an agent, a\n * teammate's browser — arrives here rather than being discovered by the 4 s list\n * poll. Only the threads whose messages are already loaded are refetched: pulling a\n * conversation nobody has open would be work for nothing.\n */\n private startLiveThreads() {\n const bridge = this.cfg.bridge;\n if (!bridge || this.liveSource) return;\n // Absent in some test environments; the poll still covers us if it is.\n if (typeof EventSource === \"undefined\") return;\n try {\n const source = new EventSource(`${bridge.replace(/\\/$/, \"\")}/thread-updates`);\n // Named event: the bridge writes `event: thread`, so `onmessage` never fires.\n source.addEventListener(\"thread\", (ev) => {\n let parsed: any;\n try { parsed = JSON.parse((ev as MessageEvent).data); } catch { return; }\n if (!parsed || typeof parsed.threadId !== \"string\") return;\n if (!this.messages.has(parsed.threadId)) return;\n void this.refreshMessages(parsed.threadId);\n });\n // The browser reconnects on its own; a dead bridge is not worth surfacing.\n source.onerror = () => {};\n this.liveSource = source;\n } catch {\n // EventSource construction can throw on a malformed URL — never fatal.\n }\n }\n\n /** Re-read one thread's replies, replacing the cache. */\n private async refreshMessages(threadId: string) {\n try {\n const list = await this.store.listMessages(threadId);\n if (!Array.isArray(list)) return;\n this.messages.set(threadId, list);\n this.renderList();\n } catch {\n // Leave what is on screen; the next poll or event will try again.\n }\n }\n\n /** Reactions per thread, keyed `${threadId}:${messageId}`, so a re-render is free. */\n private reactions = new Map<string, Reaction[]>();\n\n private reactionsOf(threadId: string, messageId: string): Reaction[] {\n return this.reactions.get(`${threadId}:${messageId}`) ?? [];\n }\n\n /**\n * Toggle a reaction.\n *\n * Optimistic, then replaced by the server's own set: the server returns the whole\n * list precisely so the count can never drift from what was stored.\n */\n private async react(c: Comment, messageId: string, emoji: string) {\n const key = `${c.id}:${messageId}`;\n const before = this.reactionsOf(c.id, messageId);\n this.reactions.set(key, toggleReaction(before, {\n messageId, emoji, userId: this.cfg.user.id, userName: this.cfg.user.name,\n }));\n this.renderList();\n try {\n const next = await this.store.toggleReaction({\n threadId: c.id, messageId, emoji, userId: this.cfg.user.id, userName: this.cfg.user.name,\n });\n this.reactions.set(key, Array.isArray(next) ? next : this.reactionsOf(c.id, messageId));\n } catch {\n // Put it back rather than showing a reaction that did not save.\n this.reactions.set(key, before);\n }\n this.renderList();\n }\n\n /** Everyone who has taken part, for mention autocomplete. Fetched once. */\n private people = new Map<string, { id: string; name: string; email?: string }[]>();\n\n private async loadPeople() {\n if (this.people.has(this.cfg.projectKey)) return;\n try {\n this.people.set(this.cfg.projectKey, await this.store.listPeople(this.cfg.projectKey));\n } catch {\n this.people.set(this.cfg.projectKey, []);\n }\n }\n\n /** Fetch replies once, when a card is first expanded. */\n private async loadMessages(c: Comment) {\n if (this.messages.has(c.id)) return;\n // A mention needs the people list; fetch it alongside the first thread opened.\n void this.loadPeople();\n // Reactions are secondary — a failure to load them must not cost us the thread.\n void this.store.listReactions(c.id).then((all) => {\n if (!Array.isArray(all)) return;\n for (const r of all) {\n const key = `${c.id}:${r.messageId}`;\n const list = this.reactions.get(key) ?? [];\n if (!list.some((x) => x.userId === r.userId && x.emoji === r.emoji)) list.push(r);\n this.reactions.set(key, list);\n }\n this.renderList();\n }).catch(() => {});\n try {\n this.messages.set(c.id, await this.store.listMessages(c.id));\n } catch {\n this.messages.set(c.id, []);\n }\n this.renderList();\n }\n\n /**\n * Post a reply, optimistically.\n *\n * The row appears immediately; if the store rejects it the row stays with a Retry,\n * because losing what someone typed is worse than showing a failed row.\n */\n private async sendReply(c: Comment, raw: string, files: File[] = []) {\n const body = raw.trim();\n // A reply with only an attachment is still a reply; one with neither is not.\n if (!body && !files.length) return;\n const author: ThreadAuthor = {\n id: this.cfg.user.id, name: this.cfg.user.name, email: this.cfg.user.email, type: \"user\",\n };\n // Uploaded before the optimistic row renders, so the row shows the real URLs and\n // never has to be patched once the blobs land.\n const attachments = files.length ? await this.uploadAttachments(files) : undefined;\n const optimistic: ThreadMessage = {\n id: `pending-${Date.now().toString(36)}`, threadId: c.id, author, body,\n attachments, createdAt: new Date().toISOString(),\n };\n this.messages.set(c.id, [...(this.messages.get(c.id) ?? []), optimistic]);\n this.msgPending.add(optimistic.id);\n this.msgDrafts.delete(c.id);\n this.renderList();\n\n try {\n const saved = await this.store.addMessage(c.id, { author, body, attachments });\n this.messages.set(c.id, (this.messages.get(c.id) ?? []).map((m) => (m.id === optimistic.id ? saved : m)));\n this.msgPending.delete(optimistic.id);\n this.addActivity({ kind: \"message.create\", label: `Replied on “${c.title || body.slice(0, 40)}”` });\n } catch (e) {\n this.msgPending.delete(optimistic.id);\n this.msgFailed.add(optimistic.id);\n this.msgErr.set(optimistic.id, e instanceof Error ? e.message : \"Could not send.\");\n }\n this.renderList();\n }\n\n /** Try a failed optimistic reply again, in place. */\n private async resend(c: Comment, id: string) {\n const found = (this.messages.get(c.id) ?? []).find((m) => m.id === id);\n if (!found) return;\n this.msgFailed.delete(id);\n this.msgErr.delete(id);\n this.msgPending.add(id);\n this.renderList();\n try {\n const saved = await this.store.addMessage(c.id, { author: found.author, body: found.body });\n this.messages.set(c.id, (this.messages.get(c.id) ?? []).map((m) => (m.id === id ? saved : m)));\n this.msgPending.delete(id);\n } catch (e) {\n this.msgPending.delete(id);\n this.msgFailed.add(id);\n this.msgErr.set(id, e instanceof Error ? e.message : \"Could not send.\");\n }\n this.renderList();\n }\n\n /** Copy text, and say so — silence looks like a no-op. */\n private async copyText(button: HTMLButtonElement, text: string) {\n const original = button.textContent;\n try {\n if (!navigator.clipboard?.writeText) throw new Error(\"clipboard unavailable\");\n await navigator.clipboard.writeText(text);\n button.textContent = \"Copied ✓\";\n } catch {\n button.textContent = \"Copy failed\";\n }\n setTimeout(() => { button.textContent = original; }, 1500);\n }\n\n /**\n * Copy the captured images. Best-effort and reported as such: an image clipboard\n * write needs a secure context and a user gesture, and a silent failure would look\n * like it worked.\n */\n private async copyImages(button: HTMLButtonElement, c: Comment) {\n const original = button.textContent;\n const sources = [c.screenshot, ...(c.attachments ?? []).filter((a) => a.kind === \"image\").map((a) => a.url)]\n .filter((s): s is string => !!s);\n if (!sources.length) {\n button.textContent = \"No images\";\n setTimeout(() => { button.textContent = original; }, 1500);\n return;\n }\n try {\n const blobs = await Promise.all(sources.slice(0, 4).map(async (src) => (await fetch(src)).blob()));\n const items: Record<string, Blob> = {};\n blobs.forEach((blob, i) => { items[i === 0 ? \"image/png\" : `image/png-${i}`] = blob; });\n await (navigator.clipboard as any).write([new (window as any).ClipboardItem(items)]);\n button.textContent = \"Copied ✓\";\n } catch {\n button.textContent = \"Copy failed\";\n }\n setTimeout(() => { button.textContent = original; }, 1500);\n }\n\n private flash(id: string) {\n const c = this.comments.find((x) => x.id === id);\n const pin = this.pins.get(id);\n\n if (c?.kind === \"free\") {\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin?.classList.add(\"active\");\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n window.scrollTo({\n top: Math.max(0, c.offset.y * docH - window.innerHeight / 2),\n left: Math.max(0, c.offset.x * docW - window.innerWidth / 2),\n behavior: \"smooth\",\n });\n this.position();\n return;\n }\n\n if (c?.kind === \"region\" && c.region) {\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin?.classList.add(\"active\");\n // Show the outline, keep it tracking scroll, then fade it out.\n this.activeRegionId = id;\n window.clearTimeout(this.regionTimer);\n this.regionTimer = window.setTimeout(() => {\n this.activeRegionId = null;\n this.regionBox.style.display = \"none\";\n }, 2400);\n // Scroll to the anchor element when we have it (correct across reflow),\n // otherwise to the stored document position.\n const elx = this.resolved.get(id);\n if (elx) elx.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n else window.scrollTo({ top: Math.max(0, c.region.y - 120), left: Math.max(0, c.region.x - 120), behavior: \"smooth\" });\n this.position();\n return;\n }\n\n if (!pin || pin.classList.contains(\"detached\")) return;\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin.classList.add(\"active\");\n const elx = this.resolved.get(id);\n if (elx) elx.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n }\n\n /** Absolute timestamp in the host's configured time zone and locale (see `LoupeConfig.timeZone`). */\n private fmtWhen(iso: string): string {\n return fmtAbsolute(iso, this.cfg.locale, this.cfg.timeZone);\n }\n\n /**\n * \" · package v0.11.0\", flagged, when the host's package version differs from this\n * bundle's. The two agree on a healthy install; they differ exactly when the\n * package was upgraded but its published JS was not — the trap this makes visible.\n */\n private packageVersionNote(): string {\n const pkg = (this.cfg.packageVersion ?? \"\").trim().replace(/^v/i, \"\");\n if (!pkg || pkg === SDK_VERSION) return \"\";\n const why = `This widget bundle is v${SDK_VERSION} but the installed package is v${pkg}. ` +\n `Re-publish the package assets so the served bundle matches.`;\n return ` · <span class=\"ver-stale\" title=\"${escapeAttr(why)}\">package v${escapeHtml(pkg)}</span>`;\n }\n\n destroy() {\n this.liveSource?.close();\n this.liveSource = undefined;\n this.companionSource?.close();\n this.companionSource = undefined;\n if (this.companionPoll) clearInterval(this.companionPoll);\n if (this.activityPoll) clearInterval(this.activityPoll);\n this.activityPoll = undefined;\n if (this.syncPoll) clearInterval(this.syncPoll);\n this.syncPoll = undefined;\n document.removeEventListener(\"visibilitychange\", this.onSyncVisible);\n this.stopVoice();\n this.stopPresence();\n this.stopRecording?.();\n this.setMode(\"off\");\n this.mo?.disconnect();\n if (this.tick) clearInterval(this.tick);\n window.clearTimeout(this.regionTimer);\n window.removeEventListener(\"resize\", this.onWinResize);\n window.removeEventListener(\"pointermove\", this.onHeadPointerMove);\n window.removeEventListener(\"pointerup\", this.onHeadPointerUp);\n window.removeEventListener(\"pointermove\", this.onResizeMove);\n window.removeEventListener(\"pointerup\", this.onResizeUp);\n window.removeEventListener(\"pointermove\", this.onFabPointerMove);\n window.removeEventListener(\"pointerup\", this.onFabPointerUp);\n window.removeEventListener(\"pointercancel\", this.onFabPointerUp);\n window.clearTimeout(this.toastTimer);\n document.removeEventListener(\"keydown\", this.onLauncherKey);\n document.removeEventListener(\"click\", this.onDocumentClick, true);\n document.removeEventListener(\"keydown\", this.onMenuKey);\n document.removeEventListener(\"keydown\", this.onKey, true);\n // Release the page-push margins we set for docked modes.\n const de = document.documentElement;\n de.style.marginLeft = de.style.marginRight = de.style.marginBottom = \"\";\n this.root?.remove();\n }\n}\n\n// ---- tiny DOM helpers -------------------------------------------------------\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, cls = \"\", text = \"\"): HTMLElementTagNameMap[K] {\n const n = document.createElement(tag);\n if (cls) n.className = cls;\n if (text) n.textContent = text;\n return n;\n}\nfunction clamp(n: number) { return Math.max(0, Math.min(1, n)); }\n/** \"just now\" / \"3m ago\" / \"2d ago\" for the Home feed. */\nfunction fmtAgo(iso: string): string {\n const then = Date.parse(iso);\n if (Number.isNaN(then)) return \"\";\n const s = Math.max(0, Math.round((Date.now() - then) / 1000));\n if (s < 60) return \"just now\";\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\nlet warnedBadTimeZone = false;\n/**\n * \"4 Oct 2026, 3:42 PM\" — the absolute form, in the given zone and locale (both\n * optional: the browser's by default). An unknown zone or locale falls back to the\n * browser's and says so once, rather than throwing out of a render: a wrong clock\n * is recoverable, a panel that never paints is not.\n */\nfunction fmtAbsolute(iso: string, locale?: string, timeZone?: string): string {\n const t = Date.parse(iso);\n if (Number.isNaN(t)) return \"\";\n const opts: Intl.DateTimeFormatOptions = {\n day: \"numeric\", month: \"short\", year: \"numeric\", hour: \"numeric\", minute: \"2-digit\",\n };\n try {\n return new Intl.DateTimeFormat(locale || undefined, { ...opts, timeZone: timeZone || undefined }).format(t);\n } catch (err) {\n if (!warnedBadTimeZone) {\n warnedBadTimeZone = true;\n console.warn(`[loupe] unusable timeZone/locale (${timeZone ?? \"-\"} / ${locale ?? \"-\"}); using the browser's`, err);\n }\n return new Intl.DateTimeFormat(undefined, opts).format(t);\n }\n}\n/** \"https://x.test/a/b?q=1\" → \"/a/b\" — what the page-path tag shows. */\nfunction shortPath(url: string): string {\n try { return new URL(url, location.origin).pathname || \"/\"; } catch { return url; }\n}\n/**\n * Validate and normalize an environment URL. Only absolute http(s) URLs qualify —\n * a bare \"staging.example.com\" is a typo, not an environment, and normalizing away\n * a trailing slash keeps two spellings of the same place from both being listed.\n */\nfunction normalizeEnvUrl(raw: string): string | null {\n const s = raw.trim();\n if (!s) return null;\n try {\n const u = new URL(s);\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return null;\n if (!u.hostname) return null;\n const path = u.pathname.replace(/\\/+$/, \"\");\n return u.origin + path;\n } catch {\n return null;\n }\n}\n/** The day bucket a comment falls in, for the All-scope timeline grouping. */\nfunction dayLabel(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"Earlier\";\n const today = new Date();\n const startOf = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const days = Math.round((startOf(today) - startOf(d)) / 86_400_000);\n if (days <= 0) return \"Today\";\n if (days === 1) return \"Yesterday\";\n if (days < 7) return `${days} days ago`;\n return d.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n}\nfunction clampPx(n: number, min: number, max: number) { return Math.max(min, Math.min(max, n)); }\n/** An `<option>`. Built as an element rather than `new Option(...)`, which some\n * DOM implementations (and the test environment) do not provide. */\nfunction optionEl(text: string, value: string, selected: boolean): HTMLOptionElement {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = text;\n o.selected = selected;\n return o;\n}\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (m) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[m]!));\n}\n/** Escape for a double-quoted attribute value (escapeHtml already covers the rest). */\nfunction escapeAttr(s: string): string {\n return escapeHtml(s);\n}\n\n// ---- inline icons (font-independent, currentColor) --------------------------\n\nconst svg = (inner: string) =>\n `<svg viewBox=\"0 0 16 16\" width=\"15\" height=\"15\" fill=\"none\" aria-hidden=\"true\">${inner}</svg>`;\nconst DOCK_FRAME = `<rect x=\"1.5\" y=\"2.5\" width=\"13\" height=\"11\" rx=\"1.6\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`;\nconst I_DOCK_LEFT = svg(`${DOCK_FRAME}<rect x=\"2.2\" y=\"3.2\" width=\"4\" height=\"9.6\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_DOCK_RIGHT = svg(`${DOCK_FRAME}<rect x=\"9.8\" y=\"3.2\" width=\"4\" height=\"9.6\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_DOCK_BOTTOM = svg(`${DOCK_FRAME}<rect x=\"2.2\" y=\"9\" width=\"11.6\" height=\"3.8\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_FLOAT = svg(\n `<rect x=\"2.5\" y=\"3.5\" width=\"11\" height=\"9\" rx=\"1.6\" stroke=\"currentColor\" stroke-width=\"1.3\"/>` +\n `<path d=\"M2.5 6.1h11\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`);\nconst I_SUN = svg(\n `<circle cx=\"8\" cy=\"8\" r=\"3\" stroke=\"currentColor\" stroke-width=\"1.3\"/>` +\n `<g stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\">` +\n `<path d=\"M8 1.4v1.7\"/><path d=\"M8 12.9v1.7\"/><path d=\"M1.4 8h1.7\"/><path d=\"M12.9 8h1.7\"/>` +\n `<path d=\"M3.3 3.3l1.2 1.2\"/><path d=\"M11.5 11.5l1.2 1.2\"/><path d=\"M12.7 3.3l-1.2 1.2\"/><path d=\"M4.5 11.5l-1.2 1.2\"/></g>`);\nconst I_MOON = svg(\n `<path d=\"M13 9.4A5.3 5.3 0 1 1 6.6 3 4.3 4.3 0 0 0 13 9.4z\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linejoin=\"round\"/>`);\nconst I_CLOSE = svg(\n `<path d=\"M4.2 4.2l7.6 7.6M11.8 4.2l-7.6 7.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>`);\nconst I_GEAR = svg(\n `<circle cx=\"8\" cy=\"8\" r=\"2.2\" stroke=\"currentColor\" stroke-width=\"1.4\"/>` +\n `<path d=\"M8 1.6v1.5M8 12.9v1.5M1.6 8h1.5M12.9 8h1.5M3.5 3.5l1.1 1.1M11.4 11.4l1.1 1.1M12.5 3.5l-1.1 1.1M4.6 11.4l-1.1 1.1\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/>`);\nconst I_MINIMIZE = svg(\n `<path d=\"M3.5 8h9\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/>`);\n\n/** FAB cluster quick-action icons (font-independent, currentColor). */\nconst I_COMMENT = svg(\n `<path d=\"M2 3.1h12v7.4H6.5l-3.3 2.6v-2.6H2z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M8 5.1v3.4M6.3 6.8h3.4\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>`);\n/** A sticky note for the \"Note\" quick action — deliberately unlike the comment bubble. */\nconst I_NOTE = svg(\n `<path d=\"M2.6 2.6h10.8v7.2l-3.6 3.6H2.6z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M13.4 9.8h-3.6v3.6\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>`);\nconst I_EYE = svg(\n `<path d=\"M1.4 8S3.9 4 8 4s6.6 4 6.6 4-2.5 4-6.6 4S1.4 8 1.4 8z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<circle cx=\"8\" cy=\"8\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`);\nconst I_PLUG = svg(\n `<path d=\"M6 1.8v3.1M10 1.8v3.1\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>` +\n `<path d=\"M4.4 4.9h7.2v2.3a3.6 3.6 0 0 1-7.2 0z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M8 10.8v3.4\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>`);\n/** Points up when collapsed, flips down (via CSS) when the actions are out. */\nconst I_EYE_OFF = svg(\n `<path d=\"M2 2l12 12M6.6 6.7A2 2 0 0 0 9.3 9.4M4.3 4.5C2.9 5.4 1.9 6.7 1.5 8c1.1 3 3.7 5 6.5 5 1.3 0 2.5-.4 3.6-1.1M6.9 3.2C7.3 3.1 7.6 3 8 3c2.8 0 5.4 2 6.5 5-.3.8-.8 1.6-1.4 2.3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`,\n);\nconst I_FAB_CHEVRON =\n `<span class=\"lchev\">${svg(`<path d=\"M4.4 9.6 8 6l3.6 3.6\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`)}</span>`;\n\n/** Dashed marquee icon for the \"Region\" button — inline SVG so it never depends on a font. */\nconst REGION_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-dasharray=\"2.4 1.8\"/>` +\n `</svg>`;\n\n/** Speech-bubble icon for the free-\"Note\" button. */\nconst NOTE_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<path d=\"M2 2.5h11v7.5H6l-3 2.5v-2.5H2z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `</svg>`;\n\n/** Camera/record icon for the \"Record\" button — dashed marquee with a record dot. */\nconst RECORD_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-dasharray=\"2.4 1.8\"/>` +\n `<circle cx=\"7.5\" cy=\"7.5\" r=\"2.4\" fill=\"currentColor\"/>` +\n `</svg>`;\n\n/** Video icon for the \"Video\" button — attach a screen recording made on the phone. */\nconst VIDEO_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\"/>` +\n `<path d=\"M6.3 5.5l3.9 2.2-3.9 2.2z\" fill=\"currentColor\"/>` +\n `</svg>`;\n\n// ---- integration icons (brand marks for the \"Integrates with\" footer) -------\nconst I_GITHUB =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M8 .2a8 8 0 0 0-2.5 15.6c.4.07.55-.17.55-.38v-1.3c-2.2.48-2.67-1.07-2.67-1.07-.36-.92-.88-1.16-.88-1.16-.72-.5.05-.48.05-.48.8.056 1.22.82 1.22.82.71 1.22 1.87.87 2.33.66.07-.52.28-.87.5-1.07-1.76-.2-3.6-.88-3.6-3.9 0-.86.3-1.57.82-2.12-.08-.2-.36-1 .08-2.1 0 0 .67-.21 2.2.8a7.6 7.6 0 0 1 4 0c1.53-1.02 2.2-.8 2.2-.8.44 1.1.16 1.9.08 2.1.5.55.82 1.26.82 2.12 0 3.03-1.85 3.7-3.61 3.9.28.24.54.72.54 1.46v2.16c0 .21.14.46.55.38A8 8 0 0 0 8 .2z\"/>` +\n `</svg>`;\nconst I_SLACK =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M3.4 10.1a1.6 1.6 0 1 1-1.6-1.6h1.6v1.6zm.8 0a1.6 1.6 0 0 1 3.2 0v4a1.6 1.6 0 1 1-3.2 0v-4zM5.8 3.4a1.6 1.6 0 1 1 1.6-1.6v1.6H5.8zm0 .8a1.6 1.6 0 0 1 0 3.2h-4a1.6 1.6 0 1 1 0-3.2h4zm6.7 1.6a1.6 1.6 0 1 1 1.6 1.6h-1.6V5.8zm-.8 0a1.6 1.6 0 0 1-3.2 0v-4a1.6 1.6 0 1 1 3.2 0v4zm-1.6 6.7a1.6 1.6 0 1 1-1.6 1.6v-1.6h1.6zm0-.8a1.6 1.6 0 0 1 0-3.2h4a1.6 1.6 0 1 1 0 3.2h-4z\"/>` +\n `</svg>`;\nconst I_TELEGRAM =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0zm3.7 5.4-1.24 5.85c-.09.41-.34.51-.69.32l-1.9-1.4-.92.88c-.1.1-.19.19-.38.19l.14-1.93 3.5-3.17c.15-.13-.03-.2-.24-.07l-4.32 2.72-1.86-.58c-.4-.13-.41-.4.09-.6l7.26-2.8c.34-.12.63.08.52.6z\"/>` +\n `</svg>`;\nconst I_LINEAR =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M.6 9.2a7.4 7.4 0 0 0 6.2 6.2c.3.04.44-.33.22-.55L1.15 9a.33.33 0 0 0-.55.22zM.5 6.9c-.01.13.04.25.13.34l8.13 8.13c.09.09.21.14.34.13a7.4 7.4 0 0 0 1.3-.26c.28-.08.36-.43.15-.63L1.4 5.45c-.2-.2-.55-.13-.63.15-.12.42-.21.86-.26 1.3zM2.05 4c-.1.13-.09.32.03.44l9.48 9.48c.12.12.31.13.44.03.3-.23.58-.48.85-.75.15-.15.15-.4 0-.55L3.35 3.15a.39.39 0 0 0-.55 0c-.27.27-.52.55-.75.85zM4.5 1.9a.35.35 0 0 0-.04.53l9.11 9.11c.16.16.42.13.53-.04A7.4 7.4 0 1 0 4.5 1.9z\"/>` +\n `</svg>`;\n\n/** Synthesize an Anchor for a free page-level note so downstream (dashboard/MCP) stays happy. */\nfunction pageAnchor(point: { x: number; y: number }): Anchor {\n return {\n tag: \"page\",\n cssPath: \"page\",\n xpath: \"\",\n testid: null,\n text: \"\",\n attrs: {},\n nthOfType: 1,\n rect: { x: Math.round(point.x), y: Math.round(point.y), w: 0, h: 0 },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\n\n/** Synthesize an Anchor for a free region so downstream (dashboard/MCP) stays happy. */\nfunction regionAnchor(region: RegionRect): Anchor {\n return {\n tag: \"region\",\n cssPath: `region ${Math.round(region.w)}×${Math.round(region.h)}`,\n xpath: \"\",\n testid: null,\n text: \"\",\n attrs: {},\n nthOfType: 1,\n rect: { x: Math.round(region.x), y: Math.round(region.y), w: Math.round(region.w), h: Math.round(region.h) },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\nfunction regionNote(region: RegionRect): string {\n return `<!-- Loupe free-region annotation: ${Math.round(region.w)}×${Math.round(region.h)}px at document (${Math.round(region.x)}, ${Math.round(region.y)}). No single DOM element — see the attached screenshot. -->`;\n}\n\nfunction describe(elx: Element): string {\n const testid = elx.getAttribute(\"data-testid\") || elx.getAttribute(\"data-test\");\n const tag = elx.tagName.toLowerCase();\n if (testid) return `${tag}[data-testid=\"${testid}\"]`;\n if (elx.id) return `${tag}#${elx.id}`;\n const txt = (elx.textContent || \"\").trim().replace(/\\s+/g, \" \").slice(0, 32);\n return txt ? `${tag} · “${txt}”` : tag;\n}\n/**\n * Where a thread points, for a reader: the element's visible text or label, or its test\n * id, before any selector. The raw cssPath (`#delPanel > div:nth-of-type(3) >\n * button:nth-of-type(24)`) is the last resort, not the headline.\n */\nfunction describeAnchor(c: Comment): string {\n if (c.kind === \"free\") return \"Free note · page-level\";\n if (c.kind === \"region\" && c.region) {\n const size = `${Math.round(c.region.w)}×${Math.round(c.region.h)}`;\n if (c.anchor.tag === \"region\") return `Area ${size} · page-level`;\n // \"in\" only when the stored fractions say the area sits inside the anchor; a region\n // saved by an earlier version was anchored to whatever was under its center.\n return `Area ${size} · ${relUsable(c.region.rel) ? \"in\" : \"near\"} ${anchorLabel(c.anchor)}`;\n }\n return anchorLabel(c.anchor);\n}\nfunction anchorLabel(a: Anchor): string {\n const tag = a.tag || \"element\";\n if (a.testid) return `${tag}[data-testid=\"${a.testid}\"]`;\n const text = (a.text || \"\").replace(/\\s+/g, \" \").trim();\n if (text) return `${tag} · “${text.length > 32 ? text.slice(0, 32).trimEnd() + \"…\" : text}”`;\n const attrs = a.attrs ?? {};\n const named = attrs[\"aria-label\"] || attrs.title || attrs.placeholder || attrs.alt || attrs.name;\n if (named) return `${tag} · “${named}”`;\n return a.cssPath || tag;\n}\n\n/** How much of a region an element must cover to anchor it. */\nconst REGION_COVER_MIN = 0.6;\n\n/**\n * The nearest ancestor of `from` (itself included) whose box covers at least\n * REGION_COVER_MIN of the region. `body` and `html` never qualify: a region nothing\n * smaller contains is page-level, and says so through a synthetic anchor.\n */\nfunction regionContainer(from: Element | null, vp: RegionRect): Element | null {\n const area = vp.w * vp.h;\n if (area <= 0) return null;\n for (let n: Element | null = from; n && n !== document.body && n !== document.documentElement; n = n.parentElement) {\n const r = n.getBoundingClientRect();\n if (r.width <= 0 || r.height <= 0) continue;\n const ix = Math.max(0, Math.min(r.right, vp.x + vp.w) - Math.max(r.left, vp.x));\n const iy = Math.max(0, Math.min(r.bottom, vp.y + vp.h) - Math.max(r.top, vp.y));\n if ((ix * iy) / area >= REGION_COVER_MIN) return n;\n }\n return null;\n}\n\n/**\n * Stored fractions a region can trust: ones that keep it roughly within its anchor.\n * Regions saved before 0.11.1 anchored to the element under their center, so a\n * full-screen recording anchored to one word carries fx≈−7 and fw≈15; those place the\n * pin from document coordinates instead.\n */\nfunction relUsable(rel: RegionRect[\"rel\"]): rel is NonNullable<RegionRect[\"rel\"]> {\n if (!rel) return false;\n const lo = -1.5, hi = 2.5;\n return rel.fw > 0 && rel.fh > 0 && rel.fx > lo && rel.fy > lo && rel.fx + rel.fw < hi && rel.fy + rel.fh < hi;\n}\n\n/**\n * A comment is done only at the last stage. Normalizing first means a row still\n * carrying a legacy status (`done`) reads correctly without a data migration.\n */\nfunction isResolved(c: Comment): boolean {\n return normalizeStatus(c.status) === \"resolved\";\n}\n","import type { LoupeTab, LoupeTabContext } from \"./types.js\";\n\n/**\n * The Claude/MCP onboarding page, as a **reusable tab** rather than something the\n * panel forces on every host. Register it if you want it:\n *\n * import { init, connectTab } from \"@loupekit/sdk\";\n * init({ projectKey, user, tabs: [connectTab()] });\n *\n * It is also the worked example for `LoupeTab`: it reads only from the context it\n * is handed, and returns markup.\n */\n\nconst escapeHtml = (s: string) =>\n s.replace(/[&<>\"']/g, (m) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[m]!));\n\nexport function connectTab(): LoupeTab {\n return {\n id: \"connect\",\n label: \"Connect\",\n hint: {\n title: \"Hand it to Claude\",\n body: \"Add the MCP server to your client and it can list, read and answer this feedback — screenshot included.\",\n },\n render: (ctx: LoupeTabContext) => {\n const apiHint = ctx.apiBase ?? \"http://localhost:8787\";\n const config = JSON.stringify(\n {\n mcpServers: {\n loupe: {\n command: \"npx\",\n args: [\"-y\", \"@loupekit/mcp\"],\n env: { LOUPE_API: apiHint, LOUPE_PROJECT_KEY: ctx.projectKey, LOUPE_ADMIN_KEY: \"<your project secret>\" },\n },\n },\n },\n null,\n 2,\n );\n const steps: [string, string][] = [\n [\"Pin your feedback\", \"Use Inspect, Region, Record, or Note to leave comments right on the live app.\"],\n [\"Add the Loupe MCP server\", \"Drop this into your Claude Code config so Claude can read this project's backlog:\"],\n [\"Let Claude fix it\", \"Claude reads each comment (with the screenshot, HTML & CSS), rewrites the UI, and calls propose_change — the modified HTML/CSS then shows up for your dev team in the dashboard.\"],\n ];\n\n return (\n `<div class=\"connect-hero\">` +\n `<div class=\"chero-logo\">◎</div>` +\n `<div class=\"chero-title\">Hand your feedback to <span class=\"accentink\">Claude</span></div>` +\n `<div class=\"chero-sub\">Every pinned comment becomes an actionable, fully-contextualized task Claude Code can act on.</div>` +\n `</div>` +\n `<ol class=\"connect-steps\">` +\n steps.map(([title, body], i) =>\n `<li><div class=\"cstep-t\">${i + 1}. ${escapeHtml(title)}</div>` +\n `<div class=\"cstep-d\">${escapeHtml(body)}</div>` +\n (i === 1 ? `<pre class=\"cstep-code\">${escapeHtml(config)}</pre>` : \"\") +\n `</li>`).join(\"\") +\n `</ol>`\n );\n },\n };\n}\n","import { LoupeApp } from \"./app.js\";\nimport type { ActivityEventInput, ActivityStatus, LoupeConfig } from \"./types.js\";\n\nexport { connectTab } from \"./connect.js\";\n/** The version baked into this bundle — `Loupe.version` from a script tag. \"dev\" from source. */\nexport { SDK_VERSION as version } from \"./app.js\";\nexport type {\n LoupeConfig, LoupeUser, Comment, Anchor, RegionRect, LoupeTab, LoupeTabContext,\n LocalAiConfig, GenerateRequest, GenerateResult, AccessRequest,\n} from \"./types.js\";\nexport type {\n ActivityEvent, ActivityEventInput, ActivityStatus, ActivityLevel,\n} from \"./types.js\";\n\nlet app: LoupeApp | null = null;\n\n/**\n * Initialize Loupe on the current page. Call once, after your app knows who the\n * user is. The toolbar renders only for the identified user.\n *\n * Loupe.init({ projectKey: \"pk_live_…\", user: { id, name, email }, userHmac });\n */\nexport function init(config: LoupeConfig): void {\n if (app) return; // idempotent\n if (!config?.projectKey) { console.error(\"[loupe] init requires a projectKey\"); return; }\n if (!config.user?.id) { console.error(\"[loupe] init requires user.id\"); return; }\n // NOTE: in production the backend verifies config.userHmac before serving data.\n app = new LoupeApp(config);\n const boot = () => app!.start();\n if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", boot);\n else boot();\n}\n\n/** Tear down the toolbar and all listeners. */\nexport function destroy(): void {\n app?.destroy();\n app = null;\n}\n\n/**\n * Push one event into the panel's Activity view — the seam an agent bridge (or the\n * host application) uses to make its work visible without leaving the page.\n * Loupe's own operations feed the same stream, so the view is never empty.\n *\n * Loupe.trackActivity({ kind: \"Read\", label: \"Read src/app.ts\", files: [\"src/app.ts\"] });\n */\nexport function trackActivity(event: ActivityEventInput): void {\n app?.addActivity(event);\n}\n\n/** Set the Activity view's status dot — idle, working, or error. */\nexport function setActivityStatus(status: ActivityStatus): void {\n app?.setActivityStatus(status);\n}\n\n/** Drop everything currently in the Activity view. */\nexport function clearActivity(): void {\n app?.clearActivity();\n}\n\n/**\n * Ask the user to let an agent move the browser. **Nothing navigates here** — the\n * panel shows a prompt and only an explicit grant produces a navigation, which is\n * recorded. Use this rather than driving `location` yourself.\n */\nexport function requestNavigation(url: string, opts?: { reason?: string; requester?: string }): void {\n app?.requestNavigation(url, opts);\n}\n\n/** Store the local-AI endpoint + model the Generate pane should pass to `generate`. */\nexport function setLocalAi(config: { url: string; model: string } | null): void {\n app?.setLocalAi(config);\n}\n\n/** Arm a tool from outside the panel — e.g. a browser context menu. */\nexport function openTool(tool: \"inspect\" | \"note\"): void {\n app?.openTool(tool);\n}\n\n/**\n * Bring the collapsed launcher back after a user hid it (the quick action, the\n * Settings switch, or Alt+Shift+L). The host can wire this to its own menu item.\n */\nexport function showLauncher(): void {\n app?.showLauncher();\n}\n\n/** Hide the collapsed launcher. Persisted per browser; `showLauncher()` or Alt+Shift+L undoes it. */\nexport function hideLauncher(): void {\n app?.hideLauncher();\n}\n"],"mappings":";AACO,IAAM;AAAA;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["el","svg","el","svg","current","el","blobToDataUrl","normalizeStage","normalizeStage","current","init","uid","el","url","label","regionContainer","x","slot","W","undo","elx","escapeHtml","requestNavigation"]}
1
+ {"version":3,"sources":["../src/styles.ts","../src/fingerprint.ts","../../../node_modules/modern-screenshot/dist/index.mjs","../src/capture.ts","../../shared/dist/activity.js","../../shared/dist/lifecycle.js","../../shared/dist/iteration.js","../../shared/dist/consent.js","../../shared/dist/thread.js","../../shared/dist/timeline.js","../../shared/dist/mentions.js","../../shared/dist/needs-you.js","../../shared/dist/reactions.js","../../shared/dist/presence.js","../../shared/dist/companion-tray.js","../../shared/dist/index.js","../src/store.ts","../src/http-adapter.ts","../src/app.ts","../src/connect.ts","../src/index.ts"],"sourcesContent":["// Scoped to the Shadow DOM — none of this leaks to (or is affected by) the host page.\nexport const STYLES = /* css */ `\n:host { all: initial; }\n* { box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif; }\n\n/* Theme tokens live on :host (inside the Shadow DOM :root matches nothing).\n Dark is the default; the host element gets .theme-light to flip to light. */\n:host {\n --accent: #6b73e6;\n --accent-soft: rgba(107, 115, 230, 0.12);\n --pin: #ff5842;\n --bg: #14161d;\n --bg-2: #1b1e27;\n --bg-3: #262a36;\n --ink: #e7e9f0;\n --muted: #9aa0af;\n --line: #2b2f3b;\n --shadow: 0 12px 48px rgba(0,0,0,.42);\n}\n:host(.theme-light) {\n --accent: #4a55d6;\n --accent-soft: rgba(74, 85, 214, 0.12);\n --pin: #ff5842;\n --bg: #ffffff;\n --bg-2: #f6f7fb;\n --bg-3: #eceef4;\n --ink: #16181f;\n --muted: #6b7180;\n --line: #e2e5ee;\n --shadow: 0 12px 40px rgba(0,0,0,.22);\n}\n\n.overlay { position: fixed; inset: 0; z-index: 2147483000; pointer-events: none; }\n\n/* inspector highlight */\n.hl {\n position: fixed; pointer-events: none; z-index: 2147483001;\n border: 2px solid var(--accent);\n background: var(--accent-soft);\n border-radius: 4px; display: none;\n transition: all 60ms linear;\n}\n.hl .tip {\n position: absolute; top: -24px; left: 0; background: var(--accent); color: #fff;\n font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 4px; white-space: nowrap;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n/* region selection (during drag) + active-comment outline */\n.selbox {\n position: fixed; pointer-events: none; z-index: 2147483001; display: none;\n border: 2px dashed var(--accent); background: var(--accent-soft); border-radius: 4px;\n}\n.region-box {\n position: fixed; pointer-events: none; z-index: 2147483001; display: none;\n border: 2px solid var(--pin); border-radius: 4px;\n box-shadow: 0 0 0 2px rgba(255, 88, 66, .25), 0 4px 16px rgba(0,0,0,.25);\n}\n\n/* pins */\n.pin {\n position: fixed; pointer-events: auto; z-index: 2147483002;\n width: 26px; height: 26px; border-radius: 50% 50% 50% 2px;\n background: var(--pin); color: #fff; border: 2px solid #fff;\n font-size: 12px; font-weight: 700; cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,.35);\n display: grid; place-items: center; transform: translate(-4px, -4px);\n transition: transform 80ms ease;\n}\n.pin:hover { transform: translate(-4px, -4px) scale(1.12); }\n.pin.detached { background: #9aa0af; }\n.pin.done { background: #10935a; }\n.pin.free { background: var(--accent); border-radius: 50% 50% 2px 50%; }\n.pin.free.done { background: #10935a; }\n.pin.active { outline: 3px solid rgba(107,115,230,.45); }\n/* The quick-action \"Markers\" toggle hides every pin without discarding it.\n !important beats the inline display the pin positioner sets on each frame. */\n.overlay.hide-pins .pin { display: none !important; }\n\n/* --------------------------------------------------------------- FAB cluster */\n/* The collapsed state: a primary brand button (with the comment count) plus the\n quick actions that expand out of it. Replaces the old single launcher. */\n.fab-cluster {\n position: fixed; z-index: 2147483003; bottom: 20px; right: 20px;\n display: none; flex-direction: column; align-items: flex-end; gap: 10px;\n}\n.fab-cluster.show { display: flex; }\n/* The way back on a touch screen once the launcher is hidden (no keyboard for Alt+Shift+L):\n a slim tab on the right edge, shown only while the panel is closed. */\n.fab-handle {\n position: fixed; z-index: 2147483003; right: 0; bottom: 96px; width: 12px; height: 56px;\n display: none; padding: 0; border: 0; border-radius: 8px 0 0 8px;\n background: var(--accent); opacity: .6; cursor: pointer; touch-action: manipulation;\n}\n.fab-handle.show { display: block; }\n.fab-handle:hover, .fab-handle:focus-visible { opacity: 1; }\n/* A dragged launcher is anchored to its nearest edges (JS sets left/right/top/bottom),\n and the quick actions grow INTO the page: downward from the upper half, labels to the\n right from the left half. */\n.fab-cluster.at-top { flex-direction: column-reverse; }\n.fab-cluster.at-left, .fab-cluster.at-left .fab-minis { align-items: flex-start; }\n.fab-cluster.at-left .fab-mini .fab-tip { right: auto; left: calc(100% + 8px); }\n.fab-cluster.dragging .launcher { cursor: grabbing; border-color: var(--accent); }\n.fab-cluster.dragging .fab-mini .fab-tip { display: none; }\n\n.fab-minis { display: none; flex-direction: column; align-items: flex-end; gap: 10px; }\n.fab-cluster.expanded .fab-minis { display: flex; }\n.fab-cluster.expanded .fab-minis .fab-mini { animation: loupe-fab-in 180ms cubic-bezier(.16, 1, .3, 1) both; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(1) { animation-delay: 0ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(2) { animation-delay: 30ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(3) { animation-delay: 60ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(4) { animation-delay: 90ms; }\n.fab-cluster.expanded .fab-minis .fab-mini:nth-child(5) { animation-delay: 120ms; }\n@keyframes loupe-fab-in { from { opacity: 0; transform: translateY(8px) scale(.9); } to { opacity: 1; transform: none; } }\n.fab-cluster.at-top.expanded .fab-minis .fab-mini { animation-name: loupe-fab-in-down; }\n@keyframes loupe-fab-in-down { from { opacity: 0; transform: translateY(-8px) scale(.9); } to { opacity: 1; transform: none; } }\n\n.fab-mini {\n position: relative; width: 40px; height: 40px; border-radius: 50%; padding: 0;\n border: 1px solid var(--line); background: var(--bg); color: var(--ink);\n cursor: pointer; display: inline-flex; align-items: center; justify-content: center;\n box-shadow: var(--shadow);\n}\n.fab-mini:hover { border-color: var(--accent); color: var(--accent); }\n.fab-mini.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.fab-mini.on:hover { color: #fff; }\n.fab-mini svg { display: block; width: 16px; height: 16px; }\n/* The action's label, revealed on hover so the collapsed cluster stays calm. */\n.fab-mini .fab-tip {\n position: absolute; right: calc(100% + 8px); top: 50%; transform: translateY(-50%);\n background: var(--bg); color: var(--ink); border: 1px solid var(--line);\n border-radius: 7px; padding: 4px 8px; font-size: 11px; font-weight: 600; white-space: nowrap;\n box-shadow: var(--shadow); opacity: 0; pointer-events: none; transition: opacity 120ms ease;\n}\n.fab-mini:hover .fab-tip { opacity: 1; }\n\n/* The launcher and its chevron share a box so the chevron can sit on the launcher's\n corner while being its own button (tap = quick actions; the launcher = open). */\n.fab-main { position: relative; display: inline-flex; }\n.launcher {\n position: relative; width: 46px; height: 46px; border-radius: 50%; padding: 0;\n border: 1px solid var(--line); background: var(--bg-2); color: var(--ink);\n cursor: grab; display: inline-flex; align-items: center; justify-content: center;\n box-shadow: var(--shadow);\n touch-action: none; user-select: none; -webkit-user-select: none; /* drag with a finger too */\n}\n.launcher:hover { border-color: var(--accent); }\n.launcher:active { cursor: grabbing; }\n.launcher .logo { font-size: 24px; line-height: 1; color: var(--accent); }\n/* Chevron pinned to the corner: up = actions are tucked away, down = they are out. */\n.fab-more {\n position: absolute; right: -3px; bottom: -3px; width: 20px; height: 20px; border-radius: 50%;\n padding: 0; cursor: pointer; z-index: 1;\n background: var(--bg); border: 1px solid var(--line); color: var(--muted);\n display: grid; place-items: center; transition: transform 160ms cubic-bezier(.16, 1, .3, 1);\n}\n.fab-more:hover { border-color: var(--accent); color: var(--accent); }\n.fab-more .lchev { display: grid; place-items: center; }\n.fab-more svg { width: 11px; height: 11px; display: block; }\n.fab-cluster.expanded .fab-more { transform: rotate(180deg); }\n.fab-cluster.at-top .fab-more { bottom: auto; top: -3px; transform: rotate(180deg); }\n.fab-cluster.at-top.expanded .fab-more { transform: none; }\n.launcher .lcount {\n position: absolute; top: -5px; right: -5px; background: var(--pin); color: #fff;\n font-size: 10px; font-weight: 700; line-height: 1; border-radius: 999px; padding: 3px 6px;\n border: 2px solid var(--bg);\n}\n.launcher .lcount:empty { display: none; }\n@media (prefers-reduced-motion: reduce) {\n .fab-cluster.expanded .fab-minis .fab-mini { animation: none; }\n .launcher .lchev { transition: none; }\n .fab-mini .fab-tip { transition: none; }\n}\n\n/* --------------------------------------------------------------------- dock */\n/* The control panel. One container, four dock modes (left/right/bottom/float),\n overlaying the host page (never reflows it). */\n.dock {\n position: fixed; z-index: 2147483003; pointer-events: auto;\n display: none; flex-direction: column;\n background: var(--bg); color: var(--ink);\n border: 1px solid var(--line); box-shadow: var(--shadow);\n overflow: hidden; font-size: 13px;\n}\n.dock.open { display: flex; }\n.dock.mode-right { top: 0; right: 0; bottom: 0; width: 360px; border-width: 0 0 0 1px; }\n.dock.mode-left { top: 0; left: 0; bottom: 0; width: 360px; border-width: 0 1px 0 0; }\n.dock.mode-bottom { left: 0; right: 0; bottom: 0; height: 320px; border-width: 1px 0 0 0; }\n.dock.mode-float { border-radius: 14px; /* left/top/width/height set inline */ }\n\n/* header: brand + dock controls */\n.dhead {\n display: flex; align-items: center; gap: 8px; flex: none;\n padding: 8px 10px; border-bottom: 1px solid var(--line); background: var(--bg-2);\n}\n.dock.mode-float .dhead { cursor: grab; }\n.dock.mode-float.dragging .dhead { cursor: grabbing; }\n.dock.dragging { user-select: none; }\n.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; letter-spacing: -.01em; }\n.brand .logo { font-size: 16px; line-height: 1; color: var(--accent); flex: none; }\n.brand .title { font-size: 13px; }\n.dctl { display: flex; align-items: center; gap: 2px; margin-left: auto; }\n/* Only the header's own icon buttons. The position and settings popovers live inside\n .dctl too, and a bare .dctl button squeezed their rows and swatches to 26px. */\n.dctl > button, .dctl > .menu-wrap > button {\n display: inline-flex; align-items: center; justify-content: center;\n width: 26px; height: 26px; padding: 0; border: 0; border-radius: 6px;\n background: transparent; color: var(--muted); cursor: pointer;\n}\n.dctl > button:hover, .dctl > .menu-wrap > button:hover { background: var(--bg-3); color: var(--ink); }\n.dctl > button.on, .dctl > .menu-wrap > button.on { background: var(--bg-3); color: var(--accent); }\n.dctl svg { display: block; }\n.dctl .gap { width: 1px; height: 16px; background: var(--line); margin: 0 4px; flex: none; }\n\n/* tools row */\n.tools { display: flex; gap: 6px; flex: none; padding: 10px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }\n.tools button {\n display: flex; align-items: center; gap: 6px; padding: 7px 10px; line-height: 1;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2); color: var(--ink);\n font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.tools button:hover { background: var(--bg-3); }\n.tools button.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.tools .ico { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; }\n.tools .ico svg { width: 15px; height: 15px; display: block; }\n\n/* list */\n.listhead {\n display: flex; align-items: center; gap: 8px; flex: none; padding: 12px 12px 6px;\n font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700;\n}\n.count { background: var(--pin); color: #fff; font-size: 11px; font-weight: 700; line-height: 1; border-radius: 999px; padding: 3px 7px; }\n.list { flex: 1; overflow-y: auto; padding: 6px 10px 12px; display: flex; flex-direction: column; gap: 8px; }\n.empty { color: var(--muted); font-size: 13px; padding: 24px 12px; text-align: center; line-height: 1.5; }\n/* bottom dock lays the list out in flowing columns so it isn't a tall single strip */\n.dock.mode-bottom .list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); align-content: start; }\n\n.item { border: 1px solid var(--line); border-radius: 10px; padding: 10px; cursor: pointer; background: var(--bg-2); }\n.item:hover { border-color: var(--accent); }\n/* The header row now carries the number, a detached badge, a lifecycle chip, a PR\n chip, a checks meter and the caret — more than fits on one line in a narrow\n panel, so it wraps rather than clipping the last chip. The caret keeps its place\n at the end of the row. */\n.item .top { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; margin-bottom: 6px; }\n.item .top .caret { margin-left: auto; }\n.item .num { background: var(--pin); color: #fff; width: 20px; height: 20px; border-radius: 50%; font-size: 11px; font-weight: 700; display: grid; place-items: center; flex: none; }\n.item .num.detached { background: #9aa0af; }\n.item .num.done { background: #10935a; }\n/* Author + absolute time, visible collapsed too. */\n.item .who { display: flex; flex-wrap: wrap; gap: 0 4px; font-size: 11.5px; color: var(--muted); margin-top: 3px; }\n.item .who b { color: var(--ink); font-weight: 600; }\n.item .who time { font-variant-numeric: tabular-nums; white-space: nowrap; }\n.item .device { font-size: 10px; color: var(--muted); background: var(--bg-3); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }\n.item .body { font-size: 13px; line-height: 1.4; }\n.item .meta { font-size: 11px; color: var(--muted); margin-top: 6px; font-family: ui-monospace, Menlo, monospace; word-break: break-all; }\n.item .badge { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 1px 6px; border-radius: 5px; margin-left: auto; white-space: nowrap; }\n.badge.detached { background: var(--bg-3); color: var(--muted); }\n.badge.done { background: #d8f0e4; color: #10935a; }\n.item .actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }\n.item .actions button { font-size: 11px; border: 1px solid var(--line); background: var(--bg-3); border-radius: 6px; padding: 4px 8px; cursor: pointer; color: var(--ink); }\n.item .actions button:hover { border-color: var(--accent); }\n.item img.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); }\n.item video.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); }\n.item .caret { margin-left: auto; color: var(--muted); font-size: 11px; }\n.item .summary { font-size: 13px; font-weight: 600; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.item .detail { margin-top: 6px; }\n.item.collapsed .detail { display: none; }\n.listhead .search {\n margin-left: auto; flex: 1; max-width: 170px; font-size: 12px; text-transform: none; letter-spacing: 0;\n padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--bg-2); color: var(--ink); outline: none;\n}\n.listhead .search:focus { border-color: var(--accent); }\n\n/* float resize grip (bottom-right corner) */\n.resize { display: none; position: absolute; right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize; z-index: 1; }\n.dock.mode-float .resize { display: block; }\n.resize::after {\n content: \"\"; position: absolute; right: 3px; bottom: 3px; width: 7px; height: 7px;\n border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); opacity: .7;\n}\n\n/* composer popover */\n.composer {\n position: fixed; z-index: 2147483004; pointer-events: auto; width: 320px;\n background: var(--bg); color: var(--ink); border: 1px solid var(--line);\n border-radius: 12px; box-shadow: var(--shadow); padding: 12px; display: none;\n}\n.composer .target {\n font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--accent);\n background: var(--bg-2); border-radius: 6px; padding: 5px 8px; margin-bottom: 8px;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.composer textarea {\n width: 100%; min-height: 68px; resize: vertical; border: 1px solid var(--line);\n border-radius: 8px; padding: 8px; font-size: 13px; color: var(--ink); background: var(--bg-2); outline: none;\n}\n.composer textarea:focus { border-color: var(--accent); }\n.composer .row { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; gap: 8px; }\n.composer label.chk { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; cursor: pointer; }\n.composer .btns { display: flex; gap: 6px; }\n.composer button { border: 0; border-radius: 8px; font-size: 13px; font-weight: 600; padding: 7px 12px; cursor: pointer; }\n.composer .primary { background: var(--accent); color: #fff; }\n.composer .primary:disabled { opacity: .5; cursor: default; }\n.composer .ghost { background: var(--bg-3); color: var(--ink); }\n.composer input.title {\n width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 8px; margin-bottom: 8px;\n font-size: 13px; font-weight: 600; color: var(--ink); background: var(--bg-2); outline: none;\n}\n.composer input.title:focus { border-color: var(--accent); }\n.composer .attach { margin-top: 8px; }\n.composer .pick {\n width: 100%; border: 1px dashed var(--line); background: transparent; color: var(--muted);\n border-radius: 8px; padding: 7px; font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.composer .pick:hover { border-color: var(--accent); color: var(--accent); }\n.composer .chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }\n.composer .chip {\n display: inline-flex; align-items: center; gap: 4px; max-width: 100%;\n background: var(--bg-3); border-radius: 6px; padding: 2px 4px 2px 7px; font-size: 11px; color: var(--ink);\n}\n.composer .chip .x { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 13px; line-height: 1; padding: 0 2px; }\n.composer .err { color: var(--pin); font-size: 11px; margin-top: 4px; }\n.composer .err:empty { display: none; }\n\n/* Priority + change-type pickers, side by side under the attachments. */\n.composer .meta2 { display: flex; gap: 6px; margin-top: 8px; }\n.composer select.mini {\n flex: 1; min-width: 0; font-size: 12px; padding: 6px 7px; border-radius: 7px;\n border: 1px solid var(--line); background: var(--bg-2); color: var(--ink); outline: none;\n}\n.composer select.mini:focus { border-color: var(--accent); }\n\n/* ------------------------------------------------------------ sidebar tabs */\n.tabs { display: flex; gap: 4px; flex: none; padding: 8px 10px 0; border-bottom: 1px solid var(--line); }\n.tabs .tab {\n flex: 1; padding: 8px 10px; border: 0; border-bottom: 2px solid transparent;\n background: transparent; color: var(--muted); font-size: 12px; font-weight: 700; cursor: pointer;\n border-radius: 6px 6px 0 0;\n}\n.tabs .tab:hover { color: var(--ink); background: var(--bg-2); }\n.tabs .tab.on { color: var(--accent); border-bottom-color: var(--accent); }\n.tabs .tab.off { opacity: .45; cursor: not-allowed; }\n.tabs .tab.off:hover { color: inherit; background: transparent; }\n\n/* Only the active page shows. Driven by an \"on\" class rather than a .tab-<id>\n selector, so host-registered tab ids need no CSS of their own. */\n.view { display: none; }\n.view.on { display: block; flex: 1; min-height: 0; overflow-y: auto; }\n.view.on.comments-view { display: flex; flex-direction: column; }\n\n/* ------------------------------------------------------------- Home overview */\n.home-view { padding: 12px 12px 18px; }\n.hstat { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }\n.hstat-b {\n display: flex; flex-direction: column; gap: 2px; text-align: left; padding: 10px;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2); color: var(--ink); cursor: pointer;\n}\n.hstat-b:hover { border-color: var(--accent); }\n.hstat-b.on { border-color: var(--accent); background: var(--bg-3); }\n.hstat-n { font-size: 20px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }\n.hstat-l { font-size: 11px; color: var(--muted); }\n.hscope { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.hscope-b {\n flex: 1; padding: 7px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.hscope-b.on { background: var(--accent); border-color: var(--accent); color: #fff; }\n.hrefresh {\n flex: none; width: 30px; height: 30px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); cursor: pointer; font-size: 14px;\n}\n.hrefresh:hover { border-color: var(--accent); color: var(--ink); }\n.hpin {\n margin-top: 10px; width: 100%; padding: 9px; border: 0; border-radius: 9px;\n background: var(--accent); color: #fff; font-size: 13px; font-weight: 600; cursor: pointer;\n}\n.hlabel { margin-top: 14px; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700; }\n.hfeed { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; }\n.hfeed-i {\n display: flex; flex-direction: column; gap: 3px; text-align: left; padding: 8px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2); color: var(--ink); cursor: pointer;\n}\n.hfeed-i:hover { border-color: var(--accent); }\n.hfeed-t { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.hfeed-m { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--muted); }\n.hfeed-s { font-weight: 700; }\n.hfeed-s-resolved { color: #34c281; }\n.hfeed-p { font-weight: 700; }\n.hfeed-p-critical { color: var(--pin); }\n.hfeed-p-high { color: #e0a92c; }\n.hfeed-a { display: flex; gap: 4px; margin-top: 3px; }\n.hfeed-act {\n font-size: 11px; padding: 3px 8px; border: 1px solid var(--line); border-radius: 6px;\n background: var(--bg-3); color: var(--ink); cursor: pointer;\n}\n.hfeed-act:hover { border-color: var(--accent); }\n.hfeed-act.danger:hover, .hfeed-act.danger[data-armed] { border-color: var(--pin); color: var(--pin); }\n.hempty { padding: 14px; text-align: center; color: var(--muted); font-size: 12px; }\n.hfoot { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 11px; color: var(--muted); text-align: center; }\n\n/* Timeline grouping (project scope) + the repo filter. */\n.daylabel {\n display: flex; align-items: center; gap: 6px; width: 100%; margin: 8px 0 0; padding: 4px 2px;\n border: 0; background: none; cursor: pointer; text-align: left;\n font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700;\n}\n.daylabel::before { content: \"▾\"; font-size: 10px; width: 10px; }\n.daylabel.shut::before { content: \"▸\"; }\n.daylabel::after {\n content: attr(data-n); padding: 0 6px; border-radius: 999px; background: var(--bg-3);\n font-size: 10px; letter-spacing: 0;\n}\n.daylabel:hover { color: var(--ink); }\n.listfilters { display: flex; gap: 6px; margin: 6px 0 2px; }\n.listfilters select {\n flex: 1; min-width: 0; font-size: 12px; padding: 4px 6px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg-2); color: var(--ink); outline: none; cursor: pointer;\n}\n.listfilters select:focus { border-color: var(--accent); }\n/* The page a comment belongs to, shown in the project scope (Settings → Page paths). */\n.pathtag {\n padding: 1px 6px; border-radius: 999px; background: var(--bg-3); color: var(--muted);\n font-size: 10.5px; font-family: ui-monospace, Menlo, monospace;\n max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n\n/* recording marker + video in the list */\n.item .rectag { font-size: 10px; font-weight: 700; color: var(--pin); background: var(--bg-3); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }\n.item video.shot { width: 100%; border-radius: 6px; margin-top: 8px; border: 1px solid var(--line); background: #000; display: block; }\n\n/* ------------------------------------------------ \"integrates with\" footer */\n.integrations { flex: none; padding: 12px 12px 14px; border-top: 1px solid var(--line); text-align: center; }\n.integrations .ilabel { font-size: 10px; letter-spacing: .12em; color: var(--muted); font-weight: 700; margin-bottom: 8px; }\n.integrations .irow { display: flex; align-items: center; justify-content: center; gap: 14px; }\n.integrations .ibtn { color: var(--muted); display: inline-flex; opacity: .8; cursor: default; }\n.integrations .ibtn:hover { color: var(--accent); opacity: 1; }\n.integrations .ibtn svg { display: block; }\n\n/* ------------------------------------------------------- Connect Claude page */\n.connect-view { padding: 16px 14px 20px; }\n.connect-hero { text-align: center; margin-bottom: 18px; }\n.connect-hero .chero-logo { font-size: 34px; line-height: 1; color: var(--accent); }\n.connect-hero .chero-title { font-size: 18px; font-weight: 800; letter-spacing: -.02em; margin-top: 8px; }\n.connect-hero .chero-sub { font-size: 12.5px; color: var(--muted); line-height: 1.45; margin-top: 6px; }\n.accentink { color: var(--accent); }\n.connect-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }\n.connect-steps .cstep-t { font-size: 13px; font-weight: 700; }\n.connect-steps .cstep-d { font-size: 12px; color: var(--muted); line-height: 1.45; margin-top: 3px; }\n.connect-steps .cstep-code {\n margin: 8px 0 0; padding: 10px; background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 8px; font-family: ui-monospace, Menlo, monospace; font-size: 11px; line-height: 1.4;\n color: var(--ink); white-space: pre; overflow-x: auto;\n}\n\n/* ------------------------------------------------------- recording indicator */\n.recbar {\n position: fixed; z-index: 2147483005; top: 16px; left: 50%; transform: translateX(-50%);\n display: none; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px;\n background: var(--bg); color: var(--ink); border: 1px solid var(--pin);\n box-shadow: var(--shadow); font-size: 12px; font-weight: 600; cursor: pointer;\n}\n.recbar.show { display: inline-flex; }\n.recbar b { color: var(--pin); }\n.recbar .recdot { width: 9px; height: 9px; border-radius: 50%; background: var(--pin); animation: loupe-recpulse 1.1s infinite; }\n@keyframes loupe-recpulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }\n@media (prefers-reduced-motion: reduce) { .recbar .recdot { animation: none; } }\n\n/* ---------------------------------------------------------------- toast */\n/* A short notice (e.g. how to bring a hidden launcher back). Click to dismiss. */\n.toast {\n position: fixed; z-index: 2147483006; bottom: 24px; left: 50%;\n transform: translateX(-50%) translateY(8px); opacity: 0; pointer-events: none;\n max-width: calc(100vw - 32px); padding: 9px 14px; border-radius: 999px; text-align: center;\n background: var(--bg); color: var(--ink); border: 1px solid var(--line); box-shadow: var(--shadow);\n font-size: 12px; font-weight: 600; line-height: 1.4;\n transition: opacity 160ms ease, transform 160ms ease;\n}\n.toast.show { opacity: 1; transform: translateX(-50%); pointer-events: auto; cursor: pointer; }\n.toast kbd {\n font-family: ui-monospace, Menlo, monospace; font-size: 11px; padding: 1px 5px;\n border: 1px solid var(--line); border-radius: 4px; background: var(--bg-3);\n}\n@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }\n\n/* ---------------------------------------------- header popovers (pos + settings) */\n.menu-wrap { position: relative; }\n.menu {\n position: absolute; top: calc(100% + 6px); right: 0; z-index: 30;\n min-width: 214px; padding: 8px; display: none;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);\n}\n.menu.open { display: block; }\n.menu-label {\n margin: 2px 5px 6px; font-size: 10px; font-weight: 700; letter-spacing: .06em;\n text-transform: uppercase; color: var(--muted);\n}\n/* dock-position grid: the four layouts as a 2x2 of buttons */\n.pos-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n.pos-grid button {\n display: flex; align-items: center; gap: 6px; padding: 7px 8px; cursor: pointer;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg); color: var(--muted);\n font-size: 11.5px; font-weight: 600;\n}\n.pos-grid button:hover { border-color: var(--accent); color: var(--ink); }\n.pos-grid button.on { border-color: var(--accent); color: var(--accent); }\n.pos-grid button svg { width: 14px; height: 14px; flex: none; }\n/* settings rows */\n.menu-row {\n display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;\n padding: 7px 6px; border: 0; border-radius: 8px; background: transparent; color: var(--ink);\n font-size: 12.5px; text-align: left; cursor: pointer;\n}\n.menu-row:hover { background: var(--bg-3); }\n.menu-sep { height: 1px; margin: 6px 4px; background: var(--line); }\n/* on/off switch inside a settings row */\n.sw { flex: none; position: relative; width: 30px; height: 17px; border-radius: 999px; background: var(--line); transition: background .12s; }\n.sw::after { content: \"\"; position: absolute; top: 2px; left: 2px; width: 13px; height: 13px; border-radius: 50%; background: #fff; transition: transform .12s; }\n.menu-row[aria-pressed=\"true\"] .sw { background: var(--accent); }\n.menu-row[aria-pressed=\"true\"] .sw::after { transform: translateX(13px); }\n/* accent swatches */\n.acc-dots { display: flex; gap: 8px; padding: 4px 6px 2px; }\n.acc-dot { width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent; padding: 0; cursor: pointer; }\n.acc-dot.on { border-color: var(--ink); }\n\n/* ---------------------------------------------------------------- minimize bar */\n.minbar { display: none; align-items: center; gap: 8px; padding: 9px 10px; cursor: pointer; background: var(--bg-2); }\n.dock.minimized .minbar { display: flex; }\n.dock.minimized .tabs, .dock.minimized .view, .dock.minimized .resize,\n.dock.minimized .dctl [data-role=\"min\"], .dock.minimized .dctl .menu-wrap { display: none !important; }\n.minbar .logo { color: var(--accent); font-size: 14px; }\n.minbar .mtext { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--muted); }\n.minbar .mtext b { color: var(--ink); }\n.minbar .mrestore { flex: none; padding: 0 2px; border: 0; background: transparent; color: var(--accent); font-size: 14px; cursor: pointer; }\n\n/* ---------------------------------------------------------------- activity monitor */\n.activity-view { padding: 10px 12px 16px; }\n.mon-status { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--ink); }\n.mon-spacer { flex: 1; }\n.mon-live { font-size: 10px; font-weight: 600; color: var(--muted); }\n.mon-live.live { color: #2f9e6a; }\n.mon-live.offline { color: #d9534f; }\n.mon-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex: none; }\n.mon-status.st-working .mon-dot { background: var(--accent); animation: loupe-pulse 1.4s ease-in-out infinite; }\n.mon-status.st-error .mon-dot { background: var(--pin); }\n.mon-status.st-idle .mon-dot { background: var(--muted); }\n@keyframes loupe-pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }\n@media (prefers-reduced-motion: reduce) { .mon-status.st-working .mon-dot { animation: none; } }\n.mon-clear {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.mon-clear:hover { border-color: var(--accent); color: var(--ink); }\n\n.mon-summary { margin-top: 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2); overflow: hidden; }\n.mon-sum-head {\n display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px;\n border: 0; background: transparent; color: var(--ink); text-align: left; cursor: pointer;\n}\n.mon-sum-title { font-size: 12px; font-weight: 700; }\n.mon-sum-peek { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--muted); }\n.mon-caret { color: var(--muted); font-size: 11px; }\n.mon-sum-body { padding: 2px 10px 10px; }\n.mon-kv { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; font-size: 11.5px; color: var(--muted); }\n.mon-kv b { color: var(--ink); font-weight: 600; text-align: right; }\n.mon-preview {\n margin-top: 8px; padding: 7px 8px; border-radius: 7px; background: var(--bg);\n font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--muted);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.mon-micro { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.mon-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }\n.mon-chip {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.mon-chip:hover { border-color: var(--accent); color: var(--ink); }\n.mon-chip.on { border-color: var(--accent); background: var(--accent); color: #fff; }\n.mon-feed {\n margin-top: 8px; max-height: 46vh; overflow-y: auto;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg);\n}\n.mon-row {\n display: grid; grid-template-columns: 58px 88px 1fr; gap: 6px;\n padding: 5px 8px; border-bottom: 1px solid var(--line); font-size: 11px; line-height: 1.4;\n}\n.mon-row:last-child { border-bottom: 0; }\n.mon-time { color: var(--muted); font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; }\n.mon-kind { color: var(--accent); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.mon-label { color: var(--ink); overflow-wrap: anywhere; }\n.mon-detail { display: block; color: var(--muted); font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; overflow-wrap: anywhere; }\n.mon-row.lv-warn .mon-label { color: #e0a92c; }\n.mon-row.lv-error .mon-label { color: var(--pin); }\n.mon-empty { padding: 16px 12px; text-align: center; font-size: 11.5px; line-height: 1.6; color: var(--muted); }\n.mon-empty code { font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--ink); }\n\n/* ---------------------------------------------- project manager (repo + environments) */\n.projbar { display: flex; align-items: center; gap: 8px; margin-top: 12px; position: relative; }\n.proj-label { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--muted); }\n.proj-chip {\n display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; padding: 5px 9px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2);\n color: var(--ink); font-size: 11.5px; font-family: ui-monospace, Menlo, monospace; cursor: pointer;\n}\n.proj-chip:hover { border-color: var(--accent); }\n.proj-chip .proj-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }\n.proj-caret { color: var(--muted); font-family: inherit; }\n.proj-pop {\n position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 25;\n display: none; max-height: 60vh; overflow-y: auto; padding: 10px;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);\n}\n.proj-pop.open { display: block; }\n.pp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.pp-x { padding: 0 4px; border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 12px; line-height: 1; cursor: pointer; }\n.pp-x:hover { background: var(--bg-3); color: var(--ink); }\n.pp-cur { margin-bottom: 8px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.pp-cur b { color: var(--ink); font-family: ui-monospace, Menlo, monospace; }\n.pp-list { display: flex; flex-direction: column; gap: 2px; max-height: 30vh; overflow-y: auto; }\n.pp-proj {\n display: flex; align-items: center; gap: 6px; padding: 5px 8px; border: 1px solid transparent;\n border-radius: 7px; font-size: 11.5px; color: var(--ink);\n}\n.pp-proj.on { border-color: var(--accent); }\n.pp-proj-n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.pp-badge {\n flex: none; padding: 1px 6px; border-radius: 999px; background: var(--bg-3);\n color: var(--muted); font-size: 10px; white-space: nowrap;\n}\n.pp-empty { padding: 8px 6px; font-size: 11px; line-height: 1.5; color: var(--muted); }\n.pp-empty code { font-family: ui-monospace, Menlo, monospace; color: var(--ink); }\n.pp-clear {\n margin-top: 8px; padding: 5px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.pp-clear:hover { border-color: var(--pin); color: var(--pin); }\n.pp-sep { height: 1px; margin: 10px 0; background: var(--line); }\n.pp-env { display: flex; align-items: center; gap: 6px; padding: 4px 6px; border-radius: 7px; }\n.pp-env:hover { background: var(--bg-3); }\n.pp-env-u { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--ink); }\n.pp-add { display: flex; gap: 6px; margin-top: 6px; }\n.pp-env-url {\n flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg); color: var(--ink); font-size: 11.5px;\n}\n.pp-env-url:focus { outline: none; border-color: var(--accent); }\n.pp-add-b {\n flex: none; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.pp-err { margin-top: 6px; font-size: 11px; color: var(--pin); }\n.hver { font-family: ui-monospace, Menlo, monospace; }\n.menu-ver {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n margin: 8px 4px 2px; padding-top: 8px; border-top: 1px solid var(--line);\n font-size: 10.5px; color: var(--muted);\n}\n.menu-ver b { color: var(--ink); font-family: ui-monospace, Menlo, monospace; font-weight: 600; }\n.menu-mode { text-transform: uppercase; letter-spacing: .06em; font-size: 9.5px; }\n/* The host package's version, shown only when it differs from this bundle's (a stale publish). */\n.ver-stale { color: var(--pin); font-family: ui-monospace, Menlo, monospace; font-weight: 600; cursor: help; }\n\n/* ------------------------------------------------ tickets between projects */\n.srcchip, .fwdchip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap; font-size: 10px;\n border: 1px solid var(--line); background: var(--bg); color: var(--muted);\n max-width: 140px; overflow: hidden; text-overflow: ellipsis;\n}\n.fwdchip { border-color: var(--accent); color: var(--accent); }\n.fwdchip.bad { border-color: #d9534f; color: #d9534f; }\na.fwdchip { text-decoration: none; cursor: pointer; }\n.fwdchip[class*=\"st-\"] { max-width: 220px; }\n.fwdchip.st-queue { border-color: var(--line); color: var(--muted); }\n.fwdchip.st-in_progress { border-color: #3f8ae0; color: #3f8ae0; }\n.fwdchip.st-in_review { border-color: #c98a1b; color: #c98a1b; }\n.fwdchip.st-resolved { border-color: #2f9e6a; color: #2f9e6a; }\n\n/* ------------------------------------------------ lifecycle chips + review flow */\n.lifechip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap;\n border: 1px solid var(--line); background: var(--bg); color: var(--muted);\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n.lifechip.st-sent { border-color: var(--accent); color: var(--accent); }\n.lifechip.st-in_pr { border-color: #3f8ae0; color: #3f8ae0; }\n.lifechip.st-preview { border-color: var(--accent); background: var(--accent); color: #fff; }\n.lifechip.st-reviewed { border-color: #2f9e6a; color: #2f9e6a; }\n.prchip {\n padding: 1px 6px; border-radius: 6px; text-decoration: none; cursor: pointer;\n border: 1px solid #3f8ae0; background: var(--bg); color: #3f8ae0;\n font-family: ui-monospace, Menlo, monospace; font-size: 10px; font-weight: 700;\n}\n.prchip:hover { background: #3f8ae0; color: #fff; }\n.prchip.st-merged { border-color: #8250df; color: #8250df; }\n.prchip.st-merged:hover { background: #8250df; color: #fff; }\n.prchip.st-closed { border-color: var(--line); color: var(--muted); }\n/* a revision of another thread — the conversation carried over */\n.iterchip {\n padding: 1px 6px; border-radius: 999px; white-space: nowrap;\n border: 1px dashed var(--line); background: var(--bg); color: var(--muted);\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n/* a preview that is actually live — never shown optimistically */\n.previewchip {\n padding: 1px 6px; border-radius: 6px; text-decoration: none; white-space: nowrap;\n border: 1px solid #2f9e6a; background: var(--bg); color: #2f9e6a;\n font-size: 9.5px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;\n}\n.previewchip:hover { background: #2f9e6a; color: #fff; }\n/* checks meter — a numerator over a thin bar */\n.checks { display: inline-flex; align-items: center; gap: 4px; }\n.checks-n { font-family: ui-monospace, Menlo, monospace; font-size: 9.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.checks-bar { display: block; width: 26px; height: 3px; border-radius: 2px; background: var(--line); overflow: hidden; }\n.checks-bar i { display: block; height: 100%; background: #2f9e6a; }\n\n/* the \"N waiting on your review\" strip above the list */\n.reviewbar {\n display: flex; align-items: center; gap: 7px; margin: 8px 12px 0; padding: 7px 10px;\n border: 1px solid var(--accent); border-radius: 9px; background: var(--bg-2);\n}\n.rb-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; animation: loupe-pulse 1.6s ease-in-out infinite; }\n@media (prefers-reduced-motion: reduce) { .rb-dot { animation: none; } }\n.rb-t { flex: 1; font-size: 11.5px; color: var(--ink); }\n.rb-t b { font-variant-numeric: tabular-nums; }\n.rb-b {\n padding: 3px 9px; border: 1px solid var(--accent); border-radius: 7px;\n background: var(--accent); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer;\n}\n\n/* the review banner inside a thread */\n.revbanner {\n display: flex; align-items: center; gap: 6px; margin: 8px 0; padding: 7px 8px;\n border: 1px solid var(--accent); border-radius: 9px; background: var(--bg-3);\n}\n.rev-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }\n.rev-t { flex: 1; font-size: 11.5px; font-weight: 600; color: var(--ink); }\n.rev-approve {\n padding: 4px 10px; border: 1px solid var(--accent); border-radius: 7px;\n background: var(--accent); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer;\n}\n.rev-approve:disabled { opacity: .6; cursor: default; }\n.rev-comment, .rev-origin {\n padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.rev-comment:hover, .rev-origin:hover { border-color: var(--accent); }\n\n/* original request beside the proposed change */\n.origin { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; margin: 8px 0; }\n.or-col { min-width: 0; padding: 7px 8px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg); }\n.or-h { margin-bottom: 4px; font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.or-b { font-size: 11px; line-height: 1.45; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }\n.or-code {\n margin: 6px 0 0; padding: 6px; max-height: 130px; overflow: auto; border-radius: 6px;\n background: var(--bg-2); color: var(--muted); font-family: ui-monospace, Menlo, monospace;\n font-size: 10px; white-space: pre-wrap; overflow-wrap: anywhere;\n}\n\n/* ------------------------------------------------- consent-gated agent navigation */\n.consent {\n margin: 8px 10px 0; padding: 10px; border: 1px solid var(--pin); border-radius: 10px;\n background: var(--bg-2);\n}\n.cs-head { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink); }\n.cs-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pin); flex: none; animation: loupe-pulse 1.4s ease-in-out infinite; }\n@media (prefers-reduced-motion: reduce) { .cs-dot { animation: none; } }\n.cs-url {\n margin-top: 6px; padding: 6px 7px; border-radius: 7px; background: var(--bg);\n font-family: ui-monospace, Menlo, monospace; font-size: 10.5px; color: var(--ink);\n overflow-wrap: anywhere;\n}\n.cs-why { margin-top: 6px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.cs-btns { display: flex; justify-content: flex-end; gap: 6px; margin-top: 9px; }\n.cs-btns button { padding: 5px 10px; border-radius: 7px; font-size: 11.5px; font-weight: 600; cursor: pointer; }\n.cs-deny { border: 1px solid var(--line); background: var(--bg); color: var(--ink); }\n.cs-deny:hover { border-color: var(--accent); }\n.cs-go { border: 1px solid var(--accent); background: var(--accent); color: #fff; }\n\n/* --------------------------------------------------------------- generate + iterate */\n.genwrap { margin-top: 8px; }\n.gen-open {\n width: 100%; padding: 7px; border: 1px dashed var(--line); border-radius: 8px;\n background: transparent; color: var(--muted); font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.gen-open:hover { border-color: var(--accent); color: var(--accent); }\n.genhead { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }\n.gen-t { flex: 1; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }\n.gen-nav { display: inline-flex; align-items: center; gap: 2px; }\n.gen-step {\n width: 20px; height: 20px; padding: 0; border: 1px solid var(--line); border-radius: 6px;\n background: var(--bg); color: var(--ink); font-size: 13px; line-height: 1; cursor: pointer;\n}\n.gen-step:disabled { opacity: .4; cursor: default; }\n.gen-n { min-width: 32px; text-align: center; font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.gen-undo, .gen-x {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.gen-undo:disabled { opacity: .4; cursor: default; }\n.gen-undo:hover, .gen-x:hover { border-color: var(--accent); }\n.genbusy, .genempty { padding: 14px; text-align: center; font-size: 11.5px; color: var(--muted); }\n/* the preview plane: generated markup over the original capture, sandboxed.\n min-height matters — the iframe is absolutely positioned, so a thread with no\n screenshot would otherwise give the plane nothing in-flow and collapse it to a\n couple of pixels. */\n.genplane { position: relative; min-height: 150px; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--bg); }\n.genbase { display: block; width: 100%; }\n.genframe {\n position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: transparent;\n transition: opacity .08s linear;\n}\n.genslider { display: flex; align-items: center; gap: 7px; margin-top: 6px; }\n.gs-lab { font-size: 10.5px; color: var(--muted); }\n.gs-range { flex: 1; min-width: 0; accent-color: var(--accent); }\n.gs-n { min-width: 32px; text-align: right; font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }\n.gennotes {\n margin-top: 6px; padding: 6px 8px; border-radius: 7px; background: var(--bg-3);\n font-size: 11px; line-height: 1.45; color: var(--muted);\n}\n.geniter { display: flex; gap: 5px; margin-top: 7px; }\n.iter-in {\n flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg); color: var(--ink); font-size: 11.5px;\n}\n.iter-in:focus { outline: none; border-color: var(--accent); }\n.iter-send {\n flex: none; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.iter-send:disabled { opacity: .5; cursor: default; }\n/* the access gate, when there is no generator */\n.gengate { padding: 10px; border: 1px solid var(--line); border-radius: 9px; background: var(--bg-2); }\n.gate-t { font-size: 12px; font-weight: 700; color: var(--ink); }\n.gate-b { margin-top: 4px; font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.gate-ask {\n margin-top: 8px; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.gate-ask:disabled { opacity: .6; cursor: default; }\n.gate-hint { margin-top: 7px; font-size: 10.5px; color: var(--muted); }\n.gate-hint code { font-family: ui-monospace, Menlo, monospace; color: var(--ink); }\n\n/* dictation */\n.voice {\n width: 30px; flex: none; padding: 0; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 13px; cursor: pointer;\n}\n.voice:hover:not(:disabled) { border-color: var(--accent); color: var(--ink); }\n.voice:disabled { opacity: .45; cursor: not-allowed; }\n.voice.on { border-color: var(--pin); color: var(--pin); background: var(--bg-3); }\n\n/* attachments on a reply */\n.reply-attach {\n padding: 3px 7px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 12px; cursor: pointer; line-height: 1.4;\n}\n.reply-attach:hover { border-color: var(--accent); color: var(--accent); }\n.reply-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }\n.msg-atts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }\n.msg-att {\n max-width: 190px; max-height: 130px; border: 1px solid var(--line); border-radius: 8px;\n object-fit: cover; cursor: pointer; background: var(--bg-2);\n}\n\n/* ------------------------------------------------------------- companion chat */\n/* Same inset as the Activity view — without it the composer and its Send button sit\n flush against the panel's edge, which reads as a clipped button. Scoped to .view.on:\n a bare .chat-view display:flex outranked .view display:none by source\n order, so the chat rendered under every other tab and swallowed their clicks. */\n.view.on.chat-view { display: flex; flex-direction: column; gap: 8px; height: 100%; min-height: 0; padding: 10px 12px 16px; }\n.chat-tray {\n display: flex; flex-direction: column; gap: 4px; padding: 8px;\n border: 1px solid var(--line); border-radius: 10px; background: var(--bg-2);\n}\n.tray-head { display: flex; align-items: center; gap: 6px; }\n.tray-title { font-size: 11px; color: var(--muted); }\n.tray-spacer, .chat-spacer { flex: 1; }\n.tray-chip {\n display: flex; align-items: center; gap: 6px; padding: 4px 6px;\n border: 1px solid var(--line); border-radius: 8px; background: var(--bg); font-size: 11px;\n}\n.tray-chip.off { opacity: .5; }\n.tray-thumb { width: 24px; height: 24px; border-radius: 4px; object-fit: cover; flex: none; }\n.tray-kind { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; flex: none; }\n.tray-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, monospace; }\n.tray-nudge, .tray-x {\n border: 0; background: transparent; color: var(--muted); cursor: pointer;\n font-size: 11px; padding: 1px 4px; border-radius: 4px; line-height: 1.2;\n}\n.tray-nudge:disabled { opacity: .3; cursor: default; }\n.tray-nudge:not(:disabled):hover, .tray-x:hover { color: var(--accent); background: var(--accent-soft); }\n.chat-log { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 2px; }\n.chat-empty { color: var(--muted); font-size: 12px; padding: 12px 4px; line-height: 1.5; }\n.chat-msg { padding: 8px 10px; border-radius: 10px; background: var(--bg-2); border: 1px solid var(--line); }\n.chat-msg.mine { background: var(--accent-soft); border-color: var(--accent); }\n.chat-head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 3px; }\n.chat-who { font-size: 11px; }\n.chat-when { font-size: 10px; color: var(--muted); }\n.chat-ctx {\n font-size: 10px; color: var(--accent); border: 1px solid var(--accent);\n border-radius: 999px; padding: 0 5px; margin-left: auto;\n}\n.chat-body { font-size: 12px; white-space: pre-wrap; word-break: break-word; }\n.chat-compose { border-top: 1px solid var(--line); padding-top: 8px; }\n.chat-in {\n width: 100%; resize: vertical; min-height: 44px; padding: 7px 9px;\n border: 1px solid var(--line); border-radius: 9px; background: var(--bg);\n color: var(--ink); font: inherit; font-size: 12.5px;\n}\n.chat-in:focus { outline: none; border-color: var(--accent); }\n.chat-foot { display: flex; align-items: center; gap: 6px; margin-top: 6px; }\n.chat-add, .chat-mic, .chat-send {\n padding: 4px 9px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.chat-add:hover, .chat-mic:hover { border-color: var(--accent); color: var(--accent); }\n.chat-mic.on { border-color: var(--err, #f2555a); color: #f2555a; background: color-mix(in srgb, #f2555a 14%, transparent); }\n.chat-send { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }\n.chat-send:hover { opacity: .9; }\n.chat-rec { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: #f2555a; }\n.chat-rec-dot { width: 7px; height: 7px; border-radius: 50%; background: #f2555a; animation: chatpulse 1.2s ease-in-out infinite; }\n@keyframes chatpulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }\n.chat-err { font-size: 11px; color: #f2555a; }\n\n/* reactions */\n.rxns { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; position: relative; }\n.rxn {\n display: inline-flex; align-items: center; gap: 3px; padding: 1px 7px;\n border: 1px solid var(--line); border-radius: 999px; background: var(--bg);\n color: var(--ink); font-size: 11px; cursor: pointer; line-height: 1.7;\n}\n.rxn:hover { border-color: var(--accent); }\n.rxn.mine { border-color: var(--accent); background: var(--accent-soft); }\n.rxn-n { color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }\n.rxn.mine .rxn-n { color: var(--accent); }\n.rxn-add {\n width: 20px; height: 20px; padding: 0; border: 1px dashed var(--line); border-radius: 50%;\n background: transparent; color: var(--muted); font-size: 11px; cursor: pointer; line-height: 1;\n}\n.rxn-add:hover { border-color: var(--accent); color: var(--accent); }\n.rxn-pick {\n display: flex; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg); box-shadow: 0 4px 14px rgb(0 0 0 / 18%); z-index: 3;\n}\n.rxn-opt {\n width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%;\n background: transparent; font-size: 14px; cursor: pointer; line-height: 1;\n}\n.rxn-opt:hover { background: var(--accent-soft); }\n\n/* who else is here */\n.peers { display: flex; align-items: center; gap: -2px; margin-right: 8px; }\n.peer-av {\n display: inline-flex; align-items: center; justify-content: center;\n width: 20px; height: 20px; margin-left: -5px; border-radius: 50%;\n border: 2px solid var(--bg); background: var(--accent); color: #fff;\n font-size: 9px; font-weight: 700; letter-spacing: .02em;\n}\n.peer-av:first-child { margin-left: 0; }\n.peer-more { margin-left: 3px; font-size: 10px; color: var(--muted); }\n\n/* in-app mentions */\n.hnotif { margin-top: 10px; }\n.nf-head { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; font-size: 11.5px; color: var(--ink); }\n.nf-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }\n.nf-i {\n display: flex; align-items: baseline; gap: 7px; width: 100%; text-align: left;\n padding: 6px 8px; margin-bottom: 4px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--bg-2); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.nf-i:hover { background: var(--bg-3); }\n.nf-b { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.nf-w { flex: none; color: var(--muted); font-size: 10.5px; }\n.nf-read {\n margin-top: 2px; padding: 4px 8px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--muted); font-size: 10.5px; cursor: pointer;\n}\n.nf-read:hover { border-color: var(--accent); color: var(--ink); }\n\n/* mention highlighting + autocomplete */\n.mention { color: var(--accent); font-weight: 600; }\n.mention-list {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n padding: 5px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2);\n}\n.mention-pick {\n padding: 3px 8px; border: 1px solid var(--line); border-radius: 999px;\n background: var(--bg); color: var(--ink); font-size: 11px; cursor: pointer;\n}\n.mention-pick:hover { border-color: var(--accent); color: var(--accent); }\n/* \"needs you\" — the two reasons the stage cannot express */\n.needsline {\n display: flex; align-items: center; gap: 7px; margin: 8px 0; padding: 7px 9px;\n border: 1px solid #e0a92c; border-radius: 9px; background: var(--bg-2);\n font-size: 11.5px; font-weight: 600; color: var(--ink);\n}\n.needs-dot { width: 7px; height: 7px; border-radius: 50%; background: #e0a92c; flex: none; }\n\n/* ------------------------------------------------------------- conversation */\n.convo { margin-top: 8px; }\n.convo-loading { padding: 10px; text-align: center; font-size: 11.5px; color: var(--muted); }\n.msgs { display: flex; flex-direction: column; gap: 6px; }\n.msg { padding: 7px 8px; border-radius: 9px; background: var(--bg-2); border: 1px solid transparent; }\n/* An agent's reply is called out with a left accent bar and a lighter container —\n it should be obvious at a glance who you are talking to. */\n.msg.agent { border-left: 3px solid var(--accent); background: var(--bg-3); }\n.msg.pending { opacity: .65; }\n.msg.failed { border-color: var(--pin); }\n.msg-head { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }\n.msg-av {\n width: 20px; height: 20px; border-radius: 50%; flex: none;\n display: grid; place-items: center; background: var(--bg-3); color: var(--muted);\n font-size: 10px; font-weight: 700;\n}\n.msg-av.agent { background: var(--accent); color: #fff; }\n.msg-name { font-size: 11.5px; color: var(--ink); }\n.msg-when { flex: 1; font-size: 10.5px; color: var(--muted); }\n.msg-tag {\n padding: 0 5px; border-radius: 999px; background: var(--accent); color: #fff;\n font-size: 9px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;\n}\n.msg-body { font-size: 11.5px; line-height: 1.45; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }\n.msg-state { margin-top: 4px; font-size: 10.5px; color: var(--muted); }\n.msg-state.failed { color: var(--pin); }\n.msg-retry {\n margin-left: 6px; padding: 1px 7px; border: 1px solid var(--pin); border-radius: 6px;\n background: transparent; color: var(--pin); font-size: 10.5px; cursor: pointer;\n}\n.reply { margin-top: 7px; }\n.reply-in {\n width: 100%; resize: vertical; min-height: 40px; padding: 7px 8px;\n border: 1px solid var(--line); border-radius: 9px; background: var(--bg);\n color: var(--ink); font: inherit; font-size: 11.5px;\n}\n.reply-in:focus { outline: none; border-color: var(--accent); }\n.reply-foot { display: flex; align-items: center; gap: 7px; margin-top: 5px; }\n.reply-hint { flex: 1; font-size: 10.5px; color: var(--muted); }\n.reply-send {\n padding: 5px 10px; border: 1px solid var(--accent); border-radius: 8px;\n background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n/* the activity timeline */\n.tl { margin-top: 10px; }\n.tl-h { margin-bottom: 5px; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }\n.tl-i { position: relative; padding: 0 0 7px 14px; font-size: 11px; color: var(--muted); }\n.tl-i::before { content: \"\"; position: absolute; left: 3px; top: 4px; bottom: -3px; width: 1px; background: var(--line); }\n.tl-i:last-child::before { display: none; }\n.tl-dot { position: absolute; left: 0; top: 3px; width: 7px; height: 7px; border-radius: 50%; background: var(--line); }\n.tl-i.tl-resolved .tl-dot { background: #2f9e6a; }\n.tl-i.tl-pr .tl-dot, .tl-i.tl-preview .tl-dot { background: #3f8ae0; }\n.tl-i.tl-review .tl-dot { background: var(--accent); }\n.tl-l { color: var(--ink); }\n.tl-d { display: block; font-size: 10.5px; color: var(--muted); overflow-wrap: anywhere; }\n.copyrow { display: flex; gap: 6px; margin-top: 8px; }\n.copy-b {\n flex: 1; padding: 5px 8px; border: 1px solid var(--line); border-radius: 8px;\n background: var(--bg-2); color: var(--muted); font-size: 11px; cursor: pointer;\n}\n.copy-b:hover { border-color: var(--accent); color: var(--ink); }\n\n/* ------------------------------------------------------- hint card (once per view) */\n.hint {\n position: relative; margin: 8px 12px 0; padding: 10px 28px 10px 11px;\n border: 1px solid var(--accent); border-radius: 10px; background: var(--bg-2);\n}\n.hint-t { margin-bottom: 3px; font-size: 12.5px; font-weight: 700; color: var(--ink); }\n.hint-b { font-size: 11.5px; line-height: 1.45; color: var(--muted); }\n.hint-off { display: inline-block; margin-top: 6px; padding: 0; border: 0; background: transparent; color: var(--accent); font-size: 11px; text-decoration: underline; cursor: pointer; }\n.hint-x {\n position: absolute; top: 6px; right: 6px; width: 18px; height: 18px; padding: 0;\n border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 13px; line-height: 1; cursor: pointer;\n}\n.hint-x:hover { background: var(--bg-3); color: var(--ink); }\n\n/* ---------------------------------------------------------------- guided tour */\n/* Non-modal on purpose: the dimmer and the spotlight are click-through, so a tour\n can never trap someone mid-task. Only the card itself takes pointer events. */\n.tour { position: fixed; inset: 0; z-index: 2147483200; display: none; pointer-events: none; }\n.tour.open { display: block; }\n.tour-spot {\n position: fixed; border: 2px solid var(--accent); border-radius: 10px; pointer-events: none;\n box-shadow: 0 0 0 9999px rgba(8, 10, 16, .62);\n transition: all .18s ease;\n}\n.tour-card {\n position: fixed; width: 252px; padding: 12px; pointer-events: auto;\n background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); color: var(--ink);\n}\n.tour-title { margin-bottom: 4px; font-size: 13px; font-weight: 700; }\n.tour-body { font-size: 11.5px; line-height: 1.5; color: var(--muted); }\n.tour-foot { display: flex; align-items: center; gap: 6px; margin-top: 10px; }\n.tour-dots { display: flex; flex: 1; gap: 4px; }\n.tour-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--line); }\n.tour-dots i.on { background: var(--accent); }\n.tour-foot button {\n padding: 5px 9px; border: 1px solid var(--line); border-radius: 7px;\n background: var(--bg); color: var(--ink); font-size: 11.5px; font-weight: 600; cursor: pointer;\n}\n.tour-foot .t-next { border-color: var(--accent); background: var(--accent); color: #fff; }\n.tour-foot .t-skip { border: 0; background: transparent; color: var(--muted); }\n\n/* Mobile: left/right/float docking is a desktop affordance. On small screens the\n panel collapses to a bottom sheet that OVERLAYS the page (pushing a side dock\n here would squeeze the page to a useless sliver), regardless of the chosen dock\n mode. !important overrides the inline geometry JS applies for float mode. */\n@media (max-width: 640px) {\n .dock.open {\n top: auto !important; left: 0 !important; right: 0 !important; bottom: 0 !important;\n width: auto !important; height: 76vh !important;\n border-width: 1px 0 0 0 !important; border-radius: 16px 16px 0 0 !important;\n }\n .dctl [data-role=\"pos\"], .dctl .gap { display: none; } /* dock positions don't apply on mobile */\n .menu { min-width: 190px; }\n .resize { display: none !important; }\n .tools button { flex: 1; justify-content: center; } /* full-width tap targets */\n .dock.mode-bottom .list { grid-template-columns: 1fr; }\n .fab-cluster { bottom: 16px; right: 16px; }\n /* While a tool is active, shrink the sheet to just header + tools so most of the\n page stays visible and tappable; the list returns when the tool closes. */\n .dock.inspecting { height: auto !important; }\n .dock.inspecting .listhead, .dock.inspecting .list { display: none; }\n /* The composer is a bottom sheet on a phone: full width, thumb-reachable, and it\n scrolls when the on-screen keyboard is up. JS sets its position inline (hence the\n !important) — on small screens the sheet wins. */\n .composer {\n top: auto !important; left: 0 !important; right: 0 !important; bottom: 0 !important;\n width: auto !important; max-height: 80vh; overflow-y: auto;\n border-radius: 16px 16px 0 0; padding-bottom: 16px;\n }\n}\n`;\n","import type { Anchor, ResolveResult } from \"./types.js\";\n\n// ---- config ----------------------------------------------------------------\n\nconst TEXT_MAX = 120;\nconst ATTR_KEYS = [\"role\", \"aria-label\", \"name\", \"type\", \"alt\", \"href\", \"placeholder\", \"title\"];\n/** Minimum composite score to accept a scan match. Below this we treat the element as gone. */\nconst ACCEPT_THRESHOLD = 0.5;\n/** Weights for the composite similarity score (sum need not be 1; we normalize). */\nconst W = { tag: 0.12, text: 0.34, attrs: 0.22, testid: 0.22, cssPath: 0.2, position: 0.1 };\n\n// ---- capture ----------------------------------------------------------------\n\nexport function captureAnchor(el: Element): Anchor {\n const rect = el.getBoundingClientRect();\n return {\n tag: el.tagName.toLowerCase(),\n cssPath: cssPath(el),\n xpath: xPath(el),\n testid: stableId(el),\n text: normText(el.textContent),\n attrs: readAttrs(el),\n nthOfType: nthOfType(el),\n rect: {\n x: Math.round(rect.left + window.scrollX),\n y: Math.round(rect.top + window.scrollY),\n w: Math.round(rect.width),\n h: Math.round(rect.height),\n },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\n\n// ---- resolve ----------------------------------------------------------------\n\n/**\n * Try to re-locate the element described by `anchor` on the current page.\n * Returns the best candidate above threshold, or null (→ caller falls back to\n * a coordinate pin on the screenshot). Never returns an element inside our own UI.\n */\nexport function resolveAnchor(anchor: Anchor, root: ParentNode = document): ResolveResult | null {\n // 1. Stable id / testid — the strongest signal. Accept immediately if unique.\n if (anchor.testid) {\n const byTestid = safeQueryAll(root, `[data-testid=\"${cssStr(anchor.testid)}\"], [data-test=\"${cssStr(anchor.testid)}\"]`);\n const byId = document.getElementById(anchor.testid);\n const hits = dedupe([...byTestid, ...(byId ? [byId] : [])]).filter(usable);\n if (hits.length === 1) return { element: hits[0]!, score: 0.98, via: \"testid\" };\n // Multiple matches → fall through to scoring to disambiguate.\n }\n\n // 1.5. A cssPath rooted at a stable id/testid + structural position is\n // high-confidence even when the element's own text/content has changed\n // (e.g. a value that updates on redeploy). Require the tag to still match.\n if (/^(\\[data-testid=|#)/.test(anchor.cssPath)) {\n const hits = safeQueryAll(root, anchor.cssPath).filter(usable);\n if (hits.length === 1 && hits[0]!.tagName.toLowerCase() === anchor.tag) {\n return { element: hits[0]!, score: 0.9, via: \"cssPath\" };\n }\n }\n\n const candidates = new Map<Element, ResolveResult[\"via\"]>();\n const consider = (el: Element | null, via: ResolveResult[\"via\"]) => {\n if (el && usable(el) && !candidates.has(el)) candidates.set(el, via);\n };\n\n // 2. Exact locators.\n consider(safeQuery(root, anchor.cssPath), \"cssPath\");\n consider(byXPath(anchor.xpath), \"xpath\");\n for (const el of safeQueryAll(root, anchor.tag)) consider(el, \"scan\");\n\n // 3. Broaden by text when the tag scan is too narrow (e.g. wrapper changed tag).\n if (anchor.text) {\n for (const el of safeQueryAll(root, \"*\")) {\n if (candidates.size > 4000) break; // safety cap on huge pages\n if (normText(el.textContent) === anchor.text) consider(el, \"scan\");\n }\n }\n\n let best: ResolveResult | null = null;\n for (const [el, via] of candidates) {\n const score = similarity(anchor, el, via);\n if (!best || score > best.score) best = { element: el, score, via };\n }\n return best && best.score >= ACCEPT_THRESHOLD ? best : null;\n}\n\nfunction similarity(a: Anchor, el: Element, via: ResolveResult[\"via\"]): number {\n let sum = 0;\n let total = 0;\n\n const add = (w: number, v: number) => { sum += w * v; total += w; };\n\n add(W.tag, el.tagName.toLowerCase() === a.tag ? 1 : 0);\n\n if (a.text) {\n const t = normText(el.textContent);\n add(W.text, t === a.text ? 1 : t && (t.includes(a.text) || a.text.includes(t)) ? 0.5 : 0);\n }\n\n // Every field below is optional in practice: an anchor stored by an older (or\n // hand-written) client can be missing attrs/rect/viewport, and a throw here used\n // to abort the whole panel's first render.\n const attrKeys = Object.keys(a.attrs ?? {});\n if (attrKeys.length) {\n let matched = 0;\n for (const k of attrKeys) if (el.getAttribute(k) === (a.attrs ?? {})[k]) matched++;\n add(W.attrs, matched / attrKeys.length);\n }\n\n if (a.testid) add(W.testid, stableId(el) === a.testid ? 1 : 0);\n\n add(W.cssPath, via === \"cssPath\" ? 1 : 0);\n\n // Positional proximity — normalized by the (possibly changed) viewport diagonal.\n const r = el.getBoundingClientRect();\n const cx = r.left + window.scrollX + r.width / 2;\n const cy = r.top + window.scrollY + r.height / 2;\n const ar = a.rect ?? { x: 0, y: 0, w: 0, h: 0 };\n const av = a.viewport ?? { w: 0, h: 0 };\n const ax = ar.x + ar.w / 2;\n const ay = ar.y + ar.h / 2;\n const diag = Math.hypot(av.w, av.h) || 1;\n const dist = Math.hypot(cx - ax, cy - ay);\n add(W.position, Math.max(0, 1 - dist / diag));\n\n return total ? sum / total : 0;\n}\n\n// ---- locator builders -------------------------------------------------------\n\nfunction cssPath(el: Element): string {\n const segs: string[] = [];\n let node: Element | null = el;\n while (node && node.nodeType === 1 && node !== document.documentElement) {\n const id = node.getAttribute(\"id\");\n const testid = node.getAttribute(\"data-testid\") || node.getAttribute(\"data-test\");\n if (id && isStable(id)) { segs.unshift(`#${cssEsc(id)}`); break; }\n if (testid) { segs.unshift(`[data-testid=\"${cssStr(testid)}\"]`); break; }\n segs.unshift(`${node.tagName.toLowerCase()}:nth-of-type(${nthOfType(node)})`);\n node = node.parentElement;\n if (node === document.body) { segs.unshift(\"body\"); break; }\n }\n return segs.join(\" > \");\n}\n\nfunction xPath(el: Element): string {\n const segs: string[] = [];\n let node: Element | null = el;\n while (node && node.nodeType === 1 && node !== document.documentElement) {\n segs.unshift(`${node.tagName.toLowerCase()}[${nthOfType(node)}]`);\n node = node.parentElement;\n }\n return \"/html/\" + segs.join(\"/\");\n}\n\n// ---- small helpers ----------------------------------------------------------\n\nfunction nthOfType(el: Element): number {\n let i = 1;\n let sib = el.previousElementSibling;\n while (sib) {\n if (sib.tagName === el.tagName) i++;\n sib = sib.previousElementSibling;\n }\n return i;\n}\n\nfunction stableId(el: Element): string | null {\n const testid = el.getAttribute(\"data-testid\") || el.getAttribute(\"data-test\");\n if (testid) return testid;\n const id = el.getAttribute(\"id\");\n return id && isStable(id) ? id : null;\n}\n\n/** Reject framework-generated ids (e.g. \":r3:\", \"ember42\", long hashes). */\nfunction isStable(id: string): boolean {\n if (id.length > 40) return false;\n if (/^(ember|react|radix|headlessui|:r)/i.test(id)) return false;\n if (/[:]/.test(id)) return false;\n return true;\n}\n\nfunction readAttrs(el: Element): Record<string, string> {\n const out: Record<string, string> = {};\n for (const k of ATTR_KEYS) {\n const v = el.getAttribute(k);\n if (v != null && v !== \"\") out[k] = v.length > 200 ? v.slice(0, 200) : v;\n }\n return out;\n}\n\nfunction normText(t: string | null): string {\n return (t || \"\").replace(/\\s+/g, \" \").trim().slice(0, TEXT_MAX);\n}\n\n/**\n * Exclude anything inside our own Shadow-DOM host, the document itself, and — where the\n * browser can tell (`checkVisibility`: Chrome 105+, Firefox 106+, Safari 17.4+) — nodes\n * that are not rendered, so a hidden duplicate never wins over the visible one.\n */\nfunction usable(el: Element): boolean {\n if (el.id === \"loupe-root\" || el.closest(\"#loupe-root\")) return false;\n if (el === document.body || el === document.documentElement) return false;\n if (typeof el.checkVisibility === \"function\" && !el.checkVisibility()) return false;\n return true;\n}\n\nfunction byXPath(xp: string): Element | null {\n try {\n const r = document.evaluate(xp, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);\n return r.singleNodeValue instanceof Element ? r.singleNodeValue : null;\n } catch {\n return null;\n }\n}\n\nfunction safeQuery(root: ParentNode, sel: string): Element | null {\n try { return sel ? root.querySelector(sel) : null; } catch { return null; }\n}\nfunction safeQueryAll(root: ParentNode, sel: string): Element[] {\n try { return sel ? Array.from(root.querySelectorAll(sel)) : []; } catch { return []; }\n}\nfunction dedupe(els: Element[]): Element[] {\n return Array.from(new Set(els));\n}\nfunction cssEsc(s: string): string {\n return (window.CSS && CSS.escape) ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n/** Escape a value for use inside a double-quoted attribute selector. */\nfunction cssStr(s: string): string {\n return s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n","function changeJpegDpi(uint8Array, dpi) {\n uint8Array[13] = 1;\n uint8Array[14] = dpi >> 8;\n uint8Array[15] = dpi & 255;\n uint8Array[16] = dpi >> 8;\n uint8Array[17] = dpi & 255;\n return uint8Array;\n}\n\nconst _P = \"p\".charCodeAt(0);\nconst _H = \"H\".charCodeAt(0);\nconst _Y = \"Y\".charCodeAt(0);\nconst _S = \"s\".charCodeAt(0);\nlet pngDataTable;\nfunction createPngDataTable() {\n const crcTable = new Int32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) {\n c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;\n }\n crcTable[n] = c;\n }\n return crcTable;\n}\nfunction calcCrc(uint8Array) {\n let c = -1;\n if (!pngDataTable)\n pngDataTable = createPngDataTable();\n for (let n = 0; n < uint8Array.length; n++) {\n c = pngDataTable[(c ^ uint8Array[n]) & 255] ^ c >>> 8;\n }\n return c ^ -1;\n}\nfunction searchStartOfPhys(uint8Array) {\n const length = uint8Array.length - 1;\n for (let i = length; i >= 4; i--) {\n if (uint8Array[i - 4] === 9 && uint8Array[i - 3] === _P && uint8Array[i - 2] === _H && uint8Array[i - 1] === _Y && uint8Array[i] === _S) {\n return i - 3;\n }\n }\n return 0;\n}\nfunction changePngDpi(uint8Array, dpi, overwritepHYs = false) {\n const physChunk = new Uint8Array(13);\n dpi *= 39.3701;\n physChunk[0] = _P;\n physChunk[1] = _H;\n physChunk[2] = _Y;\n physChunk[3] = _S;\n physChunk[4] = dpi >>> 24;\n physChunk[5] = dpi >>> 16;\n physChunk[6] = dpi >>> 8;\n physChunk[7] = dpi & 255;\n physChunk[8] = physChunk[4];\n physChunk[9] = physChunk[5];\n physChunk[10] = physChunk[6];\n physChunk[11] = physChunk[7];\n physChunk[12] = 1;\n const crc = calcCrc(physChunk);\n const crcChunk = new Uint8Array(4);\n crcChunk[0] = crc >>> 24;\n crcChunk[1] = crc >>> 16;\n crcChunk[2] = crc >>> 8;\n crcChunk[3] = crc & 255;\n if (overwritepHYs) {\n const startingIndex = searchStartOfPhys(uint8Array);\n uint8Array.set(physChunk, startingIndex);\n uint8Array.set(crcChunk, startingIndex + 13);\n return uint8Array;\n } else {\n const chunkLength = new Uint8Array(4);\n chunkLength[0] = 0;\n chunkLength[1] = 0;\n chunkLength[2] = 0;\n chunkLength[3] = 9;\n const finalHeader = new Uint8Array(54);\n finalHeader.set(uint8Array, 0);\n finalHeader.set(chunkLength, 33);\n finalHeader.set(physChunk, 37);\n finalHeader.set(crcChunk, 50);\n return finalHeader;\n }\n}\nconst b64PhysSignature1 = \"AAlwSFlz\";\nconst b64PhysSignature2 = \"AAAJcEhZ\";\nconst b64PhysSignature3 = \"AAAACXBI\";\nfunction detectPhysChunkFromDataUrl(dataUrl) {\n let b64index = dataUrl.indexOf(b64PhysSignature1);\n if (b64index === -1) {\n b64index = dataUrl.indexOf(b64PhysSignature2);\n }\n if (b64index === -1) {\n b64index = dataUrl.indexOf(b64PhysSignature3);\n }\n return b64index;\n}\n\nconst PREFIX = \"[modern-screenshot]\";\nconst IN_BROWSER = typeof window !== \"undefined\";\nconst SUPPORT_WEB_WORKER = IN_BROWSER && \"Worker\" in window;\nconst SUPPORT_ATOB = IN_BROWSER && \"atob\" in window;\nconst SUPPORT_BTOA = IN_BROWSER && \"btoa\" in window;\nconst USER_AGENT = IN_BROWSER ? window.navigator?.userAgent : \"\";\nconst IN_CHROME = USER_AGENT.includes(\"Chrome\");\nconst IN_SAFARI = USER_AGENT.includes(\"AppleWebKit\") && !IN_CHROME;\nconst IN_FIREFOX = USER_AGENT.includes(\"Firefox\");\nconst isContext = (value) => value && \"__CONTEXT__\" in value;\nconst isCssFontFaceRule = (rule) => rule.constructor.name === \"CSSFontFaceRule\";\nconst isCSSImportRule = (rule) => rule.constructor.name === \"CSSImportRule\";\nconst isLayerBlockRule = (rule) => rule.constructor.name === \"CSSLayerBlockRule\";\nconst isElementNode = (node) => node.nodeType === 1;\nconst isSVGElementNode = (node) => typeof node.className === \"object\";\nconst isSVGImageElementNode = (node) => node.tagName === \"image\";\nconst isSVGUseElementNode = (node) => node.tagName === \"use\";\nconst isHTMLElementNode = (node) => isElementNode(node) && typeof node.style !== \"undefined\" && !isSVGElementNode(node);\nconst isCommentNode = (node) => node.nodeType === 8;\nconst isTextNode = (node) => node.nodeType === 3;\nconst isImageElement = (node) => node.tagName === \"IMG\";\nconst isVideoElement = (node) => node.tagName === \"VIDEO\";\nconst isCanvasElement = (node) => node.tagName === \"CANVAS\";\nconst isTextareaElement = (node) => node.tagName === \"TEXTAREA\";\nconst isInputElement = (node) => node.tagName === \"INPUT\";\nconst isStyleElement = (node) => node.tagName === \"STYLE\";\nconst isScriptElement = (node) => node.tagName === \"SCRIPT\";\nconst isSelectElement = (node) => node.tagName === \"SELECT\";\nconst isSlotElement = (node) => node.tagName === \"SLOT\";\nconst isIFrameElement = (node) => node.tagName === \"IFRAME\";\nconst consoleWarn = (...args) => console.warn(PREFIX, ...args);\nfunction supportWebp(ownerDocument) {\n const canvas = ownerDocument?.createElement?.(\"canvas\");\n if (canvas) {\n canvas.height = canvas.width = 1;\n }\n return Boolean(canvas) && \"toDataURL\" in canvas && Boolean(canvas.toDataURL(\"image/webp\").includes(\"image/webp\"));\n}\nconst isDataUrl = (url) => url.startsWith(\"data:\");\nfunction resolveUrl(url, baseUrl) {\n if (url.match(/^[a-z]+:\\/\\//i))\n return url;\n if (IN_BROWSER && url.match(/^\\/\\//))\n return window.location.protocol + url;\n if (url.match(/^[a-z]+:/i))\n return url;\n if (!IN_BROWSER)\n return url;\n const doc = getDocument().implementation.createHTMLDocument();\n const base = doc.createElement(\"base\");\n const a = doc.createElement(\"a\");\n doc.head.appendChild(base);\n doc.body.appendChild(a);\n if (baseUrl)\n base.href = baseUrl;\n a.href = url;\n return a.href;\n}\nfunction getDocument(target) {\n return (target && isElementNode(target) ? target?.ownerDocument : target) ?? window.document;\n}\nconst XMLNS = \"http://www.w3.org/2000/svg\";\nfunction createSvg(width, height, ownerDocument) {\n const svg = getDocument(ownerDocument).createElementNS(XMLNS, \"svg\");\n svg.setAttributeNS(null, \"width\", width.toString());\n svg.setAttributeNS(null, \"height\", height.toString());\n svg.setAttributeNS(null, \"viewBox\", `0 0 ${width} ${height}`);\n return svg;\n}\nfunction svgToDataUrl(svg, removeControlCharacter) {\n let xhtml = new XMLSerializer().serializeToString(svg);\n if (removeControlCharacter) {\n xhtml = xhtml.replace(/[\\u0000-\\u0008\\v\\f\\u000E-\\u001F\\uD800-\\uDFFF\\uFFFE\\uFFFF]/gu, \"\");\n }\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(xhtml)}`;\n}\nasync function canvasToBlob(canvas, type = \"image/png\", quality = 1) {\n try {\n return await new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error(\"Blob is null\"));\n }\n }, type, quality);\n });\n } catch (error) {\n if (SUPPORT_ATOB) {\n return dataUrlToBlob(canvas.toDataURL(type, quality));\n }\n throw error;\n }\n}\nfunction dataUrlToBlob(dataUrl) {\n const [header, base64] = dataUrl.split(\",\");\n const type = header.match(/data:(.+);/)?.[1] ?? void 0;\n const decoded = window.atob(base64);\n const length = decoded.length;\n const buffer = new Uint8Array(length);\n for (let i = 0; i < length; i += 1) {\n buffer[i] = decoded.charCodeAt(i);\n }\n return new Blob([buffer], { type });\n}\nfunction readBlob(blob, type) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result);\n reader.onerror = () => reject(reader.error);\n reader.onabort = () => reject(new Error(`Failed read blob to ${type}`));\n if (type === \"dataUrl\") {\n reader.readAsDataURL(blob);\n } else if (type === \"arrayBuffer\") {\n reader.readAsArrayBuffer(blob);\n }\n });\n}\nconst blobToDataUrl = (blob) => readBlob(blob, \"dataUrl\");\nconst blobToArrayBuffer = (blob) => readBlob(blob, \"arrayBuffer\");\nfunction createImage(url, ownerDocument) {\n const img = getDocument(ownerDocument).createElement(\"img\");\n img.decoding = \"sync\";\n img.loading = \"eager\";\n img.src = url;\n return img;\n}\nfunction loadMedia(media, options) {\n return new Promise((resolve) => {\n const { timeout, ownerDocument, onError: userOnError, onWarn } = options ?? {};\n const node = typeof media === \"string\" ? createImage(media, getDocument(ownerDocument)) : media;\n let timer = null;\n let removeEventListeners = null;\n function onResolve() {\n resolve(node);\n timer && clearTimeout(timer);\n removeEventListeners?.();\n }\n if (timeout) {\n timer = setTimeout(onResolve, timeout);\n }\n if (isVideoElement(node)) {\n const currentSrc = node.currentSrc || node.src;\n if (!currentSrc) {\n if (node.poster) {\n return loadMedia(node.poster, options).then(resolve);\n }\n return onResolve();\n }\n if (node.readyState >= 2) {\n return onResolve();\n }\n const onLoadeddata = onResolve;\n const onError = (error) => {\n onWarn?.(\n \"Failed video load\",\n currentSrc,\n error\n );\n userOnError?.(error);\n onResolve();\n };\n removeEventListeners = () => {\n node.removeEventListener(\"loadeddata\", onLoadeddata);\n node.removeEventListener(\"error\", onError);\n };\n node.addEventListener(\"loadeddata\", onLoadeddata, { once: true });\n node.addEventListener(\"error\", onError, { once: true });\n } else {\n const currentSrc = isSVGImageElementNode(node) ? node.href.baseVal : node.currentSrc || node.src;\n if (!currentSrc) {\n return onResolve();\n }\n const onLoad = async () => {\n if (isImageElement(node) && \"decode\" in node) {\n try {\n await node.decode();\n } catch (error) {\n onWarn?.(\n \"Failed to decode image, trying to render anyway\",\n node.dataset.originalSrc || currentSrc,\n error\n );\n }\n }\n onResolve();\n };\n const onError = (error) => {\n onWarn?.(\n \"Failed image load\",\n node.dataset.originalSrc || currentSrc,\n error\n );\n onResolve();\n };\n if (isImageElement(node) && node.complete) {\n return onLoad();\n }\n removeEventListeners = () => {\n node.removeEventListener(\"load\", onLoad);\n node.removeEventListener(\"error\", onError);\n };\n node.addEventListener(\"load\", onLoad, { once: true });\n node.addEventListener(\"error\", onError, { once: true });\n }\n });\n}\nasync function waitUntilLoad(node, options) {\n if (isHTMLElementNode(node)) {\n if (isImageElement(node) || isVideoElement(node)) {\n await loadMedia(node, options);\n } else {\n await Promise.all(\n [\"img\", \"video\"].flatMap((selectors) => {\n return Array.from(node.querySelectorAll(selectors)).map((el) => loadMedia(el, options));\n })\n );\n }\n }\n}\nconst uuid = /* @__PURE__ */ function uuid2() {\n let counter = 0;\n const random = () => `0000${(Math.random() * 36 ** 4 << 0).toString(36)}`.slice(-4);\n return () => {\n counter += 1;\n return `u${random()}${counter}`;\n };\n}();\nfunction splitFontFamily(fontFamily) {\n return fontFamily?.split(\",\").map((val) => val.trim().replace(/\"|'/g, \"\").toLowerCase()).filter(Boolean);\n}\n\nlet uid = 0;\nfunction createLogger(debug) {\n const prefix = `${PREFIX}[#${uid}]`;\n uid++;\n return {\n // eslint-disable-next-line no-console\n time: (label) => debug && console.time(`${prefix} ${label}`),\n // eslint-disable-next-line no-console\n timeEnd: (label) => debug && console.timeEnd(`${prefix} ${label}`),\n warn: (...args) => debug && consoleWarn(...args)\n };\n}\n\nfunction getDefaultRequestInit(bypassingCache) {\n return {\n cache: bypassingCache ? \"no-cache\" : \"force-cache\"\n };\n}\n\nasync function orCreateContext(node, options) {\n return isContext(node) ? node : createContext(node, { ...options, autoDestruct: true });\n}\nasync function createContext(node, options) {\n const { scale = 1, workerUrl, workerNumber = 1 } = options || {};\n const debug = Boolean(options?.debug);\n const features = options?.features ?? true;\n const ownerDocument = node.ownerDocument ?? (IN_BROWSER ? window.document : void 0);\n const ownerWindow = node.ownerDocument?.defaultView ?? (IN_BROWSER ? window : void 0);\n const requests = /* @__PURE__ */ new Map();\n const context = {\n // Options\n width: 0,\n height: 0,\n quality: 1,\n type: \"image/png\",\n scale,\n backgroundColor: null,\n style: null,\n filter: null,\n maximumCanvasSize: 0,\n timeout: 3e4,\n progress: null,\n debug,\n fetch: {\n requestInit: getDefaultRequestInit(options?.fetch?.bypassingCache),\n placeholderImage: \"data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n bypassingCache: false,\n ...options?.fetch\n },\n fetchFn: null,\n font: {},\n drawImageInterval: 100,\n workerUrl: null,\n workerNumber,\n onCloneEachNode: null,\n onCloneNode: null,\n onEmbedNode: null,\n onCreateForeignObjectSvg: null,\n includeStyleProperties: null,\n autoDestruct: false,\n ...options,\n // InternalContext\n __CONTEXT__: true,\n log: createLogger(debug),\n node,\n ownerDocument,\n ownerWindow,\n dpi: scale === 1 ? null : 96 * scale,\n svgStyleElement: createStyleElement(ownerDocument),\n svgDefsElement: ownerDocument?.createElementNS(XMLNS, \"defs\"),\n svgStyles: /* @__PURE__ */ new Map(),\n defaultComputedStyles: /* @__PURE__ */ new Map(),\n workers: [\n ...Array.from({\n length: SUPPORT_WEB_WORKER && workerUrl && workerNumber ? workerNumber : 0\n })\n ].map(() => {\n try {\n const worker = new Worker(workerUrl);\n worker.onmessage = async (event) => {\n const { url, result } = event.data;\n if (result) {\n requests.get(url)?.resolve?.(result);\n } else {\n requests.get(url)?.reject?.(new Error(`Error receiving message from worker: ${url}`));\n }\n };\n worker.onmessageerror = (event) => {\n const { url } = event.data;\n requests.get(url)?.reject?.(new Error(`Error receiving message from worker: ${url}`));\n };\n return worker;\n } catch (error) {\n context.log.warn(\"Failed to new Worker\", error);\n return null;\n }\n }).filter(Boolean),\n fontFamilies: /* @__PURE__ */ new Map(),\n fontCssTexts: /* @__PURE__ */ new Map(),\n acceptOfImage: `${[\n supportWebp(ownerDocument) && \"image/webp\",\n \"image/svg+xml\",\n \"image/*\",\n \"*/*\"\n ].filter(Boolean).join(\",\")};q=0.8`,\n requests,\n drawImageCount: 0,\n tasks: [],\n features,\n isEnable: (key) => {\n if (key === \"restoreScrollPosition\") {\n return typeof features === \"boolean\" ? false : features[key] ?? false;\n }\n if (typeof features === \"boolean\") {\n return features;\n }\n return features[key] ?? true;\n },\n shadowRoots: []\n };\n context.log.time(\"wait until load\");\n await waitUntilLoad(node, { timeout: context.timeout, onWarn: context.log.warn });\n context.log.timeEnd(\"wait until load\");\n const { width, height } = resolveBoundingBox(node, context);\n context.width = width;\n context.height = height;\n return context;\n}\nfunction createStyleElement(ownerDocument) {\n if (!ownerDocument)\n return void 0;\n const style = ownerDocument.createElement(\"style\");\n const cssText = style.ownerDocument.createTextNode(`\n.______background-clip--text {\n background-clip: text;\n -webkit-background-clip: text;\n}\n`);\n style.appendChild(cssText);\n return style;\n}\nfunction resolveBoundingBox(node, context) {\n let { width, height } = context;\n if (isElementNode(node) && (!width || !height)) {\n const box = node.getBoundingClientRect();\n width = width || box.width || Number(node.getAttribute(\"width\")) || 0;\n height = height || box.height || Number(node.getAttribute(\"height\")) || 0;\n }\n return { width, height };\n}\n\nasync function imageToCanvas(image, context) {\n const {\n log,\n timeout,\n drawImageCount,\n drawImageInterval\n } = context;\n log.time(\"image to canvas\");\n const loaded = await loadMedia(image, { timeout, onWarn: context.log.warn });\n const { canvas, context2d } = createCanvas(image.ownerDocument, context);\n const drawImage = () => {\n try {\n context2d?.drawImage(loaded, 0, 0, canvas.width, canvas.height);\n } catch (error) {\n context.log.warn(\"Failed to drawImage\", error);\n }\n };\n drawImage();\n if (context.isEnable(\"fixSvgXmlDecode\")) {\n for (let i = 0; i < drawImageCount; i++) {\n await new Promise((resolve) => {\n setTimeout(() => {\n context2d?.clearRect(0, 0, canvas.width, canvas.height);\n drawImage();\n resolve();\n }, i + drawImageInterval);\n });\n }\n }\n context.drawImageCount = 0;\n log.timeEnd(\"image to canvas\");\n return canvas;\n}\nfunction createCanvas(ownerDocument, context) {\n const { width, height, scale, backgroundColor, maximumCanvasSize: max } = context;\n const canvas = ownerDocument.createElement(\"canvas\");\n canvas.width = Math.floor(width * scale);\n canvas.height = Math.floor(height * scale);\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n if (max) {\n if (canvas.width > max || canvas.height > max) {\n if (canvas.width > max && canvas.height > max) {\n if (canvas.width > canvas.height) {\n canvas.height *= max / canvas.width;\n canvas.width = max;\n } else {\n canvas.width *= max / canvas.height;\n canvas.height = max;\n }\n } else if (canvas.width > max) {\n canvas.height *= max / canvas.width;\n canvas.width = max;\n } else {\n canvas.width *= max / canvas.height;\n canvas.height = max;\n }\n }\n }\n const context2d = canvas.getContext(\"2d\");\n if (context2d && backgroundColor) {\n context2d.fillStyle = backgroundColor;\n context2d.fillRect(0, 0, canvas.width, canvas.height);\n }\n return { canvas, context2d };\n}\n\nfunction cloneCanvas(canvas, context) {\n if (canvas.ownerDocument) {\n try {\n const dataURL = canvas.toDataURL();\n if (dataURL !== \"data:,\") {\n return createImage(dataURL, canvas.ownerDocument);\n }\n } catch (error) {\n context.log.warn(\"Failed to clone canvas\", error);\n }\n }\n const cloned = canvas.cloneNode(false);\n const ctx = canvas.getContext(\"2d\");\n const clonedCtx = cloned.getContext(\"2d\");\n try {\n if (ctx && clonedCtx) {\n clonedCtx.putImageData(\n ctx.getImageData(0, 0, canvas.width, canvas.height),\n 0,\n 0\n );\n }\n return cloned;\n } catch (error) {\n context.log.warn(\"Failed to clone canvas\", error);\n }\n return cloned;\n}\n\nfunction cloneIframe(iframe, context) {\n try {\n if (iframe?.contentDocument?.documentElement) {\n return cloneNode(iframe.contentDocument.documentElement, context);\n }\n } catch (error) {\n context.log.warn(\"Failed to clone iframe\", error);\n }\n return iframe.cloneNode(false);\n}\n\nfunction cloneImage(image) {\n const cloned = image.cloneNode(false);\n if (image.currentSrc && image.currentSrc !== image.src) {\n cloned.src = image.currentSrc;\n cloned.srcset = \"\";\n }\n if (cloned.loading === \"lazy\") {\n cloned.loading = \"eager\";\n }\n return cloned;\n}\n\nasync function cloneVideo(video, context) {\n if (video.ownerDocument && !video.currentSrc && video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n const cloned = video.cloneNode(false);\n cloned.crossOrigin = \"anonymous\";\n if (video.currentSrc && video.currentSrc !== video.src) {\n cloned.src = video.currentSrc;\n }\n const ownerDocument = cloned.ownerDocument;\n if (ownerDocument) {\n let canPlay = true;\n await loadMedia(cloned, { onError: () => canPlay = false, onWarn: context.log.warn });\n if (!canPlay) {\n if (video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n return cloned;\n }\n cloned.currentTime = video.currentTime;\n await new Promise((resolve) => {\n cloned.addEventListener(\"seeked\", resolve, { once: true });\n });\n const canvas = ownerDocument.createElement(\"canvas\");\n canvas.width = video.offsetWidth;\n canvas.height = video.offsetHeight;\n try {\n const ctx = canvas.getContext(\"2d\");\n if (ctx)\n ctx.drawImage(cloned, 0, 0, canvas.width, canvas.height);\n } catch (error) {\n context.log.warn(\"Failed to clone video\", error);\n if (video.poster) {\n return createImage(video.poster, video.ownerDocument);\n }\n return cloned;\n }\n return cloneCanvas(canvas, context);\n }\n return cloned;\n}\n\nfunction cloneElement(node, context) {\n if (isCanvasElement(node)) {\n return cloneCanvas(node, context);\n }\n if (isIFrameElement(node)) {\n return cloneIframe(node, context);\n }\n if (isImageElement(node)) {\n return cloneImage(node);\n }\n if (isVideoElement(node)) {\n return cloneVideo(node, context);\n }\n return node.cloneNode(false);\n}\n\nfunction getSandBox(context) {\n let sandbox = context.sandbox;\n if (!sandbox) {\n const { ownerDocument } = context;\n try {\n if (ownerDocument) {\n sandbox = ownerDocument.createElement(\"iframe\");\n sandbox.id = `__SANDBOX__${uuid()}`;\n sandbox.width = \"0\";\n sandbox.height = \"0\";\n sandbox.style.visibility = \"hidden\";\n sandbox.style.position = \"fixed\";\n ownerDocument.body.appendChild(sandbox);\n sandbox.srcdoc = '<!DOCTYPE html><meta charset=\"UTF-8\"><title></title><body>';\n context.sandbox = sandbox;\n }\n } catch (error) {\n context.log.warn(\"Failed to getSandBox\", error);\n }\n }\n return sandbox;\n}\n\nconst ignoredStyles = [\n \"width\",\n \"height\",\n \"-webkit-text-fill-color\"\n];\nconst includedAttributes = [\n \"stroke\",\n \"fill\"\n];\nfunction getDefaultStyle(node, pseudoElement, context) {\n const { defaultComputedStyles } = context;\n const nodeName = node.nodeName.toLowerCase();\n const isSvgNode = isSVGElementNode(node) && nodeName !== \"svg\";\n const attributes = isSvgNode ? includedAttributes.map((name) => [name, node.getAttribute(name)]).filter(([, value]) => value !== null) : [];\n const key = [\n isSvgNode && \"svg\",\n nodeName,\n attributes.map((name, value) => `${name}=${value}`).join(\",\"),\n pseudoElement\n ].filter(Boolean).join(\":\");\n if (defaultComputedStyles.has(key))\n return defaultComputedStyles.get(key);\n const sandbox = getSandBox(context);\n const sandboxWindow = sandbox?.contentWindow;\n if (!sandboxWindow)\n return /* @__PURE__ */ new Map();\n const sandboxDocument = sandboxWindow?.document;\n let root;\n let el;\n if (isSvgNode) {\n root = sandboxDocument.createElementNS(XMLNS, \"svg\");\n el = root.ownerDocument.createElementNS(root.namespaceURI, nodeName);\n attributes.forEach(([name, value]) => {\n el.setAttributeNS(null, name, value);\n });\n root.appendChild(el);\n } else {\n root = el = sandboxDocument.createElement(nodeName);\n }\n el.textContent = \" \";\n sandboxDocument.body.appendChild(root);\n const computedStyle = sandboxWindow.getComputedStyle(el, pseudoElement);\n const styles = /* @__PURE__ */ new Map();\n for (let len = computedStyle.length, i = 0; i < len; i++) {\n const name = computedStyle.item(i);\n if (ignoredStyles.includes(name))\n continue;\n styles.set(name, computedStyle.getPropertyValue(name));\n }\n sandboxDocument.body.removeChild(root);\n defaultComputedStyles.set(key, styles);\n return styles;\n}\n\nfunction getDiffStyle(style, defaultStyle, includeStyleProperties) {\n const diffStyle = /* @__PURE__ */ new Map();\n const prefixs = [];\n const prefixTree = /* @__PURE__ */ new Map();\n if (includeStyleProperties) {\n for (const name of includeStyleProperties) {\n applyTo(name);\n }\n } else {\n for (let len = style.length, i = 0; i < len; i++) {\n const name = style.item(i);\n applyTo(name);\n }\n }\n for (let len = prefixs.length, i = 0; i < len; i++) {\n prefixTree.get(prefixs[i])?.forEach((value, name) => diffStyle.set(name, value));\n }\n function applyTo(name) {\n const value = style.getPropertyValue(name);\n const priority = style.getPropertyPriority(name);\n const subIndex = name.lastIndexOf(\"-\");\n const prefix = subIndex > -1 ? name.substring(0, subIndex) : void 0;\n if (prefix) {\n let map = prefixTree.get(prefix);\n if (!map) {\n map = /* @__PURE__ */ new Map();\n prefixTree.set(prefix, map);\n }\n map.set(name, [value, priority]);\n }\n if (defaultStyle.get(name) === value && !priority)\n return;\n if (prefix) {\n prefixs.push(prefix);\n } else {\n diffStyle.set(name, [value, priority]);\n }\n }\n return diffStyle;\n}\n\nfunction copyCssStyles(node, cloned, isRoot, context) {\n const { ownerWindow, includeStyleProperties, currentParentNodeStyle } = context;\n const clonedStyle = cloned.style;\n const computedStyle = ownerWindow.getComputedStyle(node);\n const defaultStyle = getDefaultStyle(node, null, context);\n currentParentNodeStyle?.forEach((_, key) => {\n defaultStyle.delete(key);\n });\n const style = getDiffStyle(computedStyle, defaultStyle, includeStyleProperties);\n style.delete(\"transition-property\");\n style.delete(\"all\");\n style.delete(\"d\");\n style.delete(\"content\");\n if (isRoot) {\n style.delete(\"position\");\n style.delete(\"margin-top\");\n style.delete(\"margin-right\");\n style.delete(\"margin-bottom\");\n style.delete(\"margin-left\");\n style.delete(\"margin-block-start\");\n style.delete(\"margin-block-end\");\n style.delete(\"margin-inline-start\");\n style.delete(\"margin-inline-end\");\n style.set(\"box-sizing\", [\"border-box\", \"\"]);\n }\n if (style.get(\"background-clip\")?.[0] === \"text\") {\n cloned.classList.add(\"______background-clip--text\");\n }\n if (IN_CHROME) {\n if (!style.has(\"font-kerning\"))\n style.set(\"font-kerning\", [\"normal\", \"\"]);\n if ((style.get(\"overflow-x\")?.[0] === \"hidden\" || style.get(\"overflow-y\")?.[0] === \"hidden\") && style.get(\"text-overflow\")?.[0] === \"ellipsis\" && node.scrollWidth === node.clientWidth) {\n style.set(\"text-overflow\", [\"clip\", \"\"]);\n }\n }\n for (let len = clonedStyle.length, i = 0; i < len; i++) {\n clonedStyle.removeProperty(clonedStyle.item(i));\n }\n style.forEach(([value, priority], name) => {\n clonedStyle.setProperty(name, value, priority);\n });\n return style;\n}\n\nfunction copyInputValue(node, cloned) {\n if (isTextareaElement(node) || isInputElement(node) || isSelectElement(node)) {\n cloned.setAttribute(\"value\", node.value);\n }\n}\n\nconst pseudoClasses = [\n \"::before\",\n \"::after\"\n // '::placeholder', TODO\n];\nconst scrollbarPseudoClasses = [\n \"::-webkit-scrollbar\",\n \"::-webkit-scrollbar-button\",\n // '::-webkit-scrollbar:horizontal', TODO\n \"::-webkit-scrollbar-thumb\",\n \"::-webkit-scrollbar-track\",\n \"::-webkit-scrollbar-track-piece\",\n // '::-webkit-scrollbar:vertical', TODO\n \"::-webkit-scrollbar-corner\",\n \"::-webkit-resizer\"\n];\nfunction copyPseudoClass(node, cloned, copyScrollbar, context, addWordToFontFamilies) {\n const { ownerWindow, svgStyleElement, svgStyles, currentNodeStyle } = context;\n if (!svgStyleElement || !ownerWindow)\n return;\n function copyBy(pseudoClass) {\n const computedStyle = ownerWindow.getComputedStyle(node, pseudoClass);\n let content = computedStyle.getPropertyValue(\"content\");\n if (!content || content === \"none\")\n return;\n addWordToFontFamilies?.(content);\n content = content.replace(/(')|(\")|(counter\\(.+\\))/g, \"\");\n const klasses = [uuid()];\n const defaultStyle = getDefaultStyle(node, pseudoClass, context);\n currentNodeStyle?.forEach((_, key) => {\n defaultStyle.delete(key);\n });\n const style = getDiffStyle(computedStyle, defaultStyle, context.includeStyleProperties);\n style.delete(\"content\");\n style.delete(\"-webkit-locale\");\n if (style.get(\"background-clip\")?.[0] === \"text\") {\n cloned.classList.add(\"______background-clip--text\");\n }\n const cloneStyle = [\n `content: '${content}';`\n ];\n style.forEach(([value, priority], name) => {\n cloneStyle.push(`${name}: ${value}${priority ? \" !important\" : \"\"};`);\n });\n if (cloneStyle.length === 1)\n return;\n try {\n cloned.className = [cloned.className, ...klasses].join(\" \");\n } catch (err) {\n context.log.warn(\"Failed to copyPseudoClass\", err);\n return;\n }\n const cssText = cloneStyle.join(\"\\n \");\n let allClasses = svgStyles.get(cssText);\n if (!allClasses) {\n allClasses = [];\n svgStyles.set(cssText, allClasses);\n }\n allClasses.push(`.${klasses[0]}${pseudoClass}`);\n }\n pseudoClasses.forEach(copyBy);\n if (copyScrollbar)\n scrollbarPseudoClasses.forEach(copyBy);\n}\n\nconst excludeParentNodes = /* @__PURE__ */ new Set([\n \"symbol\"\n // test/fixtures/svg.symbol.html\n]);\nasync function appendChildNode(node, cloned, child, context, addWordToFontFamilies) {\n if (isElementNode(child) && (isStyleElement(child) || isScriptElement(child)))\n return;\n if (context.filter && !context.filter(child))\n return;\n if (excludeParentNodes.has(cloned.nodeName) || excludeParentNodes.has(child.nodeName)) {\n context.currentParentNodeStyle = void 0;\n } else {\n context.currentParentNodeStyle = context.currentNodeStyle;\n }\n const childCloned = await cloneNode(child, context, false, addWordToFontFamilies);\n if (context.isEnable(\"restoreScrollPosition\")) {\n restoreScrollPosition(node, childCloned);\n }\n cloned.appendChild(childCloned);\n}\nasync function cloneChildNodes(node, cloned, context, addWordToFontFamilies) {\n let firstChild = node.firstChild;\n if (isElementNode(node)) {\n if (node.shadowRoot) {\n firstChild = node.shadowRoot?.firstChild;\n context.shadowRoots.push(node.shadowRoot);\n }\n }\n for (let child = firstChild; child; child = child.nextSibling) {\n if (isCommentNode(child))\n continue;\n if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === \"function\") {\n const nodes = child.assignedNodes();\n for (let i = 0; i < nodes.length; i++) {\n await appendChildNode(node, cloned, nodes[i], context, addWordToFontFamilies);\n }\n } else {\n await appendChildNode(node, cloned, child, context, addWordToFontFamilies);\n }\n }\n}\nfunction restoreScrollPosition(node, chlidCloned) {\n if (!isHTMLElementNode(node) || !isHTMLElementNode(chlidCloned))\n return;\n const { scrollTop, scrollLeft } = node;\n if (!scrollTop && !scrollLeft) {\n return;\n }\n const { transform } = chlidCloned.style;\n const matrix = new DOMMatrix(transform);\n const { a, b, c, d } = matrix;\n matrix.a = 1;\n matrix.b = 0;\n matrix.c = 0;\n matrix.d = 1;\n matrix.translateSelf(-scrollLeft, -scrollTop);\n matrix.a = a;\n matrix.b = b;\n matrix.c = c;\n matrix.d = d;\n chlidCloned.style.transform = matrix.toString();\n}\nfunction applyCssStyleWithOptions(cloned, context) {\n const { backgroundColor, width, height, style: styles } = context;\n const clonedStyle = cloned.style;\n if (backgroundColor)\n clonedStyle.setProperty(\"background-color\", backgroundColor, \"important\");\n if (width)\n clonedStyle.setProperty(\"width\", `${width}px`, \"important\");\n if (height)\n clonedStyle.setProperty(\"height\", `${height}px`, \"important\");\n if (styles) {\n for (const name in styles) clonedStyle[name] = styles[name];\n }\n}\nconst NORMAL_ATTRIBUTE_RE = /^[\\w-:]+$/;\nasync function cloneNode(node, context, isRoot = false, addWordToFontFamilies) {\n const { ownerDocument, ownerWindow, fontFamilies, onCloneEachNode } = context;\n if (ownerDocument && isTextNode(node)) {\n if (addWordToFontFamilies && /\\S/.test(node.data)) {\n addWordToFontFamilies(node.data);\n }\n return ownerDocument.createTextNode(node.data);\n }\n if (ownerDocument && ownerWindow && isElementNode(node) && (isHTMLElementNode(node) || isSVGElementNode(node))) {\n const cloned2 = await cloneElement(node, context);\n if (context.isEnable(\"removeAbnormalAttributes\")) {\n const names = cloned2.getAttributeNames();\n for (let len = names.length, i = 0; i < len; i++) {\n const name = names[i];\n if (!NORMAL_ATTRIBUTE_RE.test(name)) {\n cloned2.removeAttribute(name);\n }\n }\n }\n const style = context.currentNodeStyle = copyCssStyles(node, cloned2, isRoot, context);\n if (isRoot)\n applyCssStyleWithOptions(cloned2, context);\n let copyScrollbar = false;\n if (context.isEnable(\"copyScrollbar\")) {\n const overflow = [\n style.get(\"overflow-x\")?.[0],\n style.get(\"overflow-y\")?.[0]\n ];\n copyScrollbar = overflow.includes(\"scroll\") || (overflow.includes(\"auto\") || overflow.includes(\"overlay\")) && (node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth);\n }\n const textTransform = style.get(\"text-transform\")?.[0];\n const families = splitFontFamily(style.get(\"font-family\")?.[0]);\n const addWordToFontFamilies2 = families ? (word) => {\n if (textTransform === \"uppercase\") {\n word = word.toUpperCase();\n } else if (textTransform === \"lowercase\") {\n word = word.toLowerCase();\n } else if (textTransform === \"capitalize\") {\n word = word[0].toUpperCase() + word.substring(1);\n }\n families.forEach((family) => {\n let fontFamily = fontFamilies.get(family);\n if (!fontFamily) {\n fontFamilies.set(family, fontFamily = /* @__PURE__ */ new Set());\n }\n word.split(\"\").forEach((text) => fontFamily.add(text));\n });\n } : void 0;\n copyPseudoClass(\n node,\n cloned2,\n copyScrollbar,\n context,\n addWordToFontFamilies2\n );\n copyInputValue(node, cloned2);\n if (!isVideoElement(node)) {\n await cloneChildNodes(\n node,\n cloned2,\n context,\n addWordToFontFamilies2\n );\n }\n await onCloneEachNode?.(cloned2);\n return cloned2;\n }\n const cloned = node.cloneNode(false);\n await cloneChildNodes(node, cloned, context);\n await onCloneEachNode?.(cloned);\n return cloned;\n}\n\nfunction destroyContext(context) {\n context.ownerDocument = void 0;\n context.ownerWindow = void 0;\n context.svgStyleElement = void 0;\n context.svgDefsElement = void 0;\n context.svgStyles.clear();\n context.defaultComputedStyles.clear();\n if (context.sandbox) {\n try {\n context.sandbox.remove();\n } catch (err) {\n context.log.warn(\"Failed to destroyContext\", err);\n }\n context.sandbox = void 0;\n }\n context.workers = [];\n context.fontFamilies.clear();\n context.fontCssTexts.clear();\n context.requests.clear();\n context.tasks = [];\n context.shadowRoots = [];\n}\n\nfunction baseFetch(options) {\n const { url, timeout, responseType, ...requestInit } = options;\n const controller = new AbortController();\n const timer = timeout ? setTimeout(() => controller.abort(), timeout) : void 0;\n return fetch(url, { signal: controller.signal, ...requestInit }).then((response) => {\n if (!response.ok) {\n throw new Error(\"Failed fetch, not 2xx response\", { cause: response });\n }\n switch (responseType) {\n case \"arrayBuffer\":\n return response.arrayBuffer();\n case \"dataUrl\":\n return response.blob().then(blobToDataUrl);\n case \"text\":\n default:\n return response.text();\n }\n }).finally(() => clearTimeout(timer));\n}\nfunction contextFetch(context, options) {\n const { url: rawUrl, requestType = \"text\", responseType = \"text\", imageDom } = options;\n let url = rawUrl;\n const {\n timeout,\n acceptOfImage,\n requests,\n fetchFn,\n fetch: {\n requestInit,\n bypassingCache,\n placeholderImage\n },\n font,\n workers,\n fontFamilies\n } = context;\n if (requestType === \"image\" && (IN_SAFARI || IN_FIREFOX)) {\n context.drawImageCount++;\n }\n let request = requests.get(rawUrl);\n if (!request) {\n if (bypassingCache) {\n if (bypassingCache instanceof RegExp && bypassingCache.test(url)) {\n url += (/\\?/.test(url) ? \"&\" : \"?\") + (/* @__PURE__ */ new Date()).getTime();\n }\n }\n const canFontMinify = requestType.startsWith(\"font\") && font && font.minify;\n const fontTexts = /* @__PURE__ */ new Set();\n if (canFontMinify) {\n const families = requestType.split(\";\")[1].split(\",\");\n families.forEach((family) => {\n if (!fontFamilies.has(family))\n return;\n fontFamilies.get(family).forEach((text) => fontTexts.add(text));\n });\n }\n const needFontMinify = canFontMinify && fontTexts.size;\n const baseFetchOptions = {\n url,\n timeout,\n responseType: needFontMinify ? \"arrayBuffer\" : responseType,\n headers: requestType === \"image\" ? { accept: acceptOfImage } : void 0,\n ...requestInit\n };\n request = {\n type: requestType,\n resolve: void 0,\n reject: void 0,\n response: null\n };\n request.response = (async () => {\n if (fetchFn && requestType === \"image\") {\n const result = await fetchFn(rawUrl);\n if (result)\n return result;\n }\n if (!IN_SAFARI && rawUrl.startsWith(\"http\") && workers.length) {\n return new Promise((resolve, reject) => {\n const worker = workers[requests.size & workers.length - 1];\n worker.postMessage({ rawUrl, ...baseFetchOptions });\n request.resolve = resolve;\n request.reject = reject;\n });\n }\n return baseFetch(baseFetchOptions);\n })().catch((error) => {\n requests.delete(rawUrl);\n if (requestType === \"image\" && placeholderImage) {\n context.log.warn(\"Failed to fetch image base64, trying to use placeholder image\", url);\n return typeof placeholderImage === \"string\" ? placeholderImage : placeholderImage(imageDom);\n }\n throw error;\n });\n requests.set(rawUrl, request);\n }\n return request.response;\n}\n\nasync function replaceCssUrlToDataUrl(cssText, baseUrl, context, isImage) {\n if (!hasCssUrl(cssText))\n return cssText;\n for (const [rawUrl, url] of parseCssUrls(cssText, baseUrl)) {\n try {\n const dataUrl = await contextFetch(\n context,\n {\n url,\n requestType: isImage ? \"image\" : \"text\",\n responseType: \"dataUrl\"\n }\n );\n cssText = cssText.replace(toRE(rawUrl), `$1${dataUrl}$3`);\n } catch (error) {\n context.log.warn(\"Failed to fetch css data url\", rawUrl, error);\n }\n }\n return cssText;\n}\nfunction hasCssUrl(cssText) {\n return /url\\((['\"]?)([^'\"]+?)\\1\\)/.test(cssText);\n}\nconst URL_RE = /url\\((['\"]?)([^'\"]+?)\\1\\)/g;\nfunction parseCssUrls(cssText, baseUrl) {\n const result = [];\n cssText.replace(URL_RE, (raw, quotation, url) => {\n result.push([url, resolveUrl(url, baseUrl)]);\n return raw;\n });\n return result.filter(([url]) => !isDataUrl(url));\n}\nfunction toRE(url) {\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, \"\\\\$1\");\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, \"g\");\n}\n\nconst properties = [\n \"background-image\",\n \"border-image-source\",\n \"-webkit-border-image\",\n \"-webkit-mask-image\",\n \"list-style-image\"\n];\nfunction embedCssStyleImage(style, context) {\n return properties.map((property) => {\n const value = style.getPropertyValue(property);\n if (!value || value === \"none\") {\n return null;\n }\n if (IN_SAFARI || IN_FIREFOX) {\n context.drawImageCount++;\n }\n return replaceCssUrlToDataUrl(value, null, context, true).then((newValue) => {\n if (!newValue || value === newValue)\n return;\n style.setProperty(\n property,\n newValue,\n style.getPropertyPriority(property)\n );\n });\n }).filter(Boolean);\n}\n\nfunction embedImageElement(cloned, context) {\n if (isImageElement(cloned)) {\n const originalSrc = cloned.currentSrc || cloned.src;\n if (!isDataUrl(originalSrc)) {\n return [\n contextFetch(context, {\n url: originalSrc,\n imageDom: cloned,\n requestType: \"image\",\n responseType: \"dataUrl\"\n }).then((url) => {\n if (!url)\n return;\n cloned.srcset = \"\";\n cloned.dataset.originalSrc = originalSrc;\n cloned.src = url || \"\";\n })\n ];\n }\n if (IN_SAFARI || IN_FIREFOX) {\n context.drawImageCount++;\n }\n } else if (isSVGElementNode(cloned) && !isDataUrl(cloned.href.baseVal)) {\n const originalSrc = cloned.href.baseVal;\n return [\n contextFetch(context, {\n url: originalSrc,\n imageDom: cloned,\n requestType: \"image\",\n responseType: \"dataUrl\"\n }).then((url) => {\n if (!url)\n return;\n cloned.dataset.originalSrc = originalSrc;\n cloned.href.baseVal = url || \"\";\n })\n ];\n }\n return [];\n}\n\nfunction embedSvgUse(cloned, context) {\n const { ownerDocument, svgDefsElement } = context;\n const href = cloned.getAttribute(\"href\") ?? cloned.getAttribute(\"xlink:href\");\n if (!href)\n return [];\n const [svgUrl, id] = href.split(\"#\");\n if (id) {\n const query = `#${id}`;\n const definition = context.shadowRoots.reduce(\n (res, root) => {\n return res ?? root.querySelector(`svg ${query}`);\n },\n ownerDocument?.querySelector(`svg ${query}`)\n );\n if (svgUrl) {\n cloned.setAttribute(\"href\", query);\n }\n if (svgDefsElement?.querySelector(query))\n return [];\n if (definition) {\n svgDefsElement?.appendChild(definition.cloneNode(true));\n return [];\n } else if (svgUrl) {\n return [\n contextFetch(context, {\n url: svgUrl,\n responseType: \"text\"\n }).then((svgData) => {\n svgDefsElement?.insertAdjacentHTML(\"beforeend\", svgData);\n })\n ];\n }\n }\n return [];\n}\n\nfunction embedNode(cloned, context) {\n const { tasks } = context;\n if (isElementNode(cloned)) {\n if (isImageElement(cloned) || isSVGImageElementNode(cloned)) {\n tasks.push(...embedImageElement(cloned, context));\n }\n if (isSVGUseElementNode(cloned)) {\n tasks.push(...embedSvgUse(cloned, context));\n }\n }\n if (isHTMLElementNode(cloned)) {\n tasks.push(...embedCssStyleImage(cloned.style, context));\n }\n cloned.childNodes.forEach((child) => {\n embedNode(child, context);\n });\n}\n\nasync function embedWebFont(clone, context) {\n const {\n ownerDocument,\n svgStyleElement,\n fontFamilies,\n fontCssTexts,\n tasks,\n font\n } = context;\n if (!ownerDocument || !svgStyleElement || !fontFamilies.size) {\n return;\n }\n if (font && font.cssText) {\n const cssText = filterPreferredFormat(font.cssText, context);\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText}\n`));\n } else {\n const styleSheets = Array.from(ownerDocument.styleSheets).filter((styleSheet) => {\n try {\n return \"cssRules\" in styleSheet && Boolean(styleSheet.cssRules.length);\n } catch (error) {\n context.log.warn(`Error while reading CSS rules from ${styleSheet.href}`, error);\n return false;\n }\n });\n const tempDoc = ownerDocument.implementation.createHTMLDocument(\"\");\n const tempStyleEl = tempDoc.createElement(\"style\");\n tempDoc.head.appendChild(tempStyleEl);\n const tempStyleSheet = tempStyleEl.sheet;\n await Promise.all(\n styleSheets.flatMap((styleSheet) => {\n return Array.from(styleSheet.cssRules).map(async (cssRule) => {\n if (isCSSImportRule(cssRule)) {\n const baseUrl = cssRule.href;\n let cssText = \"\";\n try {\n cssText = await contextFetch(context, {\n url: baseUrl,\n requestType: \"text\",\n responseType: \"text\"\n });\n } catch (error) {\n context.log.warn(`Error fetch remote css import from ${baseUrl}`, error);\n }\n const replacedCssText = cssText.replace(\n URL_RE,\n (raw, quotation, url) => raw.replace(url, resolveUrl(url, baseUrl))\n );\n for (const rule of parseCss(replacedCssText)) {\n try {\n tempStyleSheet.insertRule(rule, tempStyleSheet.cssRules.length);\n } catch (error) {\n context.log.warn(\"Error inserting rule from remote css import\", { rule, error });\n }\n }\n }\n });\n })\n );\n if (tempStyleSheet.cssRules.length)\n styleSheets.push(tempStyleSheet);\n const cssRules = [];\n styleSheets.forEach((sheet) => {\n unwrapCssLayers(sheet.cssRules, cssRules);\n });\n cssRules.filter((cssRule) => isCssFontFaceRule(cssRule) && hasCssUrl(cssRule.style.getPropertyValue(\"src\")) && splitFontFamily(cssRule.style.getPropertyValue(\"font-family\"))?.some((val) => fontFamilies.has(val))).forEach((value) => {\n const rule = value;\n const cssText = fontCssTexts.get(rule.cssText);\n if (cssText) {\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText}\n`));\n } else {\n tasks.push(\n replaceCssUrlToDataUrl(\n rule.cssText,\n rule.parentStyleSheet ? rule.parentStyleSheet.href : null,\n context\n ).then((cssText2) => {\n cssText2 = filterPreferredFormat(cssText2, context);\n fontCssTexts.set(rule.cssText, cssText2);\n svgStyleElement.appendChild(ownerDocument.createTextNode(`${cssText2}\n`));\n })\n );\n }\n });\n }\n}\nconst COMMENTS_RE = /(\\/\\*[\\s\\S]*?\\*\\/)/g;\nconst KEYFRAMES_RE = /((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})/gi;\nfunction parseCss(source) {\n if (source == null)\n return [];\n const result = [];\n let cssText = source.replace(COMMENTS_RE, \"\");\n while (true) {\n const matches = KEYFRAMES_RE.exec(cssText);\n if (!matches)\n break;\n result.push(matches[0]);\n }\n cssText = cssText.replace(KEYFRAMES_RE, \"\");\n const IMPORT_RE = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi;\n const UNIFIED_RE = new RegExp(\n // eslint-disable-next-line\n \"((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})\",\n \"gi\"\n );\n while (true) {\n let matches = IMPORT_RE.exec(cssText);\n if (!matches) {\n matches = UNIFIED_RE.exec(cssText);\n if (!matches) {\n break;\n } else {\n IMPORT_RE.lastIndex = UNIFIED_RE.lastIndex;\n }\n } else {\n UNIFIED_RE.lastIndex = IMPORT_RE.lastIndex;\n }\n result.push(matches[0]);\n }\n return result;\n}\nconst URL_WITH_FORMAT_RE = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g;\nconst FONT_SRC_RE = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g;\nfunction filterPreferredFormat(str, context) {\n const { font } = context;\n const preferredFormat = font ? font?.preferredFormat : void 0;\n return preferredFormat ? str.replace(FONT_SRC_RE, (match) => {\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_RE.exec(match) || [];\n if (!format)\n return \"\";\n if (format === preferredFormat)\n return `src: ${src};`;\n }\n }) : str;\n}\nfunction unwrapCssLayers(rules, out = []) {\n for (const rule of Array.from(rules)) {\n if (isLayerBlockRule(rule)) {\n out.push(...unwrapCssLayers(rule.cssRules));\n } else if (\"cssRules\" in rule) {\n unwrapCssLayers(rule.cssRules, out);\n } else {\n out.push(rule);\n }\n }\n return out;\n}\n\nconst SVG_EXTERNAL_RESOURCE_REGEX = /\\bx?link:?href\\s*=\\s*[\"'](?!data:)[^\"']+[\"']/i;\nfunction svgHasExternalResources(svg) {\n return SVG_EXTERNAL_RESOURCE_REGEX.test(svg.innerHTML);\n}\nasync function domToForeignObjectSvg(node, options) {\n const context = await orCreateContext(node, options);\n if (isElementNode(context.node) && isSVGElementNode(context.node) && !svgHasExternalResources(context.node))\n return context.node;\n const {\n ownerDocument,\n log,\n tasks,\n svgStyleElement,\n svgDefsElement,\n svgStyles,\n font,\n progress,\n autoDestruct,\n onCloneNode,\n onEmbedNode,\n onCreateForeignObjectSvg\n } = context;\n log.time(\"clone node\");\n const clone = await cloneNode(context.node, context, true);\n if (svgStyleElement && ownerDocument) {\n let allCssText = \"\";\n svgStyles.forEach((klasses, cssText) => {\n allCssText += `${klasses.join(\",\\n\")} {\n ${cssText}\n}\n`;\n });\n svgStyleElement.appendChild(ownerDocument.createTextNode(allCssText));\n }\n log.timeEnd(\"clone node\");\n await onCloneNode?.(clone);\n if (font !== false && isElementNode(clone)) {\n log.time(\"embed web font\");\n await embedWebFont(clone, context);\n log.timeEnd(\"embed web font\");\n }\n log.time(\"embed node\");\n embedNode(clone, context);\n const count = tasks.length;\n let current = 0;\n const runTask = async () => {\n while (true) {\n const task = tasks.pop();\n if (!task)\n break;\n try {\n await task;\n } catch (error) {\n context.log.warn(\"Failed to run task\", error);\n }\n progress?.(++current, count);\n }\n };\n progress?.(current, count);\n await Promise.all([...Array.from({ length: 4 })].map(runTask));\n log.timeEnd(\"embed node\");\n await onEmbedNode?.(clone);\n const svg = createForeignObjectSvg(clone, context);\n svgDefsElement && svg.insertBefore(svgDefsElement, svg.children[0]);\n svgStyleElement && svg.insertBefore(svgStyleElement, svg.children[0]);\n autoDestruct && destroyContext(context);\n await onCreateForeignObjectSvg?.(svg);\n return svg;\n}\nfunction createForeignObjectSvg(clone, context) {\n const { width, height } = context;\n const svg = createSvg(width, height, clone.ownerDocument);\n const foreignObject = svg.ownerDocument.createElementNS(svg.namespaceURI, \"foreignObject\");\n foreignObject.setAttributeNS(null, \"x\", \"0%\");\n foreignObject.setAttributeNS(null, \"y\", \"0%\");\n foreignObject.setAttributeNS(null, \"width\", \"100%\");\n foreignObject.setAttributeNS(null, \"height\", \"100%\");\n foreignObject.append(clone);\n svg.appendChild(foreignObject);\n return svg;\n}\n\nasync function domToCanvas(node, options) {\n const context = await orCreateContext(node, options);\n const svg = await domToForeignObjectSvg(context);\n const dataUrl = svgToDataUrl(svg, context.isEnable(\"removeControlCharacter\"));\n if (!context.autoDestruct) {\n context.svgStyleElement = createStyleElement(context.ownerDocument);\n context.svgDefsElement = context.ownerDocument?.createElementNS(XMLNS, \"defs\");\n context.svgStyles.clear();\n }\n const image = createImage(dataUrl, svg.ownerDocument);\n return await imageToCanvas(image, context);\n}\n\nasync function domToBlob(node, options) {\n const context = await orCreateContext(node, options);\n const { log, type, quality, dpi } = context;\n const canvas = await domToCanvas(context);\n log.time(\"canvas to blob\");\n const blob = await canvasToBlob(canvas, type, quality);\n if ([\"image/png\", \"image/jpeg\"].includes(type) && dpi) {\n const arrayBuffer = await blobToArrayBuffer(blob.slice(0, 33));\n let uint8Array = new Uint8Array(arrayBuffer);\n if (type === \"image/png\") {\n uint8Array = changePngDpi(uint8Array, dpi);\n } else if (type === \"image/jpeg\") {\n uint8Array = changeJpegDpi(uint8Array, dpi);\n }\n log.timeEnd(\"canvas to blob\");\n return new Blob([uint8Array, blob.slice(33)], { type });\n }\n log.timeEnd(\"canvas to blob\");\n return blob;\n}\n\nasync function domToDataUrl(node, options) {\n const context = await orCreateContext(node, options);\n const { log, quality, type, dpi } = context;\n const canvas = await domToCanvas(context);\n log.time(\"canvas to data url\");\n let dataUrl = canvas.toDataURL(type, quality);\n if ([\"image/png\", \"image/jpeg\"].includes(type) && dpi && SUPPORT_ATOB && SUPPORT_BTOA) {\n const [format, body] = dataUrl.split(\",\");\n let headerLength = 0;\n let overwritepHYs = false;\n if (type === \"image/png\") {\n const b64Index = detectPhysChunkFromDataUrl(body);\n if (b64Index >= 0) {\n headerLength = Math.ceil((b64Index + 28) / 3) * 4;\n overwritepHYs = true;\n } else {\n headerLength = 33 / 3 * 4;\n }\n } else if (type === \"image/jpeg\") {\n headerLength = 18 / 3 * 4;\n }\n const stringHeader = body.substring(0, headerLength);\n const restOfData = body.substring(headerLength);\n const headerBytes = window.atob(stringHeader);\n const uint8Array = new Uint8Array(headerBytes.length);\n for (let i = 0; i < uint8Array.length; i++) {\n uint8Array[i] = headerBytes.charCodeAt(i);\n }\n const finalArray = type === \"image/png\" ? changePngDpi(uint8Array, dpi, overwritepHYs) : changeJpegDpi(uint8Array, dpi);\n const base64Header = window.btoa(String.fromCharCode(...finalArray));\n dataUrl = [format, \",\", base64Header, restOfData].join(\"\");\n }\n log.timeEnd(\"canvas to data url\");\n return dataUrl;\n}\n\nasync function domToSvg(node, options) {\n const context = await orCreateContext(node, options);\n const { width, height, ownerDocument } = context;\n const dataUrl = await domToDataUrl(context);\n const svg = createSvg(width, height, ownerDocument);\n const svgImage = svg.ownerDocument.createElementNS(svg.namespaceURI, \"image\");\n svgImage.setAttributeNS(null, \"href\", dataUrl);\n svgImage.setAttributeNS(null, \"height\", \"100%\");\n svgImage.setAttributeNS(null, \"width\", \"100%\");\n svg.appendChild(svgImage);\n return svgToDataUrl(svg, context.isEnable(\"removeControlCharacter\"));\n}\n\nasync function domToImage(node, options) {\n const context = await orCreateContext(node, options);\n const { ownerDocument, width, height, scale, type } = context;\n const url = type === \"image/svg+xml\" ? await domToSvg(context) : await domToDataUrl(context);\n const image = createImage(url, ownerDocument);\n image.width = Math.floor(width * scale);\n image.height = Math.floor(height * scale);\n image.style.width = `${width}px`;\n image.style.height = `${height}px`;\n return image;\n}\n\nasync function domToJpeg(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/jpeg\" })\n );\n}\n\nasync function domToPixel(node, options) {\n const context = await orCreateContext(node, options);\n const canvas = await domToCanvas(context);\n return canvas.getContext(\"2d\").getImageData(0, 0, canvas.width, canvas.height).data;\n}\n\nasync function domToPng(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/png\" })\n );\n}\n\nasync function domToWebp(node, options) {\n return domToDataUrl(\n await orCreateContext(node, { ...options, type: \"image/webp\" })\n );\n}\n\nexport { createContext, destroyContext, domToBlob, domToCanvas, domToDataUrl, domToForeignObjectSvg, domToImage, domToJpeg, domToPixel, domToPng, domToSvg, domToWebp, loadMedia, waitUntilLoad };\n","import { domToPng } from \"modern-screenshot\";\nimport type { ElementContext, RegionRect } from \"./types.js\";\n\nconst STYLE_KEYS = [\n \"display\", \"position\", \"width\", \"height\", \"margin\", \"padding\",\n \"color\", \"background-color\", \"font-size\", \"font-weight\", \"font-family\",\n \"border\", \"border-radius\", \"box-shadow\", \"flex\", \"grid-template-columns\",\n \"text-align\", \"line-height\", \"opacity\",\n];\n\n/** outerHTML + a curated slice of computed styles — the context handed to Claude. */\nexport function captureElementContext(el: Element): ElementContext {\n const html = el.outerHTML.length > 6000 ? el.outerHTML.slice(0, 6000) + \"…\" : el.outerHTML;\n const cs = getComputedStyle(el);\n const styles: Record<string, string> = {};\n for (const k of STYLE_KEYS) {\n const v = cs.getPropertyValue(k);\n if (v) styles[k] = v.trim();\n }\n return { html, styles };\n}\n\n/** Max time (ms) any single capture may spend fetching/embedding assets. */\nconst CAPTURE_TIMEOUT = 6000;\n\n/** Resolve `undefined` if `p` doesn't settle within `ms` — so a capture can never hang the UI. */\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T | undefined> {\n return Promise.race([p, new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), ms))]);\n}\n\n/**\n * Give web fonts a brief chance to finish loading so they embed instead of\n * falling back — but NEVER block on it. On some SPAs `document.fonts.ready`\n * settles slowly (or keeps loading), which would otherwise hang the capture,\n * so we race it against a short cap.\n */\nasync function fontsReady(): Promise<void> {\n try {\n const fonts = (document as Document & { fonts?: FontFaceSet }).fonts;\n if (!fonts?.ready) return;\n await Promise.race([\n fonts.ready,\n new Promise<void>((resolve) => setTimeout(resolve, 800)),\n ]);\n } catch {\n /* FontFaceSet unsupported — carry on */\n }\n}\n\n/** Skip Loupe's own UI and redacted elements in any capture. */\nfunction captureFilter(node: Node): boolean {\n if (!(node instanceof Element)) return true;\n if (node.id === \"loupe-root\") return false;\n if (node.hasAttribute(\"data-loupe-redact\")) return false;\n return true;\n}\n\n/**\n * Screenshot the target element. Elements marked [data-loupe-redact] are\n * excluded before anything leaves the browser, and our own UI is never captured.\n */\nexport async function captureScreenshot(el: Element): Promise<string | undefined> {\n try {\n await fontsReady();\n return await withTimeout(\n domToPng(el as HTMLElement, {\n scale: Math.min(window.devicePixelRatio || 1, 2),\n backgroundColor: getComputedStyle(document.body).backgroundColor || \"#ffffff\",\n timeout: CAPTURE_TIMEOUT,\n filter: captureFilter,\n }),\n CAPTURE_TIMEOUT + 2000,\n );\n } catch (err) {\n console.warn(\"[loupe] screenshot capture failed\", err);\n return undefined;\n }\n}\n\n/**\n * Screenshot a free-form rectangle (the \"region shot\"). `rect` is in **viewport**\n * coordinates (what's on screen now). The default renders the whole page and crops;\n * the extension overrides this with a real captureVisibleTab crop. Redacted regions\n * are painted over before the pixels leave the browser.\n */\nexport async function captureRegionScreenshot(rect: RegionRect): Promise<string | undefined> {\n try {\n await fontsReady();\n const scale = Math.min(window.devicePixelRatio || 1, 2);\n // Render the SMALLEST element that fully covers the selection, not the whole\n // page. Rendering document.body is heavy and its cross-origin font embedding\n // often times out (→ fallback fonts, reflow); a scoped subtree behaves like\n // the reliable element capture.\n const container = regionContainer(rect);\n const origin = container.getBoundingClientRect();\n const full = await withTimeout(\n domToPng(container, {\n scale,\n backgroundColor: getComputedStyle(document.body).backgroundColor || \"#ffffff\",\n timeout: CAPTURE_TIMEOUT,\n filter: captureFilter,\n }),\n CAPTURE_TIMEOUT + 2000,\n );\n if (!full) return undefined;\n const redact = Array.from(document.querySelectorAll(\"[data-loupe-redact]\")).map((n) =>\n (n as Element).getBoundingClientRect(),\n );\n return await cropRegion(full, rect, origin.left, origin.top, scale, redact);\n } catch (err) {\n console.warn(\"[loupe] region capture failed\", err);\n return undefined;\n }\n}\n\n/** The smallest on-page element whose box fully covers the selection rectangle. */\nfunction regionContainer(rect: RegionRect): HTMLElement {\n const cx = rect.x + rect.w / 2;\n const cy = rect.y + rect.h / 2;\n let node = document.elementFromPoint(cx, cy) as HTMLElement | null;\n if (node && node.closest(\"#loupe-root\")) node = null; // never our own UI\n const covers = (r: DOMRect) =>\n r.left <= rect.x && r.top <= rect.y && r.right >= rect.x + rect.w && r.bottom >= rect.y + rect.h;\n while (node && node !== document.body && node !== document.documentElement) {\n if (covers(node.getBoundingClientRect())) return node;\n node = node.parentElement;\n }\n return document.body;\n}\n\n/** Options for a screen recording. */\nexport interface RecordOptions {\n /** Auto-stop after this many ms (a safety cap so recordings never run forever). */\n maxMs?: number;\n /** Called once with a `stop()` fn so the caller can wire a Stop button to it. */\n register?: (stop: () => void) => void;\n}\n\n/** Best available webm MIME the browser can record, or \"\" to let MediaRecorder pick. */\nfunction pickRecordingMime(): string {\n const MR: any = (window as any).MediaRecorder;\n if (!MR?.isTypeSupported) return \"\";\n for (const t of [\"video/webm;codecs=vp9\", \"video/webm;codecs=vp8\", \"video/webm\"]) {\n if (MR.isTypeSupported(t)) return t;\n }\n return \"\";\n}\n\nfunction blobToDataUrl(blob: Blob): Promise<string> {\n return new Promise((resolve, reject) => {\n const r = new FileReader();\n r.onload = () => resolve(String(r.result));\n r.onerror = () => reject(r.error);\n r.readAsDataURL(blob);\n });\n}\n\n/** Read a file the reporter picked into a data URL (for upload, or offline storage). */\nexport function fileToDataUrl(file: File): Promise<string> {\n return blobToDataUrl(file);\n}\n\n/** Classify an attachment by MIME type — videos play inline, images render as thumbs. */\nexport function attachmentKind(mime: string | undefined): \"image\" | \"video\" {\n return (mime ?? \"\").startsWith(\"video/\") ? \"video\" : \"image\";\n}\n\n/**\n * Record a screen video cropped to `rect` (viewport coords), mirroring the region\n * screenshot flow. Uses getDisplayMedia (real pixels) — the browser shows a share\n * prompt; picking the current tab keeps the crop aligned. Each frame is drawn to a\n * canvas cropped to the selection, then re-encoded to webm. Returns a data URL, or\n * undefined if the user cancels the prompt or recording isn't supported. The default\n * is overridable via LoupeConfig.captureRecording (e.g. the extension).\n */\nexport async function captureRegionRecording(rect: RegionRect, opts?: RecordOptions): Promise<string | undefined> {\n const md = navigator.mediaDevices as MediaDevices & {\n getDisplayMedia?: (c?: any) => Promise<MediaStream>;\n };\n if (!md?.getDisplayMedia || !(window as any).MediaRecorder) return undefined;\n\n let stream: MediaStream;\n try {\n stream = await md.getDisplayMedia({ video: { frameRate: 30 }, audio: false, preferCurrentTab: true } as any);\n } catch {\n return undefined; // user dismissed the picker\n }\n\n try {\n return await recordCropped(stream, rect, opts);\n } catch (err) {\n console.warn(\"[loupe] screen recording failed\", err);\n return undefined;\n } finally {\n stream.getTracks().forEach((t) => t.stop());\n }\n}\n\nasync function recordCropped(stream: MediaStream, rect: RegionRect, opts?: RecordOptions): Promise<string | undefined> {\n const maxMs = opts?.maxMs ?? 20000;\n const video = document.createElement(\"video\");\n video.srcObject = stream;\n video.muted = true;\n (video as any).playsInline = true;\n await video.play().catch(() => undefined);\n\n const track = stream.getVideoTracks()[0];\n const s = track?.getSettings?.() ?? {};\n const vw = (s.width as number) || video.videoWidth || window.innerWidth;\n const vh = (s.height as number) || video.videoHeight || window.innerHeight;\n // The shared surface (ideally the current tab) maps to the page viewport by scale.\n const sx = vw / window.innerWidth;\n const sy = vh / window.innerHeight;\n const cw = Math.max(2, Math.round(rect.w * sx));\n const ch = Math.max(2, Math.round(rect.h * sy));\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = cw;\n canvas.height = ch;\n const ctx = canvas.getContext(\"2d\")!;\n let raf = 0;\n const draw = () => {\n try { ctx.drawImage(video, rect.x * sx, rect.y * sy, cw, ch, 0, 0, cw, ch); } catch { /* not ready yet */ }\n raf = requestAnimationFrame(draw);\n };\n draw();\n\n const out = (canvas as HTMLCanvasElement & { captureStream(fps?: number): MediaStream }).captureStream(30);\n const mime = pickRecordingMime();\n const rec = new MediaRecorder(out, mime ? { mimeType: mime } : undefined);\n const chunks: BlobPart[] = [];\n rec.ondataavailable = (e) => { if (e.data && e.data.size) chunks.push(e.data); };\n\n const stop = () => { if (rec.state !== \"inactive\") rec.stop(); };\n opts?.register?.(stop);\n // Auto-stop on the cap, or when the user ends the share via the browser UI.\n const timer = window.setTimeout(stop, maxMs);\n track?.addEventListener(\"ended\", stop);\n\n const done = new Promise<void>((resolve) => { rec.onstop = () => resolve(); });\n rec.start();\n await done;\n\n window.clearTimeout(timer);\n cancelAnimationFrame(raf);\n if (!chunks.length) return undefined;\n return blobToDataUrl(new Blob(chunks, { type: mime || \"video/webm\" }));\n}\n\n/** Crop `rect` (viewport coords) out of a full-page data URL whose origin sits at (ox, oy). */\nfunction cropRegion(\n dataUrl: string,\n rect: RegionRect,\n ox: number,\n oy: number,\n scale: number,\n redact: DOMRect[],\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const sw = Math.max(1, Math.round(rect.w * scale));\n const sh = Math.max(1, Math.round(rect.h * scale));\n const canvas = document.createElement(\"canvas\");\n canvas.width = sw;\n canvas.height = sh;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(img, (rect.x - ox) * scale, (rect.y - oy) * scale, sw, sh, 0, 0, sw, sh);\n ctx.fillStyle = \"#0f0f14\";\n for (const r of redact) {\n ctx.fillRect((r.left - rect.x) * scale, (r.top - rect.y) * scale, r.width * scale, r.height * scale);\n }\n resolve(canvas.toDataURL(\"image/png\"));\n };\n img.onerror = reject;\n img.src = dataUrl;\n });\n}\n","/**\n * The activity contract.\n *\n * The panel renders a live feed of what an agent (or the host app) is doing.\n * Nothing here knows *who* produces the events: the bridge, an MCP-driven agent\n * and the host application all push through the same shape, and the SDK emits its\n * own operations into it too, so the view is useful before a bridge exists.\n */\nexport const ACTIVITY_STATUSES = [\"idle\", \"working\", \"error\"];\nexport const ACTIVITY_STATUS_LABELS = {\n idle: \"Idle\",\n working: \"Working\",\n error: \"Error\",\n};\n/** \"2m 14s\" / \"48s\" / \"—\" for a duration in ms. */\nexport function formatDuration(ms) {\n if (!ms || ms < 0)\n return \"—\";\n const s = Math.round(ms / 1000);\n if (s < 60)\n return `${s}s`;\n const m = Math.floor(s / 60);\n const rest = s % 60;\n if (m < 60)\n return rest ? `${m}m ${rest}s` : `${m}m`;\n const h = Math.floor(m / 60);\n return `${h}h ${m % 60}m`;\n}\n/**\n * Derive the summary from a feed. Pure, so the panel and any other consumer agree\n * on what the numbers mean.\n */\nexport function summarizeActivity(events, status = \"idle\", now = Date.now()) {\n const files = new Set();\n const kinds = new Map();\n let errors = 0;\n let first = Infinity;\n for (const e of events) {\n for (const f of e.files ?? [])\n files.add(f);\n kinds.set(e.kind, (kinds.get(e.kind) ?? 0) + 1);\n if (e.level === \"error\")\n errors++;\n const t = Date.parse(e.at);\n if (!Number.isNaN(t))\n first = Math.min(first, t);\n }\n return {\n status,\n events: events.length,\n errors,\n files: files.size,\n durationMs: events.length && first !== Infinity ? Math.max(0, now - first) : 0,\n byKind: [...kinds.entries()]\n .map(([kind, count]) => ({ kind, count }))\n .sort((a, b) => b.count - a.count || a.kind.localeCompare(b.kind)),\n };\n}\n","/**\n * The lifecycle of a thread's change.\n *\n * A thread does not just sit on a board — its fix moves through an agent, a pull\n * request and a preview. This module is the single definition of that progression,\n * so the panel's chips, the dashboard and anything else agree on what \"In PR\" means.\n *\n * The rule the whole flow rests on: **only a human resolves a thread.** An agent\n * moves work to In Review; a person approves it from there.\n */\nexport const LIFECYCLE_LABELS = {\n sent: \"Sent to agent\",\n in_pr: \"In PR\",\n preview: \"Review preview\",\n reviewed: \"Reviewed\",\n};\n/**\n * Derive the chip for a thread, or `null` when there is nothing to say — an\n * untouched thread in Queue should not wear a badge explaining that.\n *\n * Precedence is deliberate: a merged PR outranks the board stage, because \"Reviewed\"\n * on a resolved thread and \"In PR\" on an open one are both more specific than the\n * column it sits in.\n */\nexport function lifecycle(c) {\n const hasProposal = !!c.proposal;\n const pr = c.pr ?? undefined;\n const withPr = (stage) => {\n const out = { stage, label: LIFECYCLE_LABELS[stage] };\n if (pr) {\n out.pr = pr;\n if (typeof pr.checksTotal === \"number\" && pr.checksTotal > 0) {\n const passed = Math.max(0, Math.min(pr.checksTotal, pr.checksPassed ?? 0));\n out.checks = {\n text: `${passed}/${pr.checksTotal}`,\n ratio: passed / pr.checksTotal,\n };\n }\n }\n return out;\n };\n if (c.status === \"resolved\")\n return hasProposal || pr ? withPr(\"reviewed\") : null;\n if (pr)\n return withPr(\"in_pr\");\n if (c.status === \"in_review\")\n return { stage: \"preview\", label: LIFECYCLE_LABELS.preview };\n if (hasProposal)\n return { stage: \"sent\", label: LIFECYCLE_LABELS.sent };\n return null;\n}\n/** Threads a reviewer still has to look at. */\nexport function awaitingReview(comments) {\n return comments.filter((c) => c.status === \"in_review\");\n}\n","/**\n * Iteration history for a generated change.\n *\n * Generating a change is not a one-shot: you generate, look at it, ask for a\n * refinement, look again. This is the pure model of that stack, so the panel's\n * preview pane and anything else agree on what \"the current iteration\" is — and so\n * the undo/prev/next rules can be tested without a DOM.\n */\nexport function emptyIterations() {\n return { items: [], index: -1 };\n}\n/** The iteration currently being previewed, or null when there is none. */\nexport function current(state) {\n return state.index >= 0 ? state.items[state.index] ?? null : null;\n}\n/**\n * Push a new iteration and preview it.\n *\n * A new iteration is appended **after** the current one rather than always at the\n * end, so generating from a point in the history branches there instead of silently\n * discarding what came later. The tail beyond the current index is dropped, because\n * a preview must always describe a real lineage.\n */\nexport function addIteration(state, iteration) {\n const head = state.items.slice(0, state.index + 1);\n const items = [...head, iteration].slice(-MAX_ITERATIONS);\n return { items, index: items.length - 1 };\n}\n/** Cap the stack — this is a working history, not an archive. */\nexport const MAX_ITERATIONS = 20;\nexport function canUndo(state) {\n return state.items.length > 0;\n}\n/**\n * Discard the newest iteration and preview the one before it. Distinct from\n * stepping back: undo throws the work away, `move(-1)` keeps it for the redo.\n */\nexport function undo(state) {\n if (!state.items.length)\n return state;\n const items = state.items.slice(0, -1);\n return { items, index: items.length - 1 };\n}\nexport function canMove(state, delta) {\n const next = state.index + delta;\n return next >= 0 && next < state.items.length;\n}\n/** Step through the history without discarding anything. */\nexport function move(state, delta) {\n return canMove(state, delta) ? { ...state, index: state.index + delta } : state;\n}\n/** \"2 / 3\" for the navigation counter, or \"\" when there is nothing to navigate. */\nexport function stackLabel(state) {\n return state.items.length ? `${state.index + 1} / ${state.items.length}` : \"\";\n}\n","/**\n * Letting an agent move the browser.\n *\n * An agent that can navigate is genuinely useful — \"the fix is on the preview URL,\n * let me show you\" — and genuinely dangerous if it happens silently. So navigation\n * is a **request** that a human answers, and the only way to get a URL out of this\n * module is to have granted one.\n *\n * The state machine is pure and lives here (not in the panel) because the safety\n * property is the point: `decide()` returns a URL only on an explicit grant, and\n * that is what the tests pin down.\n */\nexport function emptyConsent() {\n return { state: \"idle\", request: null, history: [] };\n}\n/** Only absolute http(s) may be requested — `javascript:` and friends never are. */\nexport function isNavigableUrl(raw) {\n try {\n const u = new URL(raw);\n return u.protocol === \"http:\" || u.protocol === \"https:\";\n }\n catch {\n return false;\n }\n}\n/**\n * Queue a navigation request for the user to answer. A second request replaces the\n * first: two prompts at once would be a good way to get a careless yes.\n */\nexport function requestNavigation(record, request) {\n if (!isNavigableUrl(request.url))\n return record;\n return {\n state: \"requested\",\n request: {\n id: request.id ?? `nav${Date.now().toString(36)}`,\n at: request.at ?? new Date().toISOString(),\n url: request.url,\n reason: request.reason,\n requester: request.requester,\n },\n history: record.history,\n };\n}\nexport function isPending(record) {\n return record.state === \"requested\" && record.request !== null;\n}\n/**\n * Answer the pending request.\n *\n * Returns the record plus the URL to navigate to — `null` unless the user actually\n * granted it. Callers must use this return value rather than reading the request\n * themselves, which is the whole point: there is no path to a URL that skips the\n * decision.\n */\nexport function decide(record, granted, now = new Date().toISOString()) {\n if (!isPending(record))\n return { record, navigateTo: null };\n const url = record.request.url;\n return {\n record: {\n state: granted ? \"granted\" : \"denied\",\n request: null,\n history: [...record.history, { url, decision: granted ? \"granted\" : \"denied\", at: now }],\n },\n navigateTo: granted ? url : null,\n };\n}\n/** Drop a pending request without deciding (a timeout, the panel closing). */\nexport function withdraw(record) {\n return isPending(record) ? { ...record, state: \"idle\", request: null } : record;\n}\n","/**\n * Thread messages.\n *\n * A comment used to be one body. That is not a conversation: an agent has to be able\n * to reply, a reviewer to answer, and each message to carry its own attachments. This\n * is the model everything downstream (mentions, activity, notification) depends on.\n *\n * The legacy single `body` stays exactly as it was and is *also* message #1 — see\n * `firstMessageFromComment`. Nothing had to be migrated to make replies work.\n */\n/**\n * The comment's own body, presented as the first message of its thread.\n *\n * Synthesised rather than stored, so there is no backfill to run and no window where\n * a thread renders with no messages. The id is derived from the comment so it is\n * stable across calls — a UI list keyed on it does not flicker.\n */\nexport function firstMessageFromComment(comment) {\n return {\n id: `${comment.id}:0`,\n threadId: comment.id,\n author: { ...comment.author, type: \"user\" },\n body: comment.body,\n attachments: comment.attachments?.length ? comment.attachments : undefined,\n createdAt: comment.createdAt,\n };\n}\n/** The first message plus every reply, oldest first. */\nexport function threadConversation(comment, replies, opts = {}) {\n // A retracted message is not part of the conversation as anyone reads it. The\n // record survives in the store for whoever needs it.\n const visible = opts.includeDeleted ? replies : replies.filter((m) => !m.deletedAt);\n return [firstMessageFromComment(comment), ...visible].sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n}\n/** Replies a reader should see — never the retracted ones. */\nexport function visibleMessages(messages) {\n return messages.filter((m) => !m.deletedAt);\n}\n/** Who has taken part, in the order they first spoke. */\nexport function participantsOf(messages) {\n const seen = new Map();\n for (const m of messages)\n if (!seen.has(m.author.id))\n seen.set(m.author.id, m.author);\n return [...seen.values()];\n}\n/** Whether a message came from an agent rather than a person. */\nexport function isAgentMessage(m) {\n return m.author.type === \"agent\";\n}\n/** \"Iteration 2\" — or nothing at all for an original thread. */\nexport function iterationLabel(link) {\n if (!link.parentThreadId || link.iterationType !== \"revision\")\n return null;\n return `Iteration ${link.iterationNumber ?? 2}`;\n}\n/** The event a new reply publishes, so an open thread can refresh itself. */\nexport const THREAD_MESSAGE_ADDED = \"message_added\";\n/** …and a retraction, so the other side stops showing it. */\nexport const THREAD_MESSAGE_DELETED = \"message_deleted\";\n","/**\n * The thread timeline.\n *\n * \"Agent activity on your feedback\" — what actually happened, in order. Built from\n * what the thread already carries (its stage, its PR, its proposal, its replies)\n * rather than from a separate event log, so it cannot drift from the truth: if the\n * timeline says a PR was opened, there is a `pr` on the comment saying so.\n *\n * Pure, so the panel and the dashboard render the same story.\n */\n/** \"a <button> “Complete checkout”\" — how the captured thing reads in a timeline. */\nexport function describeTarget(input) {\n const parts = [];\n if (input.anchor?.tag)\n parts.push(`a <${input.anchor.tag}>`);\n if (input.anchor?.selector)\n parts.push(`\\`${input.anchor.selector}\\``);\n return parts.length ? parts.join(\" \") : input.kind === \"free\" ? \"a page note\" : \"an element\";\n}\n/**\n * The story of a thread, oldest first.\n *\n * Stages are read from the thread's *current* state, so a step that was skipped does\n * not appear — there is no \"preview live\" row for a thread that never had one. The\n * timestamps for those steps are not stored, so they borrow the newest message's time;\n * that is a real limitation and the reason the entries are ordered by stage rather\n * than pretending to a precision we do not have.\n */\nexport function threadTimeline(input, messages = []) {\n const out = [];\n const latest = messages.length ? messages[messages.length - 1].at : input.createdAt;\n out.push({\n at: input.createdAt,\n kind: \"captured\",\n label: \"Feedback captured\",\n detail: [input.title, describeTarget(input)].filter(Boolean).join(\" · \"),\n });\n for (const m of messages) {\n out.push({\n at: m.at,\n kind: \"message\",\n label: `${m.authorName} replied`,\n actor: m.fromAgent ? m.authorName : undefined,\n });\n }\n const stage = normalizeStage(input.status);\n const reached = (s) => STAGE_ORDER.indexOf(stage) >= STAGE_ORDER.indexOf(s);\n if (input.proposal || reached(\"in_review\")) {\n const agent = input.proposal?.author ?? \"Claude Code\";\n out.push({\n at: input.proposal?.createdAt ?? latest,\n kind: \"sent\",\n label: `Change ready from ${agent}`,\n detail: \"The rewritten markup is on the thread.\",\n actor: agent,\n });\n }\n if (input.pr) {\n out.push({\n at: latest,\n kind: \"pr\",\n label: input.pr.number ? `Pull request #${input.pr.number} opened` : \"Pull request opened\",\n detail: input.pr.state === \"merged\" ? \"Merged.\" : input.pr.state === \"closed\" ? \"Closed without merging.\" : \"Waiting on review.\",\n });\n // Only when a URL is actually known — a preview is never inferred.\n if (input.pr.previewUrl) {\n out.push({ at: latest, kind: \"preview\", label: \"Preview live\", detail: input.pr.previewUrl });\n }\n }\n if (reached(\"in_review\")) {\n out.push({ at: latest, kind: \"review\", label: \"Waiting on a human review\", detail: \"Only a person can close this.\" });\n }\n if (stage === \"resolved\") {\n out.push({ at: latest, kind: \"resolved\", label: \"Resolved\", detail: \"A person closed this.\" });\n }\n return out;\n}\nconst STAGE_ORDER = [\"queue\", \"todo\", \"in_progress\", \"in_review\", \"resolved\"];\n/** Legacy names map onto the same stages, so an old row still renders a timeline. */\nfunction normalizeStage(status) {\n if (status === \"open\")\n return \"queue\";\n if (status === \"done\")\n return \"resolved\";\n return status;\n}\n/**\n * A thread as plain text, for pasting into a chat or a ticket.\n *\n * Deliberately starts with the element selector: pasted somewhere without Loupe, the\n * selector is the only part that still identifies *what* is being talked about.\n */\nexport function threadAsText(input, messages = []) {\n const lines = [\n `# ${input.title ?? \"Feedback\"} (#${input.id})`,\n \"\",\n `- Stage: ${normalizeStage(input.status)}`,\n `- Page: ${input.url ?? \"—\"}`,\n ];\n if (input.anchor?.selector)\n lines.push(`- Target: \\`${input.anchor.selector}\\``);\n if (input.pr?.number)\n lines.push(`- PR: #${input.pr.number}${input.pr.previewUrl ? ` · preview ${input.pr.previewUrl}` : \"\"}`);\n lines.push(\"\", \"## Request\", \"\", input.body);\n if (messages.length) {\n lines.push(\"\", \"## Conversation\", \"\");\n for (const m of messages)\n lines.push(`**${m.authorName}**${m.fromAgent ? \" (agent)\" : \"\"} — ${m.at}`, \"\", m.body, \"\");\n }\n return lines.join(\"\\n\");\n}\n","/**\n * @mentions.\n *\n * The failure mode that matters here is a *silent* one: a mention that looks like it\n * notified someone and did not. So parsing is conservative and the caller is told\n * which handles it could not resolve, rather than dropping them quietly.\n */\n/** A handle: letters, digits, and the punctuation people actually use in names. */\nconst HANDLE = /^[A-Za-z0-9][A-Za-z0-9._-]*/;\n/**\n * Ranges in the body that must not be searched: fenced blocks, inline code, and\n * `mailto:`-style text. A name inside a code sample is documentation, not a mention.\n */\nfunction excludedRanges(body) {\n const ranges = [];\n // Fenced blocks first, so an inline-code match inside one is not double counted.\n for (const m of body.matchAll(/```[\\s\\S]*?```/g))\n ranges.push([m.index, m.index + m[0].length]);\n const fenced = (i) => ranges.some(([a, b]) => i >= a && i < b);\n for (const m of body.matchAll(/`[^`\\n]*`/g)) {\n if (!fenced(m.index))\n ranges.push([m.index, m.index + m[0].length]);\n }\n return ranges;\n}\n/**\n * Every mention in a body.\n *\n * Deliberately *not* matched: an email address (`sara@acme.test`) — the `@` is\n * preceded by a word character, which no mention ever is. Trailing punctuation is\n * not part of the handle, so `@sara,` mentions `sara`.\n */\nexport function parseMentions(body) {\n if (!body)\n return [];\n const excluded = excludedRanges(body);\n const inExcluded = (i) => excluded.some(([a, b]) => i >= a && i < b);\n const out = [];\n const seen = new Set();\n for (let i = 0; i < body.length; i++) {\n if (body[i] !== \"@\")\n continue;\n if (inExcluded(i))\n continue;\n // A mention starts at the beginning of the body or after whitespace/opening\n // punctuation — never in the middle of a word, which is what rules out emails.\n const prev = i > 0 ? body[i - 1] : \"\";\n if (prev && !/[\\s([{<\"'*_~]/.test(prev))\n continue;\n const match = HANDLE.exec(body.slice(i + 1));\n if (!match)\n continue;\n const raw = match[0];\n // `@sara.` and `@sara,` end the handle at the punctuation; a dot *inside* a handle\n // (`@jane.doe`) is kept.\n const handle = raw.replace(/[._-]+$/, \"\");\n if (!handle)\n continue;\n const key = handle.toLowerCase();\n // The same person mentioned twice is one mention, but the first position wins so\n // highlighting stays stable.\n if (seen.has(key))\n continue;\n seen.add(key);\n out.push({ handle, start: i, length: handle.length + 1 });\n }\n return out;\n}\n/** Handles compare case-insensitively; a display name's first word also works. */\nexport function resolveMentions(body, candidates) {\n const byKey = new Map();\n for (const c of candidates) {\n byKey.set(c.name.toLowerCase(), c);\n byKey.set(c.name.toLowerCase().replace(/\\s+/g, \"\"), c);\n const first = c.name.split(/\\s+/)[0];\n if (first)\n byKey.set(first.toLowerCase(), c);\n if (c.email)\n byKey.set(c.email.split(\"@\")[0].toLowerCase(), c);\n byKey.set(c.id.toLowerCase(), c);\n }\n const resolved = [];\n const unknown = [];\n for (const mention of parseMentions(body)) {\n const user = byKey.get(mention.handle.toLowerCase());\n if (user && !resolved.some((r) => r.user.id === user.id))\n resolved.push({ mention, user });\n else if (!user)\n unknown.push(mention.handle);\n }\n return { resolved, unknown };\n}\n/**\n * Split a body into text and mention segments, so a renderer can highlight names\n * without re-parsing (and without highlighting the wrong occurrence).\n */\nexport function mentionSegments(body, mentions) {\n if (!mentions.length)\n return [{ text: body, mention: false }];\n const sorted = [...mentions].sort((a, b) => a.start - b.start);\n const out = [];\n let at = 0;\n for (const m of sorted) {\n if (m.start > at)\n out.push({ text: body.slice(at, m.start), mention: false });\n out.push({ text: body.slice(m.start, m.start + m.length), mention: true });\n at = m.start + m.length;\n }\n if (at < body.length)\n out.push({ text: body.slice(at), mention: false });\n return out;\n}\n/** The handles someone could type, for an autocomplete list. */\nexport function mentionSuggestions(body, caret, candidates) {\n // The handle being typed: from the last `@` before the caret to the caret.\n const before = body.slice(0, caret);\n const at = before.lastIndexOf(\"@\");\n if (at < 0)\n return [];\n const typed = before.slice(at + 1);\n // Bail once they have typed a space — the mention is finished, or was never one.\n if (/\\s/.test(typed))\n return [];\n const q = typed.toLowerCase();\n return candidates\n .filter((c) => !q || c.name.toLowerCase().includes(q) || c.id.toLowerCase().includes(q))\n .slice(0, 6);\n}\n","/**\n * \"Needs you\".\n *\n * A board that shows everything is a board nobody reads. This is the one predicate\n * that answers *what is blocked on a person right now* — and it lives in shared so\n * the panel, the dashboard and the MCP tools cannot disagree about it.\n *\n * The exclusion matters as much as the match: a thread where an **agent is still\n * working** is not waiting on a human, and counting it would train people to ignore\n * the filter.\n */\nexport const NEEDS_YOU_LABELS = {\n review: \"Waiting on your review\",\n question: \"The agent asked you something\",\n failed: \"The agent's run failed\",\n};\n/** Does this look like the agent asking for an answer rather than reporting one? */\nexport function looksLikeQuestion(body) {\n const lines = body.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n const last = lines[lines.length - 1];\n if (!last)\n return false;\n // A question mark at the end of the last line, ignoring a trailing quote or bracket.\n return /\\?[\"')\\]]*$/.test(last);\n}\n/**\n * Whether a human needs to do something.\n *\n * Precedence is deliberate: a failed run outranks an unanswered question (fix the\n * breakage first), and both outrank a routine review, because a review is the normal\n * state of work moving and a failure is not.\n */\nexport function needsYou(input) {\n const stage = normalizeStage(input.status);\n // Resolved threads need nobody, whatever else is true of them.\n if (stage === \"resolved\")\n return { needs: false };\n if (input.agentFailed)\n return { needs: true, reason: \"failed\", label: NEEDS_YOU_LABELS.failed };\n // An agent's question is addressed to a person; a *person's* question is addressed to\n // the agent, so it must not land here.\n if (input.last?.fromAgent && looksLikeQuestion(input.last.body)) {\n return { needs: true, reason: \"question\", label: NEEDS_YOU_LABELS.question };\n }\n if (stage === \"in_review\")\n return { needs: true, reason: \"review\", label: NEEDS_YOU_LABELS.review };\n return { needs: false };\n}\n/** Threads a human has to act on, in board order. */\nexport function needsYouThreads(threads) {\n return threads.filter((t) => needsYou(t).needs);\n}\nfunction normalizeStage(status) {\n if (status === \"open\")\n return \"queue\";\n if (status === \"done\")\n return \"resolved\";\n return status;\n}\n","/**\n * Reactions.\n *\n * A reaction is a toggle, not an increment: pressing the same emoji twice must leave\n * you having reacted once. That is the whole correctness question, and it is why the\n * toggle lives here as a pure function rather than being inferred from counts at the\n * call site.\n */\n/** The emoji offered in the picker. Deliberately short — a long list is a decision nobody makes. */\nexport const REACTION_CHOICES = [\"👍\", \"🎉\", \"👀\", \"🙏\", \"❤️\", \"🚀\"];\n/**\n * Aggregate one message's reactions for a viewer.\n *\n * Ordered by count (most reacted first), then by the picker's own order so the row\n * does not reshuffle between renders when counts tie.\n */\nexport function summarizeReactions(reactions, viewerId) {\n const byEmoji = new Map();\n for (const r of reactions) {\n const list = byEmoji.get(r.emoji) ?? [];\n list.push(r);\n byEmoji.set(r.emoji, list);\n }\n const rank = (emoji) => {\n const at = REACTION_CHOICES.indexOf(emoji);\n return at < 0 ? REACTION_CHOICES.length : at;\n };\n return [...byEmoji.entries()]\n .map(([emoji, list]) => ({\n emoji,\n count: list.length,\n mine: viewerId ? list.some((r) => r.userId === viewerId) : false,\n users: list.map((r) => r.userName ?? r.userId),\n }))\n .sort((a, b) => b.count - a.count || rank(a.emoji) - rank(b.emoji) || a.emoji.localeCompare(b.emoji));\n}\n/**\n * Toggle one person's reaction, returning the new set.\n *\n * Idempotent in both directions: toggling on twice adds one, toggling off twice removes\n * one and then does nothing. Applying the same toggle to an already-toggled set is\n * therefore safe to retry, which matters because a flaky network will.\n */\nexport function toggleReaction(reactions, next) {\n const has = reactions.some((r) => r.messageId === next.messageId && r.emoji === next.emoji && r.userId === next.userId);\n if (has) {\n return reactions.filter((r) => !(r.messageId === next.messageId && r.emoji === next.emoji && r.userId === next.userId));\n }\n return [...reactions, next];\n}\n/** Reactions grouped per message, for rendering a whole conversation at once. */\nexport function reactionsByMessage(reactions, viewerId) {\n const byMessage = new Map();\n for (const r of reactions) {\n const list = byMessage.get(r.messageId) ?? [];\n list.push(r);\n byMessage.set(r.messageId, list);\n }\n const out = new Map();\n for (const [messageId, list] of byMessage)\n out.set(messageId, summarizeReactions(list, viewerId));\n return out;\n}\n","/**\n * Presence.\n *\n * Who else has this page open. The only interesting part is expiry: a browser that is\n * closed or crashes sends no goodbye, so liveness is a heartbeat and silence past the\n * TTL means gone. Without that, the peer list slowly fills with ghosts and stops being\n * believed.\n *\n * Pure — the bridge and the panel both use it, and neither gets its own rules.\n */\n/** Silence after which a peer is presumed gone. Shorter than an agent's — a browser closes fast. */\nexport const PEER_TTL_MS = 20000;\n/** How often a client should heartbeat. Comfortably inside the TTL. */\nexport const PEER_HEARTBEAT_MS = 6000;\n/** Stable across reloads and tabs of the same page, so a refresh does not duplicate you. */\nexport function peerId(url, userId) {\n let h = 0x811c9dc5;\n const input = `${url}\\u0000${userId}`;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return `p_${h.toString(16).padStart(8, \"0\")}`;\n}\nexport function joinPresence(peers, input, now = Date.now()) {\n const id = peerId(input.url, input.userId);\n const without = peers.filter((p) => p.id !== id);\n return [...without, { id, ...input, lastSeen: now }];\n}\n/** Refresh one peer. An unknown id is ignored — the next join revives it. */\nexport function heartbeatPresence(peers, id, now = Date.now()) {\n if (!peers.some((p) => p.id === id))\n return peers;\n return peers.map((p) => (p.id === id ? { ...p, lastSeen: now } : p));\n}\nexport function leavePresence(peers, id) {\n return peers.filter((p) => p.id !== id);\n}\n/** Drop anything silent for the TTL. Inclusive at the boundary. */\nexport function sweepPresence(peers, now = Date.now(), ttlMs = PEER_TTL_MS) {\n return peers.filter((p) => now - p.lastSeen < ttlMs);\n}\n/** Peers on one page, excluding the viewer — \"who else is here\". */\nexport function peersOnPage(peers, url, viewerId) {\n return peers.filter((p) => p.url === url && p.id !== viewerId);\n}\n/**\n * Cursor updates arrive faster than anyone can usefully render them, so a client\n * throttles. Returns the delay to wait before sending the next one — 0 when it can go\n * immediately, so the first move is never delayed.\n */\nexport function throttleDelay(lastSentAt, now = Date.now(), minMs = 80) {\n if (!lastSentAt)\n return 0;\n const elapsed = now - lastSentAt;\n return elapsed >= minMs ? 0 : minMs - elapsed;\n}\n/** Initials for a tiny avatar: two words → two letters, one word → one. */\nexport function initialsOf(name) {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (!words.length)\n return \"?\";\n if (words.length === 1)\n return words[0].slice(0, 1).toUpperCase();\n return (words[0].slice(0, 1) + words[words.length - 1].slice(0, 1)).toUpperCase();\n}\n","/**\n * The companion gather tray.\n *\n * The point of the tray is that a visual brief is usually about *several* things at\n * once — \"these three cards, not the header\" — and one-click-at-a-time forces the\n * person to write what they could have shown. So the tray holds a list, and ordering is\n * part of the message: it is how you say which one matters most.\n *\n * Pure, so the reorder and include rules can be tested without a DOM.\n */\nexport function emptyTray() {\n return { items: [] };\n}\n/**\n * Add an item, or replace the one already there.\n *\n * Replaced rather than appended when it is the same reference: clicking \"add\" twice on\n * the same element is a person confirming, not a person wanting it twice. The position\n * is kept so a reorder is not undone by a re-add.\n */\nexport function addToTray(state, item) {\n const full = { include: true, ...item };\n const at = state.items.findIndex((i) => i.id === full.id);\n if (at < 0)\n return { items: [...state.items, full] };\n const items = [...state.items];\n items[at] = { ...items[at], ...full, include: items[at].include };\n return { items };\n}\nexport function removeFromTray(state, id) {\n return { items: state.items.filter((i) => i.id !== id) };\n}\nexport function toggleInclude(state, id) {\n return { items: state.items.map((i) => (i.id === id ? { ...i, include: !i.include } : i)) };\n}\n/** Move one item to an absolute position, clamped rather than rejected. */\nexport function moveInTray(state, id, to) {\n const from = state.items.findIndex((i) => i.id === id);\n if (from < 0)\n return state;\n const target = Math.max(0, Math.min(state.items.length - 1, to));\n if (target === from)\n return state;\n const items = [...state.items];\n const [moved] = items.splice(from, 1);\n items.splice(target, 0, moved);\n return { items };\n}\n/** Nudge one position up or down — what an arrow button does. */\nexport function nudgeInTray(state, id, delta) {\n const at = state.items.findIndex((i) => i.id === id);\n if (at < 0)\n return state;\n return moveInTray(state, id, at + delta);\n}\n/** Only what is checked. Order is preserved, because order is meaning. */\nexport function includedItems(state) {\n return state.items.filter((i) => i.include);\n}\nexport function trayCount(state) {\n return { total: state.items.length, included: includedItems(state).length };\n}\nexport function clearTray() {\n return { items: [] };\n}\n/**\n * The payload the bridge expects.\n *\n * A flat array of contexts rather than separate element/screenshot lists: the tray is\n * ordered and the agent should read it in that order, and splitting it by kind is how\n * that ordering gets lost at the boundary.\n */\nexport function trayPayload(state) {\n return includedItems(state).map((i) => ({\n kind: i.kind,\n id: i.ref ?? i.id,\n url: i.url,\n label: i.label,\n }));\n}\n/** A one-line description of the tray, for a button label. */\nexport function traySummary(state) {\n const { total, included } = trayCount(state);\n if (!total)\n return \"No context gathered\";\n if (included === total)\n return `${total} context${total === 1 ? \"\" : \"s\"}`;\n return `${included} of ${total} included`;\n}\n/**\n * Whether dictation is available.\n *\n * Two different reasons to hide the control, and they need different wording: an\n * unsupported browser is a fact, while a secure-origin failure is fixable by loading\n * the page differently. Telling someone their browser cannot do it when the real\n * problem is `http://` sends them looking in the wrong place.\n */\nexport function voiceSupport(env) {\n if (!env.isSecureContext)\n return \"insecure\";\n return env.hasCtor ? \"supported\" : \"unsupported\";\n}\nexport function voiceMessage(support) {\n if (support === \"supported\")\n return null;\n if (support === \"insecure\")\n return \"Dictation needs a secure page (https, or localhost).\";\n return \"This browser cannot dictate — the Web Speech API is not available.\";\n}\n/** mm:ss for the recording pill, so a long recording still reads. */\nexport function elapsedLabel(ms) {\n const total = Math.max(0, Math.floor(ms / 1000));\n const mm = Math.floor(total / 60);\n const ss = total % 60;\n return `${mm}:${String(ss).padStart(2, \"0\")}`;\n}\n","// Canonical types + pure helpers shared across the SDK, server, dashboard, and MCP.\nexport * from \"./activity.js\";\nexport * from \"./lifecycle.js\";\nexport * from \"./iteration.js\";\nexport * from \"./consent.js\";\nexport * from \"./preview.js\";\nexport * from \"./thread.js\";\nexport * from \"./timeline.js\";\nexport * from \"./mentions.js\";\nexport * from \"./needs-you.js\";\nexport * from \"./reactions.js\";\nexport * from \"./presence.js\";\nexport * from \"./companion-tray.js\";\n/** Board order, left to right. */\nexport const COMMENT_STAGES = [\"queue\", \"todo\", \"in_progress\", \"in_review\", \"resolved\"];\n/** Human labels for the board columns. */\nexport const STAGE_LABELS = {\n queue: \"Queue\",\n todo: \"To Do\",\n in_progress: \"In Progress\",\n in_review: \"In Review\",\n resolved: \"Resolved\",\n};\n/**\n * Statuses this project shipped before the five-stage board. Still accepted on\n * input (and on rows written by an older client) so a rolling upgrade never\n * writes a value the board cannot place.\n */\nconst LEGACY_STATUS = {\n open: \"queue\",\n in_progress: \"in_progress\",\n done: \"resolved\",\n};\n/**\n * Coerce any accepted status — current stage or legacy alias — into a stage.\n * Anything unrecognised lands in `queue`, the untriaged inbox, rather than\n * falling off the board entirely.\n */\nexport function normalizeStatus(value) {\n if (typeof value === \"string\") {\n if (COMMENT_STAGES.includes(value))\n return value;\n if (value in LEGACY_STATUS)\n return LEGACY_STATUS[value];\n }\n return \"queue\";\n}\n/** Whether a comment is still open work (everything except `resolved`). */\nexport function isOpenStage(stage) {\n return stage !== \"resolved\";\n}\n/**\n * Every raw `status` value that belongs to this stage — the stage itself plus any\n * legacy alias that maps onto it. A SQL filter uses this so it still finds rows\n * written before the five-stage board.\n */\nexport function statusAliases(stage) {\n const out = [stage];\n for (const [legacy, mapped] of Object.entries(LEGACY_STATUS)) {\n if (mapped === stage && !out.includes(legacy))\n out.push(legacy);\n }\n return out;\n}\n/** Priorities, most urgent first. */\nexport const COMMENT_PRIORITIES = [\"critical\", \"high\", \"medium\", \"low\"];\n/** Human labels for the priority chips. */\nexport const PRIORITY_LABELS = {\n critical: \"Critical\",\n high: \"High\",\n medium: \"Medium\",\n low: \"Low\",\n};\n/** Sort key: 0 is the most urgent, so `a - b` sorts correctly. */\nexport const PRIORITY_RANK = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n/** Change types. */\nexport const CHANGE_TYPES = [\"frontend\", \"backend\", \"api\", \"other\"];\n/** Human labels for the change-type chips. */\nexport const CHANGE_TYPE_LABELS = {\n frontend: \"Frontend\",\n backend: \"Backend\",\n api: \"API\",\n other: \"Other\",\n};\n/** Defaults applied when a comment does not say. */\nexport const DEFAULT_PRIORITY = \"medium\";\nexport const DEFAULT_CHANGE_TYPE = \"other\";\n/** Coerce any value into a priority, falling back to the default. */\nexport function normalizePriority(value) {\n if (typeof value === \"string\" && COMMENT_PRIORITIES.includes(value)) {\n return value;\n }\n return DEFAULT_PRIORITY;\n}\n/** Coerce any value into a change type, falling back to the default. */\nexport function normalizeChangeType(value) {\n if (typeof value === \"string\" && CHANGE_TYPES.includes(value)) {\n return value;\n }\n return DEFAULT_CHANGE_TYPE;\n}\n/** Classify a viewport width into a device bucket (mobile < 768 ≤ tablet < 1024 ≤ desktop). */\nexport function deviceType(width) {\n if (width < 768)\n return \"mobile\";\n if (width < 1024)\n return \"tablet\";\n return \"desktop\";\n}\nconst DROP_EXACT = new Set([\n \"api\", \"key\", \"fbclid\", \"gclid\", \"gbraid\", \"wbraid\", \"msclkid\",\n \"ref\", \"ref_src\", \"mc_cid\", \"mc_eid\", \"_hsenc\", \"_hsmi\", \"igshid\",\n]);\n/**\n * Normalize a page URL so comments don't fragment across tracking/volatile params.\n * Keeps the path + a filtered, sorted query. Drops utm_*, click ids, and Loupe's\n * own dev params (api/key). Accepts a full URL or a path+search string.\n */\nexport function normalizeUrl(input) {\n try {\n const u = new URL(input, \"http://loupe.local\");\n let path = u.pathname;\n const kept = [];\n for (const [k, v] of u.searchParams) {\n const key = k.toLowerCase();\n if (DROP_EXACT.has(key) || key.startsWith(\"utm_\"))\n continue;\n kept.push([k, v]);\n }\n kept.sort((a, b) => (a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0])));\n const qs = new URLSearchParams(kept).toString();\n if (path.length > 1 && path.endsWith(\"/\"))\n path = path.slice(0, -1);\n return path + (qs ? `?${qs}` : \"\");\n }\n catch {\n const i = input.indexOf(\"?\");\n return i >= 0 ? input.slice(0, i) : input;\n }\n}\n","import type { ActivityEvent, Attachment, Comment, MessageAttachment, OrgInfo, Reaction, StorageAdapter, ThreadAuthor, ThreadMessage } from \"./types.js\";\nimport { toggleReaction } from \"./types.js\";\nimport { attachmentKind, fileToDataUrl } from \"./capture.js\";\n\n/**\n * Prototype storage: everything lives in localStorage, keyed by project + path.\n * The production adapter swaps this for HTTP calls to the backend — the SDK\n * only depends on the StorageAdapter interface, so nothing else changes.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private key(projectKey: string, url: string) {\n return `loupe:${projectKey}:${url}`;\n }\n\n private readAll(projectKey: string, url: string): Comment[] {\n try {\n const raw = localStorage.getItem(this.key(projectKey, url));\n return raw ? (JSON.parse(raw) as Comment[]) : [];\n } catch {\n return [];\n }\n }\n\n private writeAll(projectKey: string, url: string, comments: Comment[]) {\n localStorage.setItem(this.key(projectKey, url), JSON.stringify(comments));\n }\n\n async list(projectKey: string, url: string): Promise<Comment[]> {\n return this.readAll(projectKey, url);\n }\n\n /** Every page's comments for this project, newest first — the \"All\" scope. */\n async listAll(projectKey: string): Promise<Comment[]> {\n const prefix = `loupe:${projectKey}:`;\n const out: Comment[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (!k || !k.startsWith(prefix)) continue;\n try {\n out.push(...(JSON.parse(localStorage.getItem(k) || \"[]\") as Comment[]));\n } catch { /* skip an unreadable key */ }\n }\n return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n }\n\n async save(comment: Comment): Promise<Comment> {\n const all = this.readAll(comment.projectKey, comment.url);\n all.push(comment);\n this.writeAll(comment.projectKey, comment.url, all);\n return comment;\n }\n\n /**\n * Offline mode: keep the file inline. localStorage is only a few MB, so refuse\n * anything that would blow the quota rather than silently dropping it.\n */\n async upload(_projectKey: string, file: File): Promise<Attachment> {\n if (file.size > 3_000_000) throw new Error(\"attachment too large for offline mode\");\n return {\n url: await fileToDataUrl(file),\n name: file.name,\n mime: file.type || undefined,\n kind: attachmentKind(file.type),\n size: file.size,\n };\n }\n\n /**\n * Keys that hold a comment list. `loupe:dock` (panel state) and `loupe:msgs:*`\n * (replies) share the prefix but are not comment lists — treating them as one made\n * update()/remove() throw, and would have it hunt a comment id among messages.\n */\n private commentKeys(): string[] {\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(\"loupe:\") && k !== \"loupe:dock\" && !k.startsWith(\"loupe:msgs:\")) keys.push(k);\n }\n return keys;\n }\n\n private parseList(key: string): Comment[] {\n try {\n const value = JSON.parse(localStorage.getItem(key) || \"[]\");\n return Array.isArray(value) ? (value as Comment[]) : [];\n } catch {\n return [];\n }\n }\n\n /** Replies, kept under their own key so they survive a comment being re-saved. */\n private msgKey(threadId: string) {\n return `loupe:msgs:${threadId}`;\n }\n\n async listMessages(threadId: string): Promise<ThreadMessage[]> {\n try {\n const raw = localStorage.getItem(this.msgKey(threadId));\n const parsed = raw ? JSON.parse(raw) : [];\n return Array.isArray(parsed) ? (parsed as ThreadMessage[]) : [];\n } catch {\n return [];\n }\n }\n\n async addMessage(\n threadId: string,\n message: { author: ThreadAuthor; body: string; attachments?: MessageAttachment[] },\n ): Promise<ThreadMessage> {\n const stored: ThreadMessage = {\n id: `m${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n threadId,\n author: message.author,\n body: message.body,\n attachments: message.attachments?.length ? message.attachments : undefined,\n createdAt: new Date().toISOString(),\n };\n const all = await this.listMessages(threadId);\n all.push(stored);\n localStorage.setItem(this.msgKey(threadId), JSON.stringify(all));\n return stored;\n }\n\n /** Offline reactions, keyed per thread. */\n async listReactions(threadId: string): Promise<Reaction[]> {\n try {\n const raw = localStorage.getItem(`loupe:rxn:${threadId}`);\n const parsed = raw ? JSON.parse(raw) : [];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n async toggleReaction(input: { threadId: string; messageId: string; emoji: string; userId: string; userName?: string }): Promise<Reaction[]> {\n const current = await this.listReactions(input.threadId);\n // The same pure toggle the server uses, so offline and online behave identically.\n const next = toggleReaction(current, {\n messageId: input.messageId, emoji: input.emoji, userId: input.userId, userName: input.userName,\n });\n localStorage.setItem(`loupe:rxn:${input.threadId}`, JSON.stringify(next));\n return next;\n }\n\n /** Offline: the people are whoever has already commented locally. */\n async listPeople(projectKey: string): Promise<{ id: string; name: string; email?: string }[]> {\n const prefix = `loupe:${projectKey}:`;\n const seen = new Map<string, { id: string; name: string; email?: string }>();\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (!k || !k.startsWith(prefix)) continue;\n for (const c of this.parseList(k)) {\n if (c.author?.id && !seen.has(c.author.id)) seen.set(c.author.id, c.author);\n }\n }\n return [...seen.values()];\n }\n\n /** Offline mode has no server to notify anyone from. */\n async listNotifications(): Promise<any[]> {\n return [];\n }\n\n async markNotificationsRead(): Promise<void> {\n /* nothing to mark offline */\n }\n\n async update(id: string, patch: Partial<Comment>): Promise<void> {\n // We don't know the url here, so scan the loupe:* list keys for the id.\n for (const k of this.commentKeys()) {\n const list = this.parseList(k);\n const idx = list.findIndex((c) => c.id === id);\n if (idx >= 0) {\n list[idx] = { ...list[idx]!, ...patch };\n localStorage.setItem(k, JSON.stringify(list));\n return;\n }\n }\n }\n\n async remove(id: string): Promise<void> {\n for (const k of this.commentKeys()) {\n const list = this.parseList(k);\n const next = list.filter((c) => c.id !== id);\n if (next.length !== list.length) {\n localStorage.setItem(k, JSON.stringify(next));\n return;\n }\n }\n }\n\n /** Offline: there is no organization to read. */\n async getOrg(): Promise<OrgInfo | null> {\n return null;\n }\n\n /** Offline: no server feed; the panel shows only what this browser reports. */\n async listActivity(_projectKey: string, _since?: string): Promise<ActivityEvent[] | null> {\n return null;\n }\n}\n","import type { ActivityEvent, Attachment, Comment, LoupeUser, MessageAttachment, OrgInfo, Reaction, StorageAdapter, ThreadAuthor, ThreadMessage } from \"./types.js\";\nimport { attachmentKind, fileToDataUrl } from \"./capture.js\";\n\n/**\n * Talks to the Loupe backend. Selected automatically when `apiBase` is set in\n * init(). Sends the identity headers the backend verifies (HMAC in production).\n */\nexport class HttpAdapter implements StorageAdapter {\n constructor(\n private base: string,\n private user: LoupeUser,\n private userHmac?: string,\n private extraHeaders?: Record<string, string>,\n private credentials?: RequestCredentials,\n ) {\n this.base = base.replace(/\\/$/, \"\");\n }\n\n private headers(): HeadersInit {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\", \"X-Loupe-User\": this.user.id };\n if (this.userHmac) h[\"X-Loupe-Hmac\"] = this.userHmac;\n if (this.extraHeaders) Object.assign(h, this.extraHeaders);\n return h;\n }\n\n /** Base fetch options shared by every request (credentials mode, if set). */\n private opts(init?: RequestInit): RequestInit {\n return this.credentials ? { credentials: this.credentials, ...init } : { ...init };\n }\n\n async list(projectKey: string, url: string): Promise<Comment[]> {\n const q = new URLSearchParams({ projectKey, url });\n const res = await fetch(`${this.base}/v1/comments?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`list failed: ${res.status}`);\n return (await res.json()) as Comment[];\n }\n\n /** Every comment in the project (no page filter) — the \"All\" scope. */\n async listAll(projectKey: string): Promise<Comment[]> {\n const q = new URLSearchParams({ projectKey });\n const res = await fetch(`${this.base}/v1/comments?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listAll failed: ${res.status}`);\n return (await res.json()) as Comment[];\n }\n\n /** Upload an inline data-URL asset to object storage; return its URL (or the data URL on failure). */\n private async uploadBlob(projectKey: string, data: string): Promise<string> {\n try {\n const up = await fetch(`${this.base}/v1/blobs`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ projectKey, data }),\n }));\n if (up.ok) return (await up.json()).url as string;\n } catch {\n /* fall back to inlining below */\n }\n return data;\n }\n\n async save(comment: Comment): Promise<Comment> {\n // Upload media to object storage first, then store only the URL — keeps the\n // comment row (and every later list/read) small.\n if (comment.screenshot?.startsWith(\"data:\")) {\n comment = { ...comment, screenshot: await this.uploadBlob(comment.projectKey, comment.screenshot) };\n }\n if (comment.recording?.startsWith(\"data:\")) {\n comment = { ...comment, recording: await this.uploadBlob(comment.projectKey, comment.recording) };\n }\n const res = await fetch(`${this.base}/v1/comments`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(comment),\n }));\n if (!res.ok) throw new Error(`save failed: ${res.status}`);\n return (await res.json()) as Comment;\n }\n\n /** Persist one reporter-attached file to object storage and describe it. */\n async upload(projectKey: string, file: File): Promise<Attachment> {\n const data = await fileToDataUrl(file);\n return {\n url: await this.uploadBlob(projectKey, data),\n name: file.name,\n mime: file.type || undefined,\n kind: attachmentKind(file.type),\n size: file.size,\n };\n }\n\n /** Replies on a thread. The comment's own body is message #1, not returned here. */\n async listMessages(threadId: string): Promise<ThreadMessage[]> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/messages`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listMessages failed: ${res.status}`);\n return (await res.json()) as ThreadMessage[];\n }\n\n async addMessage(\n threadId: string,\n message: { author: ThreadAuthor; body: string; attachments?: MessageAttachment[] },\n ): Promise<ThreadMessage & { mentions?: string[]; unknownMentions?: string[] }> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/messages`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(message),\n }));\n if (!res.ok) throw new Error(`addMessage failed: ${res.status}`);\n return (await res.json()) as ThreadMessage & { mentions?: string[]; unknownMentions?: string[] };\n }\n\n async listReactions(threadId: string): Promise<Reaction[]> {\n // Thread-level, not per message: a thread's reactions are one small set and the\n // client aggregates them, so this is one request rather than one per reply.\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(threadId)}/reactions`, this.opts({ headers: this.headers() }));\n // A 404 means the thread is gone, which for its reactions means there are none.\n if (res.status === 404) return [];\n if (!res.ok) throw new Error(`listReactions failed: ${res.status}`);\n return ((await res.json()) as { reactions: Reaction[] }).reactions;\n }\n\n async toggleReaction(input: { threadId: string; messageId: string; emoji: string; userId: string; userName?: string }): Promise<Reaction[]> {\n const res = await fetch(\n `${this.base}/v1/comments/${encodeURIComponent(input.threadId)}/messages/${encodeURIComponent(input.messageId)}/reactions`,\n this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ emoji: input.emoji, userId: input.userId, userName: input.userName }),\n }),\n );\n if (!res.ok) throw new Error(`toggleReaction failed: ${res.status}`);\n return ((await res.json()) as { reactions: Reaction[] }).reactions;\n }\n\n /** Everyone who has taken part in this project, for mention resolution. */\n async listPeople(projectKey: string): Promise<{ id: string; name: string; email?: string }[]> {\n const q = new URLSearchParams({ projectKey });\n const res = await fetch(`${this.base}/v1/people?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listPeople failed: ${res.status}`);\n return (await res.json()) as { id: string; name: string; email?: string }[];\n }\n\n async listNotifications(projectKey: string, recipient: string): Promise<any[]> {\n const q = new URLSearchParams({ projectKey, recipient });\n const res = await fetch(`${this.base}/v1/notifications?${q}`, this.opts({ headers: this.headers() }));\n if (!res.ok) throw new Error(`listNotifications failed: ${res.status}`);\n return ((await res.json()) as { notifications: any[] }).notifications;\n }\n\n async markNotificationsRead(projectKey: string, recipient: string, id?: string): Promise<void> {\n await fetch(`${this.base}/v1/notifications/read`, this.opts({\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ projectKey, recipient, id }),\n }));\n }\n\n async update(id: string, patch: Partial<Comment>): Promise<void> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(id)}`, this.opts({\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(patch),\n }));\n if (!res.ok) throw new Error(`update failed: ${res.status}`);\n }\n\n /** The organization, read through the host app. A 404 means the backend has no such endpoint. */\n async getOrg(): Promise<OrgInfo | null> {\n const res = await fetch(`${this.base}/v1/org`, this.opts({ headers: this.headers() }));\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`getOrg failed: ${res.status}`);\n // Check the shape: a proxy's JSON or some other endpoint's answer is not an organization.\n const body = (await res.json()) as OrgInfo;\n if (!body || typeof body !== \"object\" || !body.project || !Array.isArray(body.projects)) {\n throw new Error(\"getOrg: the answer was not an organization\");\n }\n return body;\n }\n\n /** The server's activity feed. A 404 means the backend keeps none. */\n async listActivity(projectKey: string, since?: string): Promise<ActivityEvent[] | null> {\n const q = new URLSearchParams({ projectKey });\n if (since) q.set(\"since\", since);\n const res = await fetch(`${this.base}/v1/activity?${q}`, this.opts({ headers: this.headers() }));\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`listActivity failed: ${res.status}`);\n const body = await res.json();\n if (!Array.isArray(body)) throw new Error(\"listActivity: the answer was not a list\");\n return body as ActivityEvent[];\n }\n\n async remove(id: string): Promise<void> {\n const res = await fetch(`${this.base}/v1/comments/${encodeURIComponent(id)}`, this.opts({\n method: \"DELETE\",\n headers: this.headers(),\n }));\n if (!res.ok && res.status !== 404) throw new Error(`remove failed: ${res.status}`);\n }\n}\n","import { STYLES } from \"./styles.js\";\nimport type { Peer, Reaction } from \"@loupekit/shared\";\nimport { captureAnchor, resolveAnchor } from \"./fingerprint.js\";\nimport { attachmentKind, captureElementContext, captureScreenshot, captureRegionScreenshot, captureRegionRecording } from \"./capture.js\";\nimport { LocalStorageAdapter } from \"./store.js\";\nimport { HttpAdapter } from \"./http-adapter.js\";\nimport {\n ACTIVITY_STATUS_LABELS,\n addIteration,\n awaitingReview,\n CHANGE_TYPES,\n CHANGE_TYPE_LABELS,\n COMMENT_PRIORITIES,\n canMove,\n canUndo,\n current as currentIteration,\n decide as decideConsent,\n DEFAULT_CHANGE_TYPE,\n DEFAULT_PRIORITY,\n emptyConsent,\n emptyIterations,\n formatDuration,\n iterationLabel,\n isPending as consentPending,\n lifecycle,\n move as moveIteration,\n normalizePriority,\n normalizeStatus,\n PRIORITY_LABELS,\n requestNavigation as requestNav,\n STAGE_LABELS,\n stackLabel,\n threadAsText,\n addToTray,\n clearTray,\n elapsedLabel,\n emptyTray,\n includedItems,\n initialsOf,\n nudgeInTray,\n removeFromTray,\n toggleInclude,\n trayPayload,\n traySummary,\n voiceMessage,\n voiceSupport,\n type TrayState,\n PEER_HEARTBEAT_MS,\n mentionSegments,\n summarizeReactions,\n toggleReaction,\n mentionSuggestions,\n needsYou,\n parseMentions,\n REACTION_CHOICES,\n threadConversation,\n threadTimeline,\n summarizeActivity,\n undo as undoIteration,\n withdraw as withdrawConsent,\n} from \"./types.js\";\nimport type {\n ActivityEvent, ActivityEventInput, ActivityStatus, Anchor, Attachment, ChangeType, Comment, OrgInfo,\n CommentPriority, ConsentRecord, IterationState, LocalAiConfig, LoupeConfig, RegionRect,\n ResolveResult, StorageAdapter, ThreadAuthor, ThreadMessage,\n} from \"./types.js\";\n\ndeclare const __LOUPE_VERSION__: string | undefined;\n/** The build that produced this bundle (baked in by tsup); recorded on every comment. */\nexport const SDK_VERSION = typeof __LOUPE_VERSION__ === \"string\" ? __LOUPE_VERSION__ : \"dev\";\n/** The launcher button's rendered size, used to keep a dragged launcher inside the viewport. */\nconst FAB_SIZE = 46;\n/** Pointer travel (px) before a press on the launcher counts as a drag rather than a tap. */\nconst FAB_DRAG_THRESHOLD = 6;\n/** Keyboard shortcut that shows a hidden launcher again (and hides a shown one). */\nconst LAUNCHER_SHORTCUT = \"Alt+Shift+L\";\n\ntype Mode = \"off\" | \"inspect\" | \"region\" | \"free\" | \"record\";\n/** Accent presets — a variant per theme, since light needs a darker hue to stay legible. */\nconst ACCENTS: { id: string; dark: string; light: string; soft: string }[] = [\n { id: \"indigo\", dark: \"#6b73e6\", light: \"#4a55d6\", soft: \"rgba(107,115,230,0.12)\" },\n { id: \"violet\", dark: \"#a06be6\", light: \"#7c3fd4\", soft: \"rgba(160,107,230,0.14)\" },\n { id: \"teal\", dark: \"#2fb6a8\", light: \"#0f8f83\", soft: \"rgba(47,182,168,0.14)\" },\n { id: \"amber\", dark: \"#d99a2b\", light: \"#a9700f\", soft: \"rgba(217,154,43,0.14)\" },\n { id: \"rose\", dark: \"#e05c86\", light: \"#c2295a\", soft: \"rgba(224,92,134,0.14)\" },\n];\nconst ACCENT_IDS = ACCENTS.map((a) => a.id);\n\n/**\n * The guided tour: one short step per idea a new user needs. Each step names the\n * tab it belongs to, so the tour can move the panel itself out of the way.\n */\nconst TOUR: { sel: string; tab: Tab; title: string; body: string }[] = [\n // Home first: the panel already opens there, so the first step never moves the\n // user — the tour starts where they are.\n { sel: \".hstat\", tab: \"home\", title: \"Home shows what needs you\",\n body: \"Four tiles count open, needs-you, resolved and stale feedback. Click one to narrow the list to that bucket.\" },\n { sel: \".hscope\", tab: \"home\", title: \"This page, or the whole project\",\n body: \"Switch to All to see every page's feedback as a day-grouped timeline.\" },\n { sel: \".tools\", tab: \"comments\", title: \"Pin feedback anywhere\",\n body: \"Inspect picks an element, Note drops a page-level comment, Region captures a rectangle, and Record films one.\" },\n { sel: '.tabs [data-tab=\"activity\"]', tab: \"activity\", title: \"Watch the work happen\",\n body: \"Comments, status changes and forwarded tickets land here as they happen, with anything a bridge or your app reports. Tool chips filter it.\" },\n { sel: '.dctl [data-role=\"settings\"]', tab: \"activity\", title: \"Make it yours\",\n body: \"Accents, the visibility switches, and Restart tour all live here.\" },\n];\n\n/** One contextual hint per built-in view, shown once (unless hints are switched off). */\nconst HINTS: Record<BuiltinTab, { title: string; body: string }> = {\n chat: {\n title: \"Talk to the agent\",\n body: \"Gather what you are looking at and send it in one go. The agent gets it on its very next step — not after it finishes.\",\n },\n home: { title: \"Your triage at a glance\", body: \"The tiles count this page by default. Switch to All for the whole project, or click a tile to jump straight to that bucket.\" },\n comments: { title: \"Pin, note or record\", body: \"Inspect selects an element, Note comments anywhere on the page, Region screenshots a rectangle, and Record captures video of one.\" },\n activity: { title: \"Watch the work happen\", body: \"Every event the bridge or your app reports lands here, alongside Loupe's own operations. Click a tool chip to filter the feed.\" },\n};\n\n/** Where the control panel is anchored — the four layouts the position menu offers. */\ntype DockMode = \"left\" | \"right\" | \"bottom\" | \"float\";\n/** The pages that ship with the panel. Hosts can add more via `init({ tabs })`. */\ntype BuiltinTab = \"home\" | \"comments\" | \"activity\" | \"chat\";\nconst BUILTIN_TABS: { id: BuiltinTab; label: string }[] = [\n { id: \"home\", label: \"Home\" },\n { id: \"comments\", label: \"Comments\" },\n { id: \"activity\", label: \"Activity\" },\n { id: \"chat\", label: \"Chat\" },\n];\n/** A tab id — built-in or host-registered. */\ntype Tab = string;\n/** Which comments the panel is looking at: just this page, or the whole project. */\ntype Scope = \"page\" | \"all\";\n/** A stat tile the user clicked — narrows the list to that bucket. */\ntype StatFilter = \"\" | \"open\" | \"needs_you\" | \"resolved\" | \"stale\";\n/** List order. \"\" follows the scope: page order on This page, newest first on All. */\ntype SortOrder = \"\" | \"newest\" | \"oldest\" | \"page\";\n/** What the composer is about to attach a comment to. */\ntype ComposeTarget =\n | { kind: \"element\"; element: Element }\n | { kind: \"region\"; region: RegionRect; element: Element | null; screenshot?: string; recording?: string }\n | { kind: \"free\"; offset: { x: number; y: number }; point: { x: number; y: number }; label?: string };\n\nconst DOCK_MODES: DockMode[] = [\"left\", \"right\", \"bottom\", \"float\"];\n/** How long a single screen recording may run before it auto-stops. */\nconst RECORD_MAX_MS = 20000;\n/** Attachment limits for the composer — small enough to survive a base64 POST. */\nconst MAX_FILES = 10;\n/** How often the panel re-reads comments, open threads and mentions when no bridge pushes them. */\nconst SYNC_POLL_MS = 10_000;\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024;\nconst MAX_VIDEO_BYTES = 25 * 1024 * 1024;\n\nconst uid = () =>\n (crypto as any).randomUUID ? crypto.randomUUID() : \"c_\" + Math.abs(hash(String(performance.now()))).toString(36);\nfunction hash(s: string) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return h; }\n\n/**\n * A phone/tablet. `(pointer: coarse)` is the primary signal, but a phone asking for the\n * **desktop site** reports a FINE pointer, so touch capability is the backstop. Getting\n * this wrong sends a finger user down the mouse path: a composer that grabs the focus\n * (keyboard over the page) and a drag-select that fights the page scroll.\n */\nfunction isTouchDevice(): boolean {\n try {\n if (window.matchMedia(\"(pointer: coarse)\").matches) return true;\n if (window.matchMedia(\"(hover: none)\").matches) return true;\n } catch {\n /* matchMedia unavailable */\n }\n if (typeof navigator !== \"undefined\" && (navigator.maxTouchPoints ?? 0) > 0) return true;\n return typeof window !== \"undefined\" && \"ontouchstart\" in window;\n}\n\n/** Whether the browser says the primary pointer is coarse (diagnostic only). */\nfunction coarsePointer(): boolean {\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\n/** Whether screen recording is possible at all (absent in every iOS browser). */\nfunction canShareScreen(): boolean {\n return typeof (navigator.mediaDevices as MediaDevices | undefined)?.getDisplayMedia === \"function\";\n}\n\n/** A captured data-URL as a File, so a screenshot can ride along as a normal attachment. */\nfunction dataUrlToFile(dataUrl: string, name: string): File | null {\n const m = /^data:([^;,]+)(;base64)?,([\\s\\S]*)$/.exec(dataUrl);\n if (!m) return null;\n const [, type, b64, payload = \"\"] = m;\n try {\n const raw = b64 ? atob(payload) : decodeURIComponent(payload);\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i);\n return new File([bytes], name, { type: type || \"image/png\" });\n } catch {\n return null;\n }\n}\n\nexport class LoupeApp {\n private cfg: LoupeConfig;\n private store: StorageAdapter;\n private root!: HTMLElement;\n private shadow!: ShadowRoot;\n private overlay!: HTMLElement;\n private hl!: HTMLElement;\n private selbox!: HTMLElement;\n private regionBox!: HTMLElement;\n private composer!: HTMLElement;\n\n /** The dockable control panel (header + tabs + tools + comment list). */\n private dock!: HTMLElement;\n /**\n * The collapsed FAB cluster shown while the panel is closed: a primary brand\n * button (with the comment count) plus quick actions that expand out of it.\n * `launcher` is the primary button itself (kept as a class for the dock's\n * show/hide logic); `fabMinis` is the row of quick actions.\n */\n private fabCluster!: HTMLElement;\n private fabMinis!: HTMLElement;\n private fabBadge!: HTMLElement;\n /** Whether the quick-action minis are expanded out of the primary FAB. */\n private fabExpanded = false;\n /** Whether pin markers are hidden on the page (a quick-action toggle, persisted). */\n private markersHidden = false;\n /**\n * Whether the collapsed launcher is hidden altogether (persisted). The way back is\n * Alt+Shift+L, Settings → Launcher, or the host calling `showLauncher()`.\n */\n private launcherHidden = false;\n /** The way back on a touch screen once the launcher is hidden: a slim tab at the viewport edge. */\n private fabHandle!: HTMLButtonElement;\n /**\n * Where the user dragged the launcher to — the launcher's top-left in viewport px —\n * or null for the default corner on the dock's side. Persisted; clamped on apply so\n * a position saved on a wide screen still lands inside a narrow one.\n */\n private fabPos: { x: number; y: number } | null = null;\n /** The in-flight launcher drag: pointer start, launcher origin, and whether it has moved past the tap threshold. */\n private fabDrag: { px: number; py: number; ox: number; oy: number; moved: boolean } | null = null;\n /** Set for one tick after a drag so the click the browser fires afterwards does not open the panel. */\n private fabSuppressClick = false;\n /** Transient notice at the bottom of the viewport (e.g. how to bring a hidden launcher back). */\n private toastEl!: HTMLElement;\n private toastTimer?: number;\n private themeBtn!: HTMLButtonElement;\n private listEl!: HTMLElement;\n private countEl!: HTMLElement;\n /** Floating \"recording…\" indicator + stop button, shown only while recording. */\n private recBar!: HTMLElement;\n /** Stops the in-flight screen recording (wired while recording). */\n private stopRecording?: () => void;\n\n private comments: Comment[] = [];\n /** Free-text filter over the list (title / body / author). */\n private search = \"\";\n /** Ids of list items the user expanded — items are collapsed by default. */\n private expanded = new Set<string>();\n /** comment.id → currently resolved element (or null when detached). */\n private resolved = new Map<string, Element | null>();\n /** comment.id → pin element. */\n private pins = new Map<string, HTMLElement>();\n\n private mode: Mode = \"off\";\n private lastUrl = \"\";\n /** In-flight region screenshot, captured in the background while the composer is open. */\n private pendingShot?: Promise<string | undefined>;\n private targetOffset = { x: 0.5, y: 0.5 };\n private pending: ComposeTarget | null = null;\n private dragStart: { x: number; y: number } | null = null;\n /** region comment whose outline is currently highlighted (tracks scroll). */\n private activeRegionId: string | null = null;\n private regionTimer?: number;\n\n // ---- control-panel state (persisted in localStorage `loupe:dock`) ----------\n private dockMode: DockMode = \"right\";\n private open = true;\n private theme: \"dark\" | \"light\" = \"dark\";\n private tab: Tab = \"home\";\n /** \"page\" = this URL only; \"all\" = the whole project (the timeline scope). */\n private scope: Scope = \"page\";\n /** Every-page comments, fetched the first time the \"All\" scope is opened. */\n private allComments: Comment[] = [];\n /** True once the project-wide list has been read, so an empty project still shows 0, not ⋯. */\n private allLoaded = false;\n /** A clicked stat tile, which narrows the list. */\n private statFilter: StatFilter = \"\";\n /** One board stage to show, or \"\" for every stage. */\n private statusFilter = \"\";\n private sortOrder: SortOrder = \"\";\n /** Day groups the reader folded shut. Session only: \"Today\" means another day tomorrow. */\n private collapsedDays = new Set<string>();\n private statusSel?: HTMLSelectElement;\n private sortSel?: HTMLSelectElement;\n /** The Home overview container (stat tiles + activity), rebuilt on render. */\n private homeEl!: HTMLElement;\n /** Accent preset id (see ACCENTS), applied as inline --accent / --accent-soft. */\n private accent = \"indigo\";\n /** Collapsed to the one-line minimize bar. */\n private minimized = false;\n /** The \"help layer\": FAB tooltips and the contextual hint cards. */\n private hoverHints = true;\n /** Show each comment's page path (useful in the project scope). */\n private showPaths = false;\n /** Views whose hint card has already been shown. */\n private hintsSeen = new Set<string>();\n /** Current guided-tour step, or -1 when the tour is closed. */\n private tourStep = -1;\n /** The first-run tour has been finished or skipped. */\n private tourDone = false;\n private posMenu!: HTMLElement;\n private settingsMenu!: HTMLElement;\n private minBar!: HTMLElement;\n private tourEl!: HTMLElement;\n private tourSpot!: HTMLElement;\n private tourCard!: HTMLElement;\n /** The live Activity feed — in memory only; it is a monitor, not an archive. */\n private activityEvents: ActivityEvent[] = [];\n private activityStatus: ActivityStatus = \"idle\";\n /** A tool chip the user clicked, which narrows the feed to that kind. */\n private activityFilter = \"\";\n /** Auto-scroll the feed to the newest event (off while the user is reading). */\n private activityFollow = true;\n /** The summary card's key/value rows are behind this toggle. */\n private summaryOpen = false;\n private activityEl!: HTMLElement;\n private feedEl!: HTMLElement;\n /** Per-browser project settings: the environment URLs and the Local AI endpoint. */\n private project: { environments: string[]; localAi?: LocalAiConfig } = { environments: [] };\n /** The organization, read once from the backend. Null offline or before it loads. */\n private org: OrgInfo | null = null;\n /** Whether the server keeps an activity feed, and whether the last read reached it. */\n private activityRemote: \"unsupported\" | \"live\" | \"offline\" = \"unsupported\";\n /** Newest server event seen, so a poll asks only for what is new. */\n private activitySince = \"\";\n private activityPoll?: ReturnType<typeof setInterval>;\n /** The backend answered that it keeps no feed, so the panel stops asking. */\n private activityNone = false;\n /** The no-bridge refresh: re-reads comments, open threads and mentions every SYNC_POLL_MS. */\n private syncPoll?: ReturnType<typeof setInterval>;\n private syncBusy = false;\n /** Iteration history per thread — generating a change is a stack, not a one-shot. */\n private iterations = new Map<string, IterationState>();\n /** The thread whose generate pane is open, if any. */\n private genOpen: string | null = null;\n /** Threads with a generation in flight. */\n private genBusy = new Set<string>();\n /** Opacity of the generated plane over the original, 0..1 (the compare slider). */\n private genOpacity = 0.6;\n /** The navigation consent state machine — a URL only ever comes out of `decide`. */\n private consent: ConsentRecord = emptyConsent();\n private consentEl!: HTMLElement;\n /** The live SpeechRecognition instance while dictating, if any. */\n private voice: any = null;\n private voiceEl!: HTMLElement;\n /** The project manager popover, and its search box. */\n private projMenu!: HTMLElement;\n private projOpen = false;\n private projError = \"\";\n private envDraft = \"\";\n /** Float-mode window geometry; (x<=0 && y<=0) → placed on first layout. */\n private floatRect = { x: 0, y: 0, w: 380, h: 540 };\n private floatDrag: { px: number; py: number; ox: number; oy: number } | null = null;\n private floatResize: { px: number; py: number; ow: number; oh: number } | null = null;\n\n private raf = 0;\n private mo?: MutationObserver;\n private tick?: number;\n\n constructor(cfg: LoupeConfig) {\n this.cfg = cfg;\n // apiBase set → talk to the backend; otherwise persist locally (prototype).\n this.store = cfg.apiBase\n ? new HttpAdapter(cfg.apiBase, cfg.user, cfg.userHmac, cfg.headers, cfg.credentials)\n : new LocalStorageAdapter();\n }\n\n private get url() { return location.pathname + location.search; }\n\n /** Chat is experimental: the tab stays dimmed and inert unless the host opts in. */\n private get chatOn() { return this.cfg.chat === true; }\n\n async start() {\n this.loadState();\n this.loadProject();\n this.buildDom();\n document.addEventListener(\"keydown\", this.onLauncherKey);\n document.addEventListener(\"click\", this.onDocumentClick, true);\n document.addEventListener(\"keydown\", this.onMenuKey);\n if (this.cfg.autoOpen) this.open = true;\n this.applyDockLayout();\n this.lastUrl = this.url;\n this.comments = await this.store.list(this.cfg.projectKey, this.url);\n this.renderPins();\n this.renderList();\n this.renderHome();\n this.startPresence();\n this.startLiveThreads();\n // Chat is off unless the host opts in, and then nothing listens for replies either.\n if (this.chatOn) this.startCompanionStream();\n void this.loadNotifications();\n void this.loadOrg();\n void this.loadActivity();\n this.syncActivityPoll();\n this.startSyncPoll();\n // The project-wide list feeds the \"All\" chip's count as well as the All scope, so it\n // is read on every start rather than only once the scope is switched.\n void this.loadAllComments();\n this.observe();\n this.watchNavigation();\n // First run: walk through the panel once. Skippable, never repeated, and off on\n // phones where the sheet is too small to spotlight anything useful.\n if (!this.tourDone && this.open && !this.isMobile()) this.startTour();\n if (this.cfg.autoOpen) this.setMode(this.cfg.tool === \"note\" ? \"free\" : \"inspect\");\n }\n\n /** Arm a tool from outside — the extension's context menus, or a host's own button. */\n openTool(tool: \"inspect\" | \"note\") {\n this.open = true;\n this.applyDockLayout();\n this.setMode(tool === \"note\" ? \"free\" : \"inspect\");\n }\n\n /**\n * Reload comments when the page URL changes without a full reload (SPA\n * navigation), so each page only ever shows its own comments.\n */\n private watchNavigation() {\n const onChange = () => {\n if (this.url === this.lastUrl) return;\n this.lastUrl = this.url;\n void this.reloadComments();\n };\n addEventListener(\"popstate\", onChange);\n // history.pushState/replaceState don't emit events — wrap them once.\n for (const key of [\"pushState\", \"replaceState\"] as const) {\n const original = history[key];\n history[key] = function (this: History, ...args: unknown[]) {\n const result = (original as (...a: unknown[]) => unknown).apply(this, args);\n dispatchEvent(new Event(\"loupe:locationchange\"));\n return result;\n } as History[typeof key];\n }\n addEventListener(\"loupe:locationchange\", onChange);\n }\n\n private async reloadComments() {\n try {\n this.comments = await this.store.list(this.cfg.projectKey, this.url);\n this.renderPins();\n this.renderList();\n } catch { /* keep the current view on transient errors */ }\n }\n\n /**\n * Keep the panel current without a reload.\n *\n * A status moved in another app (CRM approving a ticket), a reply relayed through Hub,\n * or a teammate's new pin otherwise appears only after the page reloads. The bridge's\n * SSE covers threads when one is configured; this covers everything else, for every\n * host. It pauses while the tab is hidden and catches up the moment it is shown again.\n */\n private startSyncPoll() {\n if (this.syncPoll) return;\n this.syncPoll = setInterval(() => void this.syncTick(), SYNC_POLL_MS);\n document.addEventListener(\"visibilitychange\", this.onSyncVisible);\n }\n\n private onSyncVisible = () => {\n if (document.visibilityState === \"visible\") void this.syncTick();\n };\n\n private async syncTick() {\n if (this.syncBusy || document.visibilityState === \"hidden\") return;\n // A re-render rebuilds the list, which would take the caret out of a reply box.\n const active = this.shadow?.activeElement;\n if (active && (active.tagName === \"TEXTAREA\" || active.tagName === \"INPUT\")) return;\n this.syncBusy = true;\n try {\n const url = this.url;\n const threads = [...this.messages.keys()];\n const [page, all, ...replies] = await Promise.all([\n this.store.list(this.cfg.projectKey, url).catch(() => null),\n this.allLoaded || this.scope === \"all\" ? this.store.listAll(this.cfg.projectKey).catch(() => null) : null,\n ...threads.map((id) => this.store.listMessages(id).catch(() => null)),\n ]);\n // Navigated while the reads were in flight: watchNavigation already reloaded.\n if (url !== this.url) return;\n let changed = false;\n if (Array.isArray(page) && JSON.stringify(page) !== JSON.stringify(this.comments)) {\n this.comments = page;\n changed = true;\n }\n if (Array.isArray(all) && JSON.stringify(all) !== JSON.stringify(this.allComments)) {\n this.allComments = all;\n changed = true;\n }\n threads.forEach((id, i) => {\n const list = replies[i];\n if (!Array.isArray(list)) return;\n // Replies still sending, or failed with a Retry, exist only here; keep them.\n const local = (this.messages.get(id) ?? []).filter((m) => this.msgPending.has(m.id) || this.msgFailed.has(m.id));\n const next = [...list, ...local];\n if (JSON.stringify(next) === JSON.stringify(this.messages.get(id))) return;\n this.messages.set(id, next);\n changed = true;\n });\n if (changed) {\n this.renderPins();\n this.renderList();\n this.renderHome();\n }\n } finally {\n this.syncBusy = false;\n }\n void this.loadNotifications();\n }\n\n // ---- DOM construction -----------------------------------------------------\n\n private buildDom() {\n this.root = document.createElement(\"div\");\n this.root.id = \"loupe-root\";\n document.body.appendChild(this.root);\n this.shadow = this.root.attachShadow({ mode: \"open\" });\n\n const style = document.createElement(\"style\");\n style.textContent = STYLES;\n this.shadow.appendChild(style);\n\n this.overlay = el(\"div\", \"overlay\");\n this.hl = el(\"div\", \"hl\");\n this.hl.appendChild(el(\"span\", \"tip\"));\n this.selbox = el(\"div\", \"selbox\");\n this.regionBox = el(\"div\", \"region-box\");\n this.overlay.append(this.hl, this.selbox, this.regionBox);\n this.shadow.appendChild(this.overlay);\n\n this.composer = el(\"div\", \"composer\");\n this.shadow.appendChild(this.composer);\n\n this.dock = this.buildDock();\n this.fabCluster = this.buildFabCluster();\n this.fabHandle = el(\"button\", \"fab-handle\") as HTMLButtonElement;\n this.fabHandle.type = \"button\";\n this.fabHandle.title = \"Show the launcher\";\n this.fabHandle.setAttribute(\"aria-label\", \"Show the launcher\");\n this.fabHandle.onclick = () => this.setLauncherHidden(false);\n this.recBar = this.buildRecBar();\n this.toastEl = el(\"div\", \"toast\");\n this.toastEl.setAttribute(\"role\", \"status\");\n this.toastEl.setAttribute(\"aria-live\", \"polite\");\n this.toastEl.onclick = () => this.toastEl.classList.remove(\"show\");\n\n // Guided tour overlay — click-through by design (see STYLES), so it can never\n // trap someone mid-task.\n this.tourEl = el(\"div\", \"tour\");\n this.tourSpot = el(\"div\", \"tour-spot\");\n this.tourCard = el(\"div\", \"tour-card\");\n this.tourEl.append(this.tourSpot, this.tourCard);\n\n this.shadow.append(this.dock, this.fabCluster, this.fabHandle, this.recBar, this.toastEl, this.tourEl);\n\n // A click anywhere outside a popover dismisses it.\n this.shadow.addEventListener(\"click\", (e) => {\n const t = e.target as HTMLElement | null;\n if (t?.closest && t.closest(\".menu-wrap\")) return;\n this.closeMenus();\n });\n }\n\n /**\n * The dockable control panel:\n * header (brand + dock controls) → tabs → [Comments view: tools + list + integrations]\n * and a [Connect view] with the Claude/MCP onboarding steps.\n */\n private buildDock(): HTMLElement {\n const dock = el(\"div\", \"dock\");\n\n // header ------------------------------------------------------------------\n const head = el(\"div\", \"dhead\");\n const brand = el(\"div\", \"brand\");\n brand.innerHTML = `<span class=\"logo\">◎</span><span class=\"title\"></span>`;\n (brand.querySelector(\".title\") as HTMLElement).textContent = this.cfg.label ?? \"Loupe\";\n head.addEventListener(\"pointerdown\", this.onHeadPointerDown); // drag in float mode\n\n const ctl = el(\"div\", \"dctl\");\n\n // Position menu — one button opening a 2x2 grid of the four layouts. Four\n // separate header buttons left no room once settings and minimize moved in.\n const posWrap = el(\"div\", \"menu-wrap\");\n const posBtn = el(\"button\") as HTMLButtonElement;\n posBtn.dataset.role = \"pos\";\n posBtn.title = \"Panel position\";\n posBtn.setAttribute(\"aria-label\", \"Panel position\");\n posBtn.innerHTML = I_DOCK_RIGHT;\n this.posMenu = el(\"div\", \"menu\");\n const posMeta: { mode: DockMode; icon: string; label: string }[] = [\n { mode: \"left\", icon: I_DOCK_LEFT, label: \"Left\" },\n { mode: \"bottom\", icon: I_DOCK_BOTTOM, label: \"Bottom\" },\n { mode: \"right\", icon: I_DOCK_RIGHT, label: \"Right\" },\n { mode: \"float\", icon: I_FLOAT, label: \"Float\" },\n ];\n this.posMenu.innerHTML = `<div class=\"menu-label\">Position</div><div class=\"pos-grid\">` +\n posMeta.map((m) => `<button data-pos=\"${m.mode}\">${m.icon}<span>${m.label}</span></button>`).join(\"\") +\n `</div>`;\n this.posMenu.querySelectorAll<HTMLElement>(\"[data-pos]\").forEach((b) => {\n b.onclick = () => { this.setDock(b.dataset.pos as DockMode); this.closeMenus(); };\n });\n posBtn.onclick = () => this.toggleMenu(this.posMenu);\n posWrap.append(posBtn, this.posMenu);\n\n this.themeBtn = el(\"button\") as HTMLButtonElement;\n this.themeBtn.dataset.role = \"theme\";\n this.themeBtn.onclick = () => this.toggleTheme();\n\n // Settings dropdown (theme accents, the help layer, replaying the tour).\n const setWrap = el(\"div\", \"menu-wrap\");\n const setBtn = el(\"button\") as HTMLButtonElement;\n setBtn.dataset.role = \"settings\";\n setBtn.title = \"Settings\";\n setBtn.setAttribute(\"aria-label\", \"Settings\");\n setBtn.innerHTML = I_GEAR;\n setBtn.onclick = () => this.toggleMenu(this.settingsMenu);\n // Built once and only ever reflected into — rewriting this menu's innerHTML on\n // every paint detached the row being clicked, so the outside-click handler saw\n // a detached target and closed the menu out from under the user.\n this.settingsMenu = el(\"div\", \"menu\");\n this.settingsMenu.innerHTML =\n `<div class=\"menu-label\">Appearance</div>` +\n `<div class=\"acc-dots\">` +\n ACCENTS.map((a) =>\n `<button class=\"acc-dot\" data-accent=\"${a.id}\" style=\"background:${a.dark}\" ` +\n `title=\"${a.id}\" aria-label=\"${a.id} accent\"></button>`).join(\"\") +\n `</div><div class=\"menu-sep\"></div><div class=\"menu-label\">Show</div>` +\n `<button class=\"menu-row\" data-set=\"hoverHints\" aria-pressed=\"true\"><span>Hover hints</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"markersHidden\" aria-pressed=\"true\"><span>Markers</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"showPaths\" aria-pressed=\"false\"><span>Page paths</span><span class=\"sw\"></span></button>` +\n `<button class=\"menu-row\" data-set=\"launcherHidden\" aria-pressed=\"true\" title=\"The ◎ button shown while the panel is closed. ${LAUNCHER_SHORTCUT} toggles it too.\"><span>Launcher</span><span class=\"sw\"></span></button>` +\n `<div class=\"menu-sep\"></div>` +\n `<button class=\"menu-row\" data-set=\"fabReset\" hidden><span>Reset launcher position</span></button>` +\n `<button class=\"menu-row\" data-set=\"tour\"><span>Restart tour</span></button>` +\n `<div class=\"menu-ver\"><span>Loupe <b>v${escapeHtml(SDK_VERSION)}</b>${this.packageVersionNote()}</span>` +\n `<span class=\"menu-mode\">${this.cfg.apiBase ? \"server\" : \"offline\"}</span></div>`;\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-accent]\").forEach((b) => {\n b.onclick = () => this.setAccent(b.dataset.accent!);\n });\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-set]\").forEach((b) => {\n b.onclick = () => {\n const key = b.dataset.set!;\n if (key === \"tour\") { this.closeMenus(); this.startTour(); return; }\n if (key === \"fabReset\") { this.closeMenus(); this.resetLauncherPosition(); return; }\n this.toggleSetting(key as \"markersHidden\" | \"hoverHints\" | \"showPaths\" | \"launcherHidden\");\n };\n });\n setWrap.append(setBtn, this.settingsMenu);\n\n const minBtn = el(\"button\") as HTMLButtonElement;\n minBtn.dataset.role = \"min\";\n minBtn.title = \"Minimize\";\n minBtn.setAttribute(\"aria-label\", \"Minimize\");\n minBtn.innerHTML = I_MINIMIZE;\n minBtn.onclick = () => this.setMinimized(true);\n\n const closeBtn = el(\"button\") as HTMLButtonElement;\n closeBtn.dataset.role = \"close\";\n closeBtn.title = \"Close\";\n closeBtn.setAttribute(\"aria-label\", \"Close\");\n closeBtn.innerHTML = I_CLOSE;\n closeBtn.onclick = () => this.closeDock();\n ctl.append(posWrap, this.themeBtn, setWrap, minBtn, closeBtn);\n\n // Who else has this page open. Hidden entirely when there is no bridge — an empty\n // cluster would read as \"nobody is here\", which is a different claim from \"we\n // cannot know who is here\".\n this.peerEl = el(\"div\", \"peers\");\n // Hidden from the start when there is no bridge: waiting for the first render to\n // hide it would show an empty cluster in the meantime.\n if (!this.cfg.bridge) this.peerEl.style.display = \"none\";\n head.append(brand, this.peerEl, ctl);\n\n // The minimize bar: a one-line strip that keeps the panel's context on screen.\n this.minBar = el(\"div\", \"minbar\");\n this.minBar.onclick = () => this.setMinimized(false);\n\n // tabs (built-in pages, then whatever the host registered) -----------------\n this.tabList = [...BUILTIN_TABS, ...(this.cfg.tabs ?? []).map((t) => ({ id: t.id, label: t.label }))];\n const tabs = el(\"div\", \"tabs\");\n for (const t of this.tabList) {\n const off = t.id === \"chat\" && !this.chatOn;\n const b = el(\"button\", off ? \"tab off\" : \"tab\", t.label) as HTMLButtonElement;\n b.dataset.tab = t.id;\n if (off) {\n b.setAttribute(\"aria-disabled\", \"true\");\n b.title = \"Chat — coming soon\";\n }\n b.onclick = () => this.setTab(t.id);\n tabs.appendChild(b);\n }\n\n // tools -------------------------------------------------------------------\n const tools = el(\"div\", \"tools\");\n const inspectBtn = this.toolBtn(\"✛\", \"Inspect\", \"inspect\");\n inspectBtn.title = \"Inspect an element and comment on it\";\n inspectBtn.onclick = () => this.setMode(this.mode === \"inspect\" ? \"off\" : \"inspect\");\n const freeBtn = this.toolBtn(NOTE_ICON, \"Note\", \"free\");\n freeBtn.title = \"Drop a note anywhere on the page — no element, no screenshot\";\n freeBtn.onclick = () => this.setMode(this.mode === \"free\" ? \"off\" : \"free\");\n const regionBtn = this.toolBtn(REGION_ICON, \"Region\", \"region\");\n regionBtn.title = \"Drag a free-size box, screenshot it, and comment\";\n regionBtn.onclick = () => this.setMode(this.mode === \"region\" ? \"off\" : \"region\");\n const recordBtn = this.toolBtn(RECORD_ICON, \"Record\", \"record\");\n recordBtn.title = isTouchDevice()\n ? \"Record your screen, then describe the issue\"\n : \"Drag a box, record a screen video of it, and comment\";\n recordBtn.onclick = () => this.setMode(this.mode === \"record\" ? \"off\" : \"record\");\n\n // Screen recording is desktop-only: NO mobile browser supports getDisplayMedia\n // (iOS Safari never has; Chrome/Firefox on Android expose it in old versions but every\n // call fails — recorded as unsupported). So on a phone we cannot record the screen\n // from the page at all. What we can do is take the clip the phone already recorded\n // with its own screen recorder — so open the picker for it, and deliberately WITHOUT\n // a `capture` attribute: that would open the camera, and filming the room is not a\n // screen recording.\n if (canShareScreen()) {\n tools.append(inspectBtn, freeBtn, regionBtn, recordBtn);\n } else if (isTouchDevice()) {\n const videoBtn = this.toolBtn(VIDEO_ICON, \"Video\", \"video\");\n videoBtn.title = \"Attach a video — record your screen with your phone, then pick it here\";\n videoBtn.onclick = () => this.pickVideo();\n tools.append(inspectBtn, freeBtn, regionBtn, videoBtn);\n } else {\n tools.append(inspectBtn, freeBtn, regionBtn);\n }\n\n // list --------------------------------------------------------------------\n const listHead = el(\"div\", \"listhead\");\n listHead.append(document.createTextNode(\"Comments\"));\n this.countEl = el(\"span\", \"count\", \"0\");\n listHead.appendChild(this.countEl);\n const search = el(\"input\", \"search\") as HTMLInputElement;\n search.type = \"search\";\n search.placeholder = \"Search…\";\n search.value = this.search;\n search.oninput = () => { this.search = search.value; this.renderList(); };\n listHead.appendChild(search);\n const filters = el(\"div\", \"listfilters\");\n this.statusSel = el(\"select\", \"lf-status\") as HTMLSelectElement;\n this.statusSel.setAttribute(\"aria-label\", \"Filter by status\");\n this.statusSel.append(optionEl(\"All statuses\", \"\", !this.statusFilter),\n ...(Object.keys(STAGE_LABELS) as (keyof typeof STAGE_LABELS)[]).map((k) => optionEl(STAGE_LABELS[k], k, this.statusFilter === k)));\n this.statusSel.onchange = () => { this.statusFilter = this.statusSel!.value; this.saveState(); this.renderList(); };\n this.sortSel = el(\"select\", \"lf-sort\") as HTMLSelectElement;\n this.sortSel.setAttribute(\"aria-label\", \"Order\");\n this.sortSel.append(optionEl(\"Newest first\", \"newest\", false), optionEl(\"Oldest first\", \"oldest\", false), optionEl(\"Page order\", \"page\", false));\n this.sortSel.onchange = () => { this.sortOrder = this.sortSel!.value as SortOrder; this.saveState(); this.renderList(); };\n filters.append(this.statusSel, this.sortSel);\n this.listEl = el(\"div\", \"list\");\n\n // Home view = the overview surface the panel opens on.\n const homeView = el(\"div\", \"view home-view\");\n this.homeEl = homeView;\n\n // Comments view = hint card + tools + list + the \"integrates with\" footer.\n const commentsView = el(\"div\", \"view comments-view\");\n this.commentsHint = el(\"div\", \"hint-slot\");\n this.reviewBar = el(\"div\", \"reviewbar\");\n this.reviewBar.style.display = \"none\";\n commentsView.append(this.commentsHint, tools, listHead, filters, this.reviewBar, this.listEl, this.buildIntegrations());\n\n // Activity view = the live monitor (status, summary, chips, feed). The hint slot\n // is part of this panel's own markup — appending it beforehand would be wiped by\n // the innerHTML below.\n const activityView = el(\"div\", \"view activity-view\");\n this.activityEl = activityView;\n\n // Chat view = the companion: a gather tray, a composer with dictation, and the\n // transcript of what was said to the agent and what it said back.\n const chatView = el(\"div\", \"view chat-view\");\n this.chatEl = chatView;\n\n // Host-registered tabs. `render` runs once, here, and gets a context object —\n // the panel never reaches into a tab, and a tab never reaches into the panel.\n const customViews = (this.cfg.tabs ?? []).map((t) => {\n const view = el(\"div\", \"view custom-view\");\n const slot = el(\"div\", \"hint-slot\");\n view.appendChild(slot);\n this.customHintSlots.set(t.id, slot);\n try {\n const out = t.render({\n projectKey: this.cfg.projectKey,\n apiBase: this.cfg.apiBase,\n user: this.cfg.user,\n comments: this.comments,\n url: this.url,\n version: SDK_VERSION,\n track: (event) => this.addActivity(event),\n open: (id) => this.setTab(id),\n close: () => this.closeDock(),\n });\n if (typeof out === \"string\") {\n // Built through innerHTML on a throwaway wrapper rather than\n // insertAdjacentHTML, which not every DOM implementation provides.\n const wrap = el(\"div\", \"tab-body\");\n wrap.innerHTML = out;\n view.append(...Array.from(wrap.childNodes));\n } else if (out) view.appendChild(out);\n } catch (e) {\n // A broken tab must not take the panel with it.\n view.appendChild(el(\"div\", \"empty\", `This tab failed to render: ${e instanceof Error ? e.message : String(e)}`));\n }\n return view;\n });\n\n const resize = el(\"div\", \"resize\");\n resize.addEventListener(\"pointerdown\", this.onResizeDown);\n\n // The navigation consent prompt. It lives above the tabs so an agent's request is\n // answered from wherever the user happens to be, not only on one page.\n this.consentEl = el(\"div\", \"consent\");\n this.consentEl.style.display = \"none\";\n\n dock.append(head, this.minBar, this.consentEl, tabs, homeView, commentsView, activityView, chatView, ...customViews, resize);\n for (const [id, view] of [[\"home\", homeView], [\"comments\", commentsView], [\"activity\", activityView], [\"chat\", chatView]] as [string, HTMLElement][]) {\n this.viewEls.set(id, view);\n }\n customViews.forEach((v, i) => this.viewEls.set((this.cfg.tabs ?? [])[i]!.id, v));\n this.buildHomePanel();\n this.buildActivityPanel();\n this.buildChatPanel();\n return dock;\n }\n\n /** The contextual hint cards live in a slot at the top of each view. */\n private commentsHint!: HTMLElement;\n private activityHint!: HTMLElement;\n /** The \"N waiting on your review\" strip above the list. */\n private reviewBar!: HTMLElement;\n /** Tab id → its hint slot (custom tabs only; the built-ins have named fields). */\n private customHintSlots = new Map<string, HTMLElement>();\n /** The tab strip, in order. */\n private tabList: { id: string; label: string }[] = [];\n /**\n * Each page's container, keyed by tab id. Display is driven by an \"on\" class\n * rather than a `.tab-<id>` selector, so host-registered ids need no CSS.\n */\n private viewEls = new Map<string, HTMLElement>();\n\n /**\n * The Activity view: a status row, a collapsible summary, the tool chips and the\n * live feed. Everything is re-derived from `activityEvents` on render, so the\n * summary and the micro-stats can never disagree with the feed below them.\n */\n // ---- companion chat (#28) -------------------------------------------------\n\n /** The chat page's root. */\n private chatEl!: HTMLElement;\n /** The gather tray: elements and screenshots collected into one message. */\n private chatTray: TrayState = emptyTray();\n /** Sent messages and received replies, in one ordered transcript. */\n private chatLog: { id: string; at: string; mine: boolean; author?: string; body: string; count?: number }[] = [];\n private chatUnread = 0;\n private chatSending = false;\n private chatError = \"\";\n private voiceOn = false;\n private voiceBase = \"\";\n private voiceStart = 0;\n private voiceTimer?: ReturnType<typeof setInterval>;\n private companionSource?: EventSource;\n\n private buildChatPanel() {\n this.chatEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-chint\"></div>` +\n `<div class=\"chat-tray\" id=\"loupe-tray\"></div>` +\n `<div class=\"chat-log\" id=\"loupe-chatlog\"></div>` +\n `<div class=\"chat-compose\">` +\n `<textarea class=\"chat-in\" id=\"loupe-chatin\" rows=\"2\" placeholder=\"Tell the agent what you see…\"></textarea>` +\n `<div class=\"chat-foot\">` +\n `<button class=\"chat-add\" id=\"loupe-chatadd\" title=\"Add what you have selected\">+ Selection</button>` +\n `<button class=\"chat-mic\" id=\"loupe-chatmic\" title=\"Dictate\">🎙</button>` +\n `<span class=\"chat-rec\" id=\"loupe-chatrec\" style=\"display:none\"><span class=\"chat-rec-dot\"></span><span id=\"loupe-chatrectime\">0:00</span></span>` +\n `<span class=\"chat-spacer\"></span>` +\n `<span class=\"chat-err\" id=\"loupe-chaterr\"></span>` +\n `<button class=\"chat-send\" id=\"loupe-chatsend\">Send</button>` +\n `</div></div>`;\n\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n input.addEventListener(\"click\", (e) => e.stopPropagation());\n input.oninput = () => { this.chatError = \"\"; this.renderChatError(); };\n input.onkeydown = (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) { e.preventDefault(); void this.sendCompanion(); }\n };\n\n (this.chatEl.querySelector(\"#loupe-chatadd\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n void this.addSelectionToTray();\n };\n (this.chatEl.querySelector(\"#loupe-chatsend\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n void this.sendCompanion();\n };\n (this.chatEl.querySelector(\"#loupe-chatmic\") as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n this.toggleVoice();\n };\n\n this.renderChatTray();\n this.renderChatLog();\n this.updateChatBadge();\n }\n\n /** The Chat tab label carries the unread count, so it is visible from any page. */\n private updateChatBadge() {\n if (!this.chatOn) return;\n const tab = this.tabList.findIndex((t) => t.id === \"chat\");\n const buttons = this.shadow?.querySelectorAll<HTMLElement>(\".tabs .tab\");\n const el2 = buttons?.[tab];\n if (!el2) return;\n el2.textContent = this.chatUnread ? `Chat · ${this.chatUnread > 9 ? \"9+\" : this.chatUnread}` : \"Chat\";\n }\n\n private renderChatError() {\n const box = this.chatEl?.querySelector(\"#loupe-chaterr\") as HTMLElement | null;\n if (box) box.textContent = this.chatError;\n }\n\n private renderChatTray() {\n const box = this.chatEl?.querySelector(\"#loupe-tray\") as HTMLElement | null;\n if (!box) return;\n box.textContent = \"\";\n if (!this.chatTray.items.length) { box.style.display = \"none\"; return; }\n box.style.display = \"\";\n\n const head = el(\"div\", \"tray-head\");\n head.append(\n el(\"span\", \"tray-title\", traySummary(this.chatTray)),\n el(\"span\", \"tray-spacer\"),\n );\n const clear = el(\"button\", \"tray-x\", \"Clear\") as HTMLButtonElement;\n clear.onclick = (e) => { e.stopPropagation(); this.chatTray = clearTray(); this.renderChatTray(); };\n head.appendChild(clear);\n box.appendChild(head);\n\n this.chatTray.items.forEach((item, i) => {\n const chip = el(\"div\", \"tray-chip\" + (item.include ? \"\" : \" off\"));\n\n const check = el(\"input\") as HTMLInputElement;\n check.type = \"checkbox\";\n check.checked = item.include;\n check.title = \"Include in the message\";\n check.onchange = (e) => {\n e.stopPropagation();\n this.chatTray = toggleInclude(this.chatTray, item.id);\n this.renderChatTray();\n };\n\n const label = el(\"span\", \"tray-label\", item.label);\n label.title = item.label + (item.url ? ` — ${item.url}` : \"\");\n\n const up = el(\"button\", \"tray-nudge\", \"↑\") as HTMLButtonElement;\n up.disabled = i === 0;\n up.onclick = (e) => { e.stopPropagation(); this.chatTray = nudgeInTray(this.chatTray, item.id, -1); this.renderChatTray(); };\n\n const down = el(\"button\", \"tray-nudge\", \"↓\") as HTMLButtonElement;\n down.disabled = i === this.chatTray.items.length - 1;\n down.onclick = (e) => { e.stopPropagation(); this.chatTray = nudgeInTray(this.chatTray, item.id, 1); this.renderChatTray(); };\n\n const x = el(\"button\", \"tray-x\", \"✕\") as HTMLButtonElement;\n x.title = \"Remove\";\n x.onclick = (e) => { e.stopPropagation(); this.chatTray = removeFromTray(this.chatTray, item.id); this.renderChatTray(); };\n\n chip.append(check, item.thumb ? (() => { const img = el(\"img\", \"tray-thumb\") as HTMLImageElement; img.src = item.thumb!; img.alt = \"\"; return img; })() : el(\"span\", \"tray-kind\", item.kind), label, up, down, x);\n box.appendChild(chip);\n });\n }\n\n private renderChatLog() {\n const box = this.chatEl?.querySelector(\"#loupe-chatlog\") as HTMLElement | null;\n if (!box) return;\n box.textContent = \"\";\n if (!this.chatLog.length) {\n box.appendChild(el(\"div\", \"chat-empty\",\n this.cfg.bridge\n ? \"Say what you see while the agent works — it lands on the agent’s very next step.\"\n : \"Connect a bridge to talk to the agent. Without one there is nothing to deliver to.\"));\n return;\n }\n for (const m of this.chatLog) {\n const row = el(\"div\", \"chat-msg\" + (m.mine ? \" mine\" : \"\"));\n const head = el(\"div\", \"chat-head\");\n head.append(\n el(\"b\", \"chat-who\", m.mine ? \"You\" : (m.author ?? \"Agent\")),\n el(\"span\", \"chat-when\", fmtAgo(m.at)),\n );\n if (m.count) head.appendChild(el(\"span\", \"chat-ctx\", `${m.count} context${m.count === 1 ? \"\" : \"s\"}`));\n const body = el(\"div\", \"chat-body\");\n for (const seg of mentionSegments(m.body, parseMentions(m.body))) {\n if (seg.mention) body.appendChild(el(\"span\", \"mention\", seg.text));\n else body.appendChild(document.createTextNode(seg.text));\n }\n row.append(head, body);\n box.appendChild(row);\n }\n box.scrollTop = box.scrollHeight;\n }\n\n /** Pull the current selection off the bridge and into the tray. */\n private async addSelectionToTray() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) { this.chatError = \"No bridge configured.\"; this.renderChatError(); return; }\n try {\n const res = await fetch(`${base}/selection/latest`);\n if (!res.ok) throw new Error(String(res.status));\n const { selection } = (await res.json()) as { selection?: any };\n if (!selection) { this.chatError = \"Nothing selected yet.\"; this.renderChatError(); return; }\n this.chatTray = addToTray(this.chatTray, {\n id: selection.correlationId ?? selection.selector ?? String(selection.at),\n kind: \"element\",\n // The selector is what identifies it; the text makes it recognisable.\n label: `${selection.selector ?? selection.tag ?? \"element\"}${selection.text ? ` — “${String(selection.text).slice(0, 24)}”` : \"\"}`,\n url: selection.url,\n ref: selection.correlationId ?? selection.selector,\n });\n this.chatError = \"\";\n this.renderChatError();\n this.renderChatTray();\n } catch (e) {\n this.chatError = e instanceof Error ? `Could not read the selection: ${e.message}` : \"Could not read the selection.\";\n this.renderChatError();\n }\n }\n\n private async sendCompanion() {\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n const body = input.value.trim();\n const contexts = trayPayload(this.chatTray);\n // A tray-only message is still a brief: showing three elements is a sentence.\n if (!body && !contexts.length) return;\n if (this.chatSending) return;\n\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) { this.chatError = \"No bridge configured — nothing to deliver to.\"; this.renderChatError(); return; }\n\n this.chatSending = true;\n this.chatError = \"\";\n this.renderChatError();\n const optimistic = {\n id: `pending-${Date.now().toString(36)}`,\n at: new Date().toISOString(),\n mine: true,\n body: body || \"(context only)\",\n count: contexts.length,\n };\n this.chatLog.push(optimistic);\n this.renderChatLog();\n\n try {\n const res = await fetch(`${base}/companion`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n body: body || \"(see the gathered context)\",\n author: { id: this.cfg.user.id, name: this.cfg.user.name },\n contexts,\n attachments: includedItems(this.chatTray)\n .filter((i) => i.kind === \"screenshot\" && i.thumb)\n .map((i) => ({ url: i.thumb!, kind: \"image\", name: i.label })),\n voice: this.voiceBase.length > 0,\n }),\n });\n if (!res.ok) throw new Error(`the bridge answered ${res.status}`);\n // Sent, so the tray has done its job.\n input.value = \"\";\n this.chatTray = clearTray();\n this.modelVoiceBase(\"\");\n this.renderChatTray();\n this.addActivity({ kind: \"message.create\", label: `Sent a brief to the agent${contexts.length ? ` (${contexts.length} contexts)` : \"\"}` });\n } catch (e) {\n this.chatError = e instanceof Error ? e.message : \"Could not send.\";\n this.renderChatError();\n this.addActivity({ kind: \"error\", level: \"error\", label: \"Companion message failed to send\" });\n } finally {\n this.chatSending = false;\n this.renderChatLog();\n }\n }\n\n private modelVoiceBase(v: string) { this.voiceBase = v; }\n\n /**\n * Dictation.\n *\n * Two different reasons the control can be unavailable, and they need different\n * words: an unsupported browser is a fact, while a non-secure page is something the\n * person can fix. Saying \"your browser cannot do this\" when the real problem is\n * `http://` sends them looking in the wrong place.\n */\n private toggleVoice() {\n const support = voiceSupport({\n hasCtor: typeof (globalThis as any).SpeechRecognition !== \"undefined\" || typeof (globalThis as any).webkitSpeechRecognition !== \"undefined\",\n isSecureContext: typeof isSecureContext === \"boolean\" ? isSecureContext : true,\n });\n if (support !== \"supported\") {\n this.chatError = voiceMessage(support) ?? \"Dictation is unavailable.\";\n this.renderChatError();\n return;\n }\n if (this.voiceOn) return this.stopChatVoice();\n\n const Ctor = (globalThis as any).SpeechRecognition ?? (globalThis as any).webkitSpeechRecognition;\n const input = this.chatEl.querySelector(\"#loupe-chatin\") as HTMLTextAreaElement;\n try {\n // One recogniser for the whole panel: two running at once would fight over the\n // microphone and each would transcribe the other's session.\n this.stopChatVoice();\n const rec = new Ctor();\n rec.continuous = true;\n rec.interimResults = true;\n rec.lang = document.documentElement.lang || \"en-US\";\n // Dictation appends to whatever was already typed rather than replacing it.\n this.voiceBase = input.value ? `${input.value.trim()} ` : \"\";\n rec.onresult = (ev: any) => {\n let text = \"\";\n for (let i = ev.resultIndex; i < ev.results.length; i++) text += ev.results[i][0].transcript;\n input.value = `${this.voiceBase}${text}`;\n };\n rec.onerror = (ev: any) => {\n this.chatError = ev?.error === \"not-allowed\" ? \"Microphone permission was refused.\" : \"Dictation stopped.\";\n this.renderChatError();\n this.stopChatVoice();\n };\n rec.onend = () => { if (this.voiceOn) this.stopChatVoice(); };\n rec.start();\n this.voice = rec;\n this.voiceTarget = input;\n this.voiceOn = true;\n this.voiceStart = Date.now();\n const pill = this.chatEl.querySelector(\"#loupe-chatrec\") as HTMLElement;\n pill.style.display = \"\";\n this.voiceTimer = setInterval(() => {\n const t = this.chatEl.querySelector(\"#loupe-chatrectime\") as HTMLElement | null;\n if (t) t.textContent = elapsedLabel(Date.now() - this.voiceStart);\n }, 500);\n this.chatEl.querySelector(\"#loupe-chatmic\")!.classList.add(\"on\");\n this.renderChatTray();\n } catch (e) {\n this.chatError = e instanceof Error ? e.message : \"Could not start dictation.\";\n this.renderChatError();\n }\n }\n\n private stopChatVoice() {\n this.voiceOn = false;\n if (this.voiceTimer) clearInterval(this.voiceTimer);\n this.voiceTimer = undefined;\n // Release the shared recogniser, so the panel never holds the microphone after the\n // person stopped talking to it.\n this.stopVoice();\n const pill = this.chatEl?.querySelector(\"#loupe-chatrec\") as HTMLElement | null;\n if (pill) pill.style.display = \"none\";\n this.chatEl?.querySelector(\"#loupe-chatmic\")?.classList.remove(\"on\");\n }\n\n /**\n * Follow the bridge for replies.\n *\n * With SSE where it works and a poll where it does not, because a reply the person\n * never sees is the same as no reply — and the panel is the only place it appears.\n */\n private startCompanionStream() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base || this.companionSource) return;\n if (typeof EventSource === \"undefined\") return;\n try {\n const source = new EventSource(`${base}/events`);\n // Named event, for the same reason as the thread stream above.\n source.addEventListener(\"companion\", (ev) => {\n let parsed: any;\n try { parsed = JSON.parse((ev as MessageEvent).data); } catch { return; }\n if (parsed?.eventType === \"reply\") this.receiveReply(parsed.data);\n });\n source.onerror = () => {};\n this.companionSource = source;\n // The stream can die without an event (a sleeping laptop); a slow poll keeps the\n // replies arriving either way.\n this.companionPoll = setInterval(() => void this.pollReplies(), 5000);\n } catch {\n // No stream: the poll is the whole transport then.\n this.companionPoll = setInterval(() => void this.pollReplies(), 4000);\n }\n }\n\n private companionPoll?: ReturnType<typeof setInterval>;\n private lastReplyId = \"\";\n\n private async pollReplies() {\n const base = this.cfg.bridge?.replace(/\\/$/, \"\");\n if (!base) return;\n try {\n const res = await fetch(`${base}/companion?since=${encodeURIComponent(this.lastReplyId)}`);\n if (!res.ok) return;\n const { replies } = (await res.json()) as { replies?: any[] };\n for (const r of replies ?? []) this.receiveReply(r);\n } catch {\n // The bridge is gone; the next tick will try again.\n }\n }\n\n private receiveReply(reply: any) {\n if (!reply?.id || !reply.body) return;\n // Both transports deliver, so the same reply can arrive twice. The id is what keeps\n // one reply from appearing as two.\n if (this.chatLog.some((m) => m.id === reply.id)) return;\n this.lastReplyId = reply.id;\n this.chatLog.push({ id: reply.id, at: reply.at ?? new Date().toISOString(), mine: false, body: reply.body });\n // Unread only counts when the person is not looking at the page it lands on.\n if (this.tab !== \"chat\" || this.minimized) {\n this.chatUnread++;\n this.updateChatBadge();\n this.desktopNotify(\"Loupe — the agent replied\", reply.body);\n }\n this.addActivity({ kind: \"agent.reply\", label: \"The agent replied\" });\n this.renderChatLog();\n }\n\n /** A desktop notification, when the browser will show one. Never a prompt for it. */\n private desktopNotify(title: string, body: string) {\n try {\n const N = (globalThis as any).Notification;\n if (!N || N.permission !== \"granted\") return;\n new N(title, { body: String(body).slice(0, 200), tag: \"loupe-companion\" });\n } catch {\n // Notifications are a nicety; a browser that refuses them is not an error.\n }\n }\n\n private buildActivityPanel() {\n this.activityEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-ahint\"></div>` +\n `<div class=\"mon-status\" id=\"loupe-mon-status\">` +\n `<span class=\"mon-dot\"></span><span class=\"mon-status-label\"></span>` +\n `<span class=\"mon-live\" id=\"loupe-mon-live\"></span>` +\n `<span class=\"mon-spacer\"></span>` +\n `<button class=\"mon-clear\" data-role=\"mon-clear\" title=\"Clear the feed\">Clear</button>` +\n `</div>` +\n `<div class=\"mon-summary\" id=\"loupe-mon-summary\"></div>` +\n `<div class=\"mon-micro\" id=\"loupe-mon-micro\"></div>` +\n `<div class=\"mon-chips\" id=\"loupe-mon-chips\"></div>` +\n `<div class=\"mon-feed\" id=\"loupe-mon-feed\"></div>`;\n this.feedEl = this.activityEl.querySelector(\"#loupe-mon-feed\") as HTMLElement;\n this.activityHint = this.activityEl.querySelector(\"#loupe-ahint\") as HTMLElement;\n\n (this.activityEl.querySelector('[data-role=\"mon-clear\"]') as HTMLElement).onclick = () => this.clearActivity();\n // Reading back through the feed stops it jumping to the bottom; scrolling to the\n // end starts following again. That is the \"pause on scroll\" behaviour, without a\n // separate pause button to forget about.\n this.feedEl.addEventListener(\"scroll\", () => {\n const el = this.feedEl;\n this.activityFollow = el.scrollHeight - el.scrollTop - el.clientHeight < 24;\n this.renderActivityChrome();\n });\n\n // Paint anything reported before this panel existed (e.g. by a tab's render()).\n this.renderActivity();\n }\n\n // ---- activity feed --------------------------------------------------------\n\n /** Push one event. Called by Loupe itself and by the public trackActivity(). */\n addActivity(input: ActivityEventInput) {\n const event: ActivityEvent = {\n id: input.id ?? `a${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n at: input.at ?? new Date().toISOString(),\n kind: input.kind,\n label: input.label,\n detail: input.detail,\n level: input.level ?? \"info\",\n files: input.files,\n };\n this.activityEvents.push(event);\n // Cap the ring so a long session cannot grow without bound.\n if (this.activityEvents.length > 500) this.activityEvents = this.activityEvents.slice(-500);\n // A reported error flips the status dot; progress resets it to working.\n this.activityStatus = event.level === \"error\" ? \"error\" : \"working\";\n this.renderActivity();\n }\n\n setActivityStatus(status: ActivityStatus) {\n this.activityStatus = status;\n this.renderActivity();\n }\n\n clearActivity() {\n this.activityEvents = [];\n this.activityFilter = \"\";\n this.activityStatus = \"idle\";\n this.renderActivity();\n }\n\n /**\n * Read the server's feed and merge it in by id. A backend without a feed answers\n * null once, and the panel stops asking.\n */\n private async loadActivity() {\n if (this.activityNone) return;\n let events: ActivityEvent[] | null;\n try {\n const read = this.store.listActivity?.bind(this.store);\n events = read ? await read(this.cfg.projectKey, this.activitySince || undefined) : null;\n } catch {\n if (this.activityRemote === \"live\") {\n this.activityRemote = \"offline\";\n this.renderActivity();\n }\n return;\n }\n if (events === null) {\n // Remember the answer, so neither the poll nor a tab switch asks again.\n this.activityRemote = \"unsupported\";\n this.activityNone = true;\n this.syncActivityPoll();\n this.renderActivity();\n return;\n }\n this.activityRemote = \"live\";\n const known = new Set(this.activityEvents.map((e) => e.id));\n const fresh = events.filter((e) => e && typeof e.id === \"string\" && !known.has(e.id));\n if (fresh.length) {\n this.activityEvents = [...this.activityEvents, ...fresh]\n .sort((a, b) => a.at.localeCompare(b.at))\n .slice(-500);\n const newest = fresh.reduce((m, e) => (e.at > m ? e.at : m), this.activitySince);\n this.activitySince = newest;\n // A recent server-side error is worth the red dot; an old one is history.\n const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString();\n if (fresh.some((e) => e.level === \"error\" && e.at >= tenMinutesAgo)) this.activityStatus = \"error\";\n }\n this.renderActivity();\n }\n\n /** Poll the server's feed every 15s, but only while the Activity view is on screen. */\n private syncActivityPoll() {\n const want = this.tab === \"activity\" && !this.activityNone && !!this.store.listActivity;\n if (want && !this.activityPoll) {\n this.activityPoll = setInterval(() => void this.loadActivity(), 15_000);\n } else if (!want && this.activityPoll) {\n clearInterval(this.activityPoll);\n this.activityPoll = undefined;\n }\n }\n\n /** The summary, status row, micro-stats and chips — derived, never stored. */\n private renderActivityChrome() {\n if (!this.activityEl) return;\n const status = this.activityEl.querySelector(\"#loupe-mon-status\") as HTMLElement | null;\n // A host tab's render() may report events while the panel is still being built,\n // before this markup exists. Those events are kept and painted once it does.\n if (!status) return;\n const s = summarizeActivity(this.activityEvents, this.activityStatus);\n\n status.querySelector(\".mon-status-label\")!.textContent = ACTIVITY_STATUS_LABELS[s.status];\n status.className = `mon-status st-${s.status}`;\n const live = status.querySelector(\"#loupe-mon-live\") as HTMLElement | null;\n if (live) {\n live.textContent = this.activityRemote === \"live\" ? \"Live\" : this.activityRemote === \"offline\" ? \"Offline\" : \"\";\n live.className = `mon-live ${this.activityRemote}`;\n }\n\n const summary = this.activityEl.querySelector(\"#loupe-mon-summary\") as HTMLElement;\n if (!s.events) {\n summary.innerHTML = \"\";\n summary.style.display = \"none\";\n } else {\n summary.style.display = \"\";\n const rows: [string, string][] = [\n [\"Status\", ACTIVITY_STATUS_LABELS[s.status]],\n [\"Events\", String(s.events)],\n [\"Duration\", formatDuration(s.durationMs)],\n [\"Files touched\", String(s.files)],\n [\"Errors\", String(s.errors)],\n [\"Tools\", s.byKind.map((k) => `${k.kind} ×${k.count}`).join(\", \") || \"—\"],\n ];\n summary.innerHTML =\n `<button class=\"mon-sum-head\" data-role=\"mon-toggle\" aria-expanded=\"${this.summaryOpen}\">` +\n `<span class=\"mon-sum-title\">Session summary</span>` +\n `<span class=\"mon-sum-peek\">${s.events} events · ${formatDuration(s.durationMs)} · ${s.files} files</span>` +\n `<span class=\"mon-caret\">${this.summaryOpen ? \"▾\" : \"▸\"}</span></button>` +\n `<div class=\"mon-sum-body\"${this.summaryOpen ? \"\" : ' style=\"display:none\"'}>` +\n rows.map(([k, v]) => `<div class=\"mon-kv\"><span>${escapeHtml(k)}</span><b>${escapeHtml(v)}</b></div>`).join(\"\") +\n `<div class=\"mon-preview\"></div></div>`;\n\n // Last event as the preview line. (`.at(-1)` is ES2022; the SDK targets ES2020.)\n summary.querySelector(\".mon-preview\")!.textContent =\n this.activityEvents[this.activityEvents.length - 1]?.label ?? \"\";\n (summary.querySelector('[data-role=\"mon-toggle\"]') as HTMLElement).onclick = () => {\n this.summaryOpen = !this.summaryOpen;\n this.renderActivityChrome();\n };\n }\n\n const micro = this.activityEl.querySelector(\"#loupe-mon-micro\") as HTMLElement;\n micro.textContent = \"\";\n if (s.events) {\n micro.append(\n el(\"span\", \"mon-micro-i\", `⏱ ${formatDuration(s.durationMs)}`),\n el(\"span\", \"mon-micro-i\", `◦ ${s.events} events`),\n el(\"span\", \"mon-micro-i\", `⧉ ${s.files} files`),\n );\n }\n\n const chips = this.activityEl.querySelector(\"#loupe-mon-chips\") as HTMLElement;\n chips.textContent = \"\";\n if (s.events) {\n const chip = (kind: string, label: string, count: number) => {\n const b = el(\"button\", \"mon-chip\" + (this.activityFilter === kind ? \" on\" : \"\"), `${label} ${count}`);\n b.dataset.kind = kind;\n b.onclick = () => {\n this.activityFilter = this.activityFilter === kind ? \"\" : kind;\n this.renderActivity();\n };\n return b;\n };\n chips.appendChild(chip(\"\", \"All\", s.events));\n for (const { kind, count } of s.byKind) chips.appendChild(chip(kind, kind, count));\n }\n }\n\n /** The feed itself, newest last (so it grows downward like a log). */\n private renderActivity() {\n if (!this.activityEl) return;\n this.renderActivityChrome();\n if (!this.feedEl) return;\n\n const events = this.activityFilter\n ? this.activityEvents.filter((e) => e.kind === this.activityFilter)\n : this.activityEvents;\n\n if (!events.length) {\n this.feedEl.innerHTML =\n `<div class=\"mon-empty\">` +\n (this.activityEvents.length\n ? `Nothing from <b>${escapeHtml(this.activityFilter)}</b> yet.`\n : this.activityRemote === \"live\"\n ? `No activity yet. Comments, status changes and forwarded tickets appear here.`\n : `<b>Monitor unavailable.</b> Nothing is feeding this view yet.<br>` +\n `A bridge or your app can push events with <code>Loupe.trackActivity({ kind, label })</code>, ` +\n `and Loupe reports its own operations here as you work.`) +\n `</div>`;\n return;\n }\n\n this.feedEl.innerHTML = events.map((e) => {\n const time = new Date(e.at).toLocaleTimeString(undefined, { hour12: false });\n return `<div class=\"mon-row lv-${e.level ?? \"info\"}\">` +\n `<span class=\"mon-time\">${escapeHtml(time)}</span>` +\n `<span class=\"mon-kind\">${escapeHtml(e.kind)}</span>` +\n `<span class=\"mon-label\">${escapeHtml(e.label)}` +\n (e.detail ? `<span class=\"mon-detail\">${escapeHtml(e.detail)}</span>` : \"\") +\n `</span></div>`;\n }).join(\"\");\n\n if (this.activityFollow) this.feedEl.scrollTop = this.feedEl.scrollHeight;\n }\n\n /**\n * The Home overview: four stat tiles over the current scope, a scope switch\n * (this page ↔ the whole project), a one-click way into capture, and the\n * most recent feedback. Every tile is a button that narrows the list.\n */\n private buildHomePanel() {\n const title = this.cfg.label ?? \"Loupe\";\n this.homeEl.innerHTML =\n `<div class=\"hint-slot\" id=\"loupe-hhint\"></div>` +\n `<div class=\"hstat\" id=\"loupe-hstats\"></div>` +\n `<div class=\"hscope\">` +\n `<button class=\"hscope-b\" data-scope=\"page\">This page <b class=\"hscope-n\"></b></button>` +\n `<button class=\"hscope-b\" data-scope=\"all\">All <b class=\"hscope-n\"></b></button>` +\n `<button class=\"hrefresh\" title=\"Refresh\" aria-label=\"Refresh\">⟳</button>` +\n `</div>` +\n `<button class=\"hpin\" data-role=\"home-pin\">✛ Pin feedback on this page</button>` +\n `<div class=\"projbar\">` +\n `<span class=\"proj-label\">Project</span>` +\n `<button class=\"proj-chip\" data-role=\"proj-open\" aria-haspopup=\"dialog\" aria-expanded=\"false\">` +\n `<span class=\"proj-name\"></span><span class=\"proj-caret\">▾</span></button>` +\n // The popover lives INSIDE .projbar: absolute positioning resolves against the\n // nearest positioned ancestor, and as a sibling it anchored to the panel\n // instead — landing off the bottom of the view.\n `<div class=\"proj-pop\" id=\"loupe-proj\" role=\"dialog\" aria-label=\"Project settings\"></div>` +\n `</div>` +\n `<div class=\"hnotif\" id=\"loupe-hnotif\"></div>` +\n `<div class=\"hlabel\">Recent</div>` +\n `<div class=\"hfeed\" id=\"loupe-hfeed\"></div>` +\n `<div class=\"hfoot\">${escapeHtml(title)} · <span class=\"hver\">v${escapeHtml(SDK_VERSION)}</span>${this.packageVersionNote()}</div>`;\n\n (this.homeEl.querySelector('[data-role=\"proj-open\"]') as HTMLElement).onclick = (e) => {\n e.stopPropagation();\n this.setProjectOpen(!this.projOpen);\n };\n\n this.homeEl.querySelectorAll<HTMLElement>(\".hscope-b\").forEach((b) => {\n b.onclick = () => this.setScope(b.dataset.scope === \"all\" ? \"all\" : \"page\");\n });\n (this.homeEl.querySelector('[data-role=\"home-pin\"]') as HTMLElement | null)!.onclick = () => {\n this.setTab(\"comments\");\n this.setMode(\"inspect\");\n };\n (this.homeEl.querySelector(\".hrefresh\") as HTMLElement | null)!.onclick = () => {\n void this.reloadComments();\n if (this.scope === \"all\") void this.loadAllComments();\n };\n }\n\n /** The comments the panel is currently looking at (page scope or project scope). */\n private get visibleComments(): Comment[] {\n return this.scope === \"all\" ? this.allComments : this.comments;\n }\n\n /** Switch the panel between \"this page\" and the whole project. */\n private setScope(scope: Scope) {\n this.scope = scope;\n this.saveState();\n // The project scope costs a fetch; do it once, then keep it fresh.\n if (scope === \"all\" && !this.allComments.length) void this.loadAllComments();\n this.renderHome();\n this.renderList();\n }\n\n private async loadAllComments() {\n try {\n this.allComments = await this.store.listAll(this.cfg.projectKey);\n this.allLoaded = true;\n this.renderHome();\n this.renderList();\n } catch { /* keep whatever we have */ }\n }\n\n /**\n * The four buckets a triager actually asks about. \"Stale\" is open work older\n * than a week — the thing that quietly rots on a board.\n */\n private homeStats(): { key: StatFilter; label: string; n: number }[] {\n const list = this.visibleComments;\n const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;\n return [\n { key: \"open\", label: \"Open\", n: list.filter((c) => normalizeStatus(c.status) !== \"resolved\").length },\n // The shared predicate, so the panel and the dashboard cannot disagree about\n // what \"needs you\" means. Only the stage is available here — the reasons that\n // depend on the last message are computed where the messages are loaded.\n { key: \"needs_you\", label: \"Needs you\", n: list.filter((c) => needsYou({ status: c.status }).needs).length },\n { key: \"resolved\", label: \"Resolved\", n: list.filter((c) => normalizeStatus(c.status) === \"resolved\").length },\n {\n key: \"stale\",\n label: \"Stale\",\n n: list.filter((c) => normalizeStatus(c.status) !== \"resolved\" && Date.parse(c.createdAt) < weekAgo).length,\n },\n ];\n }\n\n private renderHome() {\n if (!this.homeEl) return;\n const stats = this.homeStats();\n const statsEl = this.homeEl.querySelector(\"#loupe-hstats\") as HTMLElement | null;\n if (statsEl) {\n statsEl.innerHTML = stats\n .map((s) =>\n `<button class=\"hstat-b${this.statFilter === s.key ? \" on\" : \"\"}\" data-stat=\"${s.key}\">` +\n `<span class=\"hstat-n\">${s.n}</span><span class=\"hstat-l\">${s.label}</span></button>`)\n .join(\"\");\n statsEl.querySelectorAll<HTMLElement>(\".hstat-b\").forEach((b) => {\n b.onclick = () => {\n const key = b.dataset.stat as StatFilter;\n // Clicking the active tile clears the filter.\n this.statFilter = this.statFilter === key ? \"\" : key;\n this.setTab(\"comments\");\n };\n });\n }\n\n // Scope chips carry the counts, so \"All\" is a decision, not a guess. The project\n // total is only known once the project list has been read; until then it shows ⋯\n // rather than a number we would be inventing.\n const allKnown = this.allLoaded || this.scope === \"all\";\n const counts: Record<Scope, string> = {\n page: String(this.comments.length),\n all: allKnown ? String(this.allComments.length) : \"⋯\",\n };\n const labels: Record<Scope, string> = { page: \"This page\", all: \"All\" };\n this.homeEl.querySelectorAll<HTMLElement>(\".hscope-b\").forEach((b) => {\n const scope = (b.dataset.scope === \"all\" ? \"all\" : \"page\") as Scope;\n b.classList.toggle(\"on\", scope === this.scope);\n b.setAttribute(\"aria-pressed\", String(scope === this.scope));\n b.setAttribute(\"aria-label\", `${labels[scope]} — ${counts[scope]} comments`);\n (b.querySelector(\".hscope-n\") as HTMLElement).textContent = counts[scope];\n });\n this.renderProject();\n this.renderNotifications();\n\n const feed = this.homeEl.querySelector(\"#loupe-hfeed\") as HTMLElement | null;\n if (!feed) return;\n const recent = [...this.visibleComments]\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, 8);\n feed.innerHTML = recent.length\n ? recent.map((c) => {\n const stage = STAGE_LABELS[normalizeStatus(c.status)];\n const prio = normalizePriority(c.priority);\n // A div, not a button: the row holds its own action buttons.\n return `<div class=\"hfeed-i\" role=\"button\" tabindex=\"0\" data-id=\"${escapeAttr(c.id)}\">` +\n `<span class=\"hfeed-t\">${escapeHtml(c.title || (c.body.split(\"\\n\")[0] ?? \"\").slice(0, 60))}</span>` +\n `<span class=\"hfeed-m\">${escapeHtml(c.author?.name ?? \"\")} · <span title=\"${escapeAttr(this.fmtWhen(c.createdAt))}\">${fmtAgo(c.createdAt)}</span> · ` +\n `<span class=\"hfeed-s hfeed-s-${normalizeStatus(c.status)}\">${stage}</span>` +\n `<span class=\"hfeed-p hfeed-p-${prio}\">${PRIORITY_LABELS[prio]}</span></span>` +\n `<span class=\"hfeed-a\">` +\n `<button class=\"hfeed-act\" data-act=\"resolve\">${isResolved(c) ? \"Reopen\" : \"Resolve\"}</button>` +\n `<button class=\"hfeed-act\" data-act=\"open\">Open</button>` +\n `<button class=\"hfeed-act danger\" data-act=\"delete\">Delete</button>` +\n `</span></div>`;\n }).join(\"\")\n : `<div class=\"hempty\">Nothing here yet.</div>`;\n feed.querySelectorAll<HTMLElement>(\".hfeed-i\").forEach((b) => {\n const id = b.dataset.id!;\n const open = () => {\n this.statFilter = \"\";\n this.statusFilter = \"\";\n this.setTab(\"comments\");\n this.expanded.add(id);\n const c = recent.find((x) => x.id === id);\n if (c) void this.loadMessages(c);\n this.renderList();\n this.flash(id);\n };\n b.onclick = open;\n b.onkeydown = (e) => { if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); open(); } };\n b.querySelectorAll<HTMLButtonElement>(\".hfeed-act\").forEach((btn) => {\n btn.onclick = (e) => {\n e.stopPropagation();\n const c = recent.find((x) => x.id === id);\n if (!c) return;\n if (btn.dataset.act === \"open\") open();\n else if (btn.dataset.act === \"resolve\") void this.toggleResolved(c);\n else if (btn.dataset.act === \"delete\") {\n // A row on Home is a small target, so delete asks once before it acts.\n if (btn.dataset.armed) void this.deleteComment(c);\n else {\n btn.dataset.armed = \"1\";\n btn.textContent = \"Confirm delete\";\n setTimeout(() => { if (btn.isConnected) { delete btn.dataset.armed; btn.textContent = \"Delete\"; } }, 3000);\n }\n }\n };\n });\n });\n }\n\n /** In-app notifications: mentions of you, newest first. */\n private notifications: { id: string; threadId: string; body: string; actorName?: string; createdAt: string; readAt?: string }[] = [];\n\n\n private async loadNotifications() {\n try {\n // Guarded at the boundary rather than trusted: an adapter (or a server) that\n // answers with something other than a list must not leave `notifications`\n // undefined and take the whole Home render down with it.\n const list = await this.store.listNotifications(this.cfg.projectKey, this.cfg.user.id);\n this.notifications = Array.isArray(list) ? list : [];\n } catch {\n this.notifications = [];\n }\n this.renderNotifications();\n }\n\n /**\n * The mentions block. Rendered only when there are unread ones — a permanent empty\n * \"0 unread\" is noise, and the whole point is that it appears when it matters.\n */\n private renderNotifications() {\n const box = this.homeEl?.querySelector(\"#loupe-hnotif\") as HTMLElement | null;\n if (!box) return;\n const unread = this.notifications.filter((n) => !n.readAt);\n if (!unread.length) { box.innerHTML = \"\"; box.style.display = \"none\"; return; }\n box.style.display = \"\";\n box.innerHTML =\n `<div class=\"nf-head\"><span class=\"nf-dot\"></span><b>${unread.length}</b> mention${unread.length === 1 ? \"\" : \"s\"} waiting</div>` +\n unread.slice(0, 3).map((n) =>\n `<button class=\"nf-i\" data-thread=\"${escapeAttr(n.threadId)}\">` +\n `<span class=\"nf-b\">${escapeHtml(n.body)}</span>` +\n `<span class=\"nf-w\">${escapeHtml(fmtAgo(n.createdAt))}</span></button>`).join(\"\") +\n `<button class=\"nf-read\">Mark as read</button>`;\n\n box.querySelectorAll<HTMLElement>(\".nf-i\").forEach((b) => {\n b.onclick = () => {\n const id = b.dataset.thread!;\n this.scope = \"all\";\n if (!this.allComments.length) void this.loadAllComments();\n this.statFilter = \"\";\n this.setTab(\"comments\");\n this.expanded.add(id);\n this.renderList();\n this.flash(id);\n };\n });\n (box.querySelector(\".nf-read\") as HTMLElement).onclick = async () => {\n try {\n await this.store.markNotificationsRead(this.cfg.projectKey, this.cfg.user.id);\n } catch { /* the badge will clear on the next load if this failed */ }\n void this.loadNotifications();\n };\n }\n\n // ---- project manager (#60) ------------------------------------------------\n\n private setProjectOpen(open: boolean) {\n this.projOpen = open;\n this.projError = \"\";\n this.renderProject();\n }\n\n /** Read the organization once. A backend without the endpoint, or offline mode, leaves it null. */\n private async loadOrg() {\n try {\n this.org = (await this.store.getOrg?.()) ?? null;\n } catch {\n this.org = null;\n }\n this.renderProject();\n }\n\n /** \"Project · Organization\", or the project key when there is no organization to show. */\n private projectLabel(): string {\n const org = this.org;\n const name = org?.project.name || this.cfg.projectKey;\n return org?.organization ? `${name} · ${org.organization.name}` : name;\n }\n\n /** The Organization section of the project popover. Read-only: Hub owns this. */\n private orgSectionHtml(): string {\n const org = this.org;\n const head = `<div class=\"pp-head\"><span>Organization</span><button class=\"pp-x\" data-role=\"pp-close\" aria-label=\"Close\">✕</button></div>`;\n if (!org?.organization) {\n return head + `<div class=\"pp-cur\">` + (org?.error\n ? \"Could not reach Loupe Hub. Your organization's projects will show here when it is back.\"\n : \"This project is not connected to an organization. Connect it to Loupe Hub to see the \" +\n \"organization's projects and where its tickets go.\") + `</div>`;\n }\n const dest = org.project.destination;\n const others = org.projects;\n return head +\n `<div class=\"pp-cur\"><b>${escapeHtml(org.project.name || this.cfg.projectKey)}</b> in ` +\n `<b>${escapeHtml(org.organization.name)}</b>.</div>` +\n `<div class=\"pp-cur pp-dest\">${dest\n ? `Tickets go to <b>${escapeHtml(dest.name)}</b>.`\n : \"Tickets stay in this project.\"}</div>` +\n `<div class=\"pp-list pp-org\">` + (others.length\n ? others.map((p) =>\n `<div class=\"pp-proj${p.isDestination ? \" on\" : \"\"}\"><span class=\"pp-proj-n\">${escapeHtml(p.name)}</span>` +\n (p.receives ? `<span class=\"pp-badge\">receives tickets</span>` : \"\") + `</div>`).join(\"\")\n : `<div class=\"pp-empty\">No other projects in this organization yet.</div>`) + `</div>`;\n }\n\n private renderProjectError() {\n const box = this.homeEl?.querySelector(\"#loupe-pp-err\") as HTMLElement | null;\n if (!box) return;\n box.textContent = this.projError;\n box.style.display = this.projError ? \"\" : \"none\";\n }\n\n private renderProject() {\n if (!this.homeEl) return;\n const chip = this.homeEl.querySelector(\".proj-chip\") as HTMLElement | null;\n const pop = this.homeEl.querySelector(\"#loupe-proj\") as HTMLElement | null;\n if (!chip || !pop) return;\n (chip.querySelector(\".proj-name\") as HTMLElement).textContent = this.projectLabel();\n chip.classList.toggle(\"unset\", !this.org?.organization);\n chip.setAttribute(\"aria-expanded\", String(this.projOpen));\n\n if (!this.projOpen) { pop.classList.remove(\"open\"); pop.innerHTML = \"\"; return; }\n pop.classList.add(\"open\");\n\n const envs = this.project.environments;\n pop.innerHTML =\n this.orgSectionHtml() +\n `<div class=\"pp-sep\"></div>` +\n `<div class=\"pp-head\"><span>Environments</span></div>` +\n `<div class=\"pp-list\">` + (envs.length\n ? envs.map((u, i) =>\n `<div class=\"pp-env\"><span class=\"pp-env-u\" title=\"${escapeAttr(u)}\">${escapeHtml(u)}</span>` +\n `<button class=\"pp-x\" data-env-rm=\"${i}\" aria-label=\"Remove environment\">✕</button></div>`).join(\"\")\n : `<div class=\"pp-empty\">No environment URLs yet.</div>`) + `</div>` +\n `<div class=\"pp-add\"><input class=\"pp-env-url\" type=\"url\" placeholder=\"https://staging.example.com\" ` +\n `value=\"${escapeAttr(this.envDraft)}\" aria-label=\"Environment URL\">` +\n `<button class=\"pp-add-b\" data-role=\"env-add\">Add</button></div>` +\n `<div class=\"pp-sep\"></div>` +\n `<div class=\"pp-head\"><span>Local AI</span></div>` +\n `<div class=\"pp-empty\">Any OpenAI-compatible server — used by the Generate pane.</div>` +\n `<div class=\"pp-add\"><input class=\"pp-ai-url\" type=\"url\" placeholder=\"http://localhost:11434\" ` +\n `value=\"${escapeAttr(this.project.localAi?.url ?? \"\")}\" aria-label=\"Local AI endpoint\"></div>` +\n `<div class=\"pp-add\"><input class=\"pp-ai-model\" type=\"text\" placeholder=\"llama3.2\" ` +\n `value=\"${escapeAttr(this.project.localAi?.model ?? \"\")}\" aria-label=\"Model name\">` +\n `<button class=\"pp-add-b\" data-role=\"ai-save\">Save</button></div>` +\n `<div class=\"pp-add\"><button class=\"pp-clear\" data-role=\"ai-test\">Test connection</button></div>` +\n `<div class=\"pp-ai-out\" id=\"loupe-pp-ai\"></div>` +\n `<div class=\"pp-err\" id=\"loupe-pp-err\"></div>`;\n\n this.renderProjectError();\n\n (pop.querySelector('[data-role=\"pp-close\"]') as HTMLElement).onclick = () => this.setProjectOpen(false);\n\n pop.querySelectorAll<HTMLElement>(\"[data-env-rm]\").forEach((b) => {\n b.onclick = () => {\n const i = Number(b.dataset.envRm);\n this.project.environments = this.project.environments.filter((_, n) => n !== i);\n this.saveProject();\n this.renderProject();\n };\n });\n\n const url = pop.querySelector(\".pp-env-url\") as HTMLInputElement | null;\n if (url) {\n url.addEventListener(\"click\", (e) => e.stopPropagation());\n url.oninput = () => { this.envDraft = url.value; };\n url.onkeydown = (e) => { if (e.key === \"Enter\") (pop.querySelector('[data-role=\"env-add\"]') as HTMLElement).click(); };\n }\n (pop.querySelector('[data-role=\"env-add\"]') as HTMLElement).onclick = () => {\n const normalized = normalizeEnvUrl(this.envDraft);\n if (!normalized) {\n this.projError = \"Enter a full http:// or https:// URL.\";\n this.renderProjectError();\n return;\n }\n if (this.project.environments.includes(normalized)) {\n this.projError = \"That environment is already listed.\";\n this.renderProjectError();\n return;\n }\n this.project.environments = [...this.project.environments, normalized];\n this.envDraft = \"\";\n this.projError = \"\";\n this.saveProject();\n this.renderProject();\n (pop.querySelector(\".pp-env-url\") as HTMLInputElement | null)?.focus();\n };\n\n // Local AI: saved per browser, and checked against the real endpoint.\n for (const sel of [\".pp-ai-url\", \".pp-ai-model\"]) {\n pop.querySelector(sel)?.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n (pop.querySelector('[data-role=\"ai-save\"]') as HTMLElement).onclick = () => {\n const url = normalizeEnvUrl((pop.querySelector(\".pp-ai-url\") as HTMLInputElement).value);\n const model = (pop.querySelector(\".pp-ai-model\") as HTMLInputElement).value.trim();\n if (!url || !model) {\n this.setLocalAiStatus(this.project.localAi\n ? `Saved: ${this.project.localAi.model} at ${this.project.localAi.url}`\n : \"Nothing saved yet.\");\n this.projError = !url ? \"Enter a full http:// or https:// endpoint URL.\" : \"Enter a model name.\";\n this.renderProjectError();\n return;\n }\n this.projError = \"\";\n this.setLocalAi({ url, model });\n this.setLocalAiStatus(`Saved: ${model} at ${url}`);\n };\n (pop.querySelector('[data-role=\"ai-test\"]') as HTMLElement).onclick = () => {\n void this.testLocalAi(pop);\n };\n }\n\n /** Per-browser project settings, keyed separately from the dock's UI state. */\n private loadProject() {\n const fromConfig = (this.cfg.environments ?? []).filter((u): u is string => typeof u === \"string\");\n try {\n const raw = localStorage.getItem(`loupe:project:${this.cfg.projectKey}`);\n // A `repo` stored by an older version is ignored; repo linking is gone.\n const p = raw ? JSON.parse(raw) : null;\n const stored = Array.isArray(p?.environments)\n ? (p.environments as unknown[]).filter((u): u is string => typeof u === \"string\")\n : null;\n const localAi = p?.localAi && typeof p.localAi.url === \"string\" && typeof p.localAi.model === \"string\"\n ? { url: p.localAi.url as string, model: p.localAi.model as string }\n : undefined;\n this.project = { environments: stored ?? fromConfig, localAi };\n } catch {\n this.project = { environments: fromConfig };\n }\n }\n\n private saveProject() {\n try {\n localStorage.setItem(`loupe:project:${this.cfg.projectKey}`, JSON.stringify(this.project));\n } catch { /* storage unavailable */ }\n }\n\n /** The \"INTEGRATES WITH\" footer on the Comments page (visual only for now). */\n private buildIntegrations(): HTMLElement {\n const wrap = el(\"div\", \"integrations\");\n wrap.append(el(\"div\", \"ilabel\", \"INTEGRATES WITH\"));\n const row = el(\"div\", \"irow\");\n const icons: [string, string][] = [\n [\"GitHub\", I_GITHUB],\n [\"Slack\", I_SLACK],\n [\"Telegram\", I_TELEGRAM],\n [\"Linear\", I_LINEAR],\n ];\n for (const [name, icon] of icons) {\n const b = el(\"span\", \"ibtn\");\n b.title = `${name} — connect (coming soon)`;\n b.setAttribute(\"aria-label\", name);\n b.innerHTML = icon;\n row.appendChild(b);\n }\n wrap.appendChild(row);\n return wrap;\n }\n\n /** The floating \"recording…\" pill with a Stop button (shown only while recording). */\n private buildRecBar(): HTMLElement {\n const bar = el(\"button\", \"recbar\") as HTMLButtonElement;\n bar.title = \"Stop recording\";\n bar.setAttribute(\"aria-label\", \"Stop recording\");\n bar.onclick = () => this.stopRecording?.();\n return bar;\n }\n\n /**\n * The collapsed-state FAB cluster. The primary brand button carries the comment\n * count and OPENS the panel — one tap, the thing most people came for. A drag on\n * it moves the whole cluster anywhere on screen (persisted). The chevron beside it\n * is its own button and toggles the quick actions: pin a comment, drop a note,\n * hide/show the markers already on the page, hide the launcher itself, and — when\n * the host registered one — jump straight to the Connect tab.\n */\n private buildFabCluster(): HTMLElement {\n const cluster = el(\"div\", \"fab-cluster\");\n\n const minis = el(\"div\", \"fab-minis\");\n const mini = (role: string, icon: string, label: string, title: string) => {\n const b = el(\"button\", \"fab-mini\") as HTMLButtonElement;\n b.dataset.fab = role;\n b.title = title;\n b.setAttribute(\"aria-label\", title);\n b.innerHTML = `${icon}<span class=\"fab-tip\">${label}</span>`;\n return b;\n };\n const comment = mini(\"comment\", I_COMMENT, \"Pin comment\", \"Pin feedback on any element\");\n comment.onclick = () => { this.collapseFab(); this.openDock(); this.setMode(\"inspect\"); };\n const note = mini(\"note\", I_NOTE, \"Note\", \"Drop a note anywhere on the page\");\n note.onclick = () => { this.collapseFab(); this.openDock(); this.setMode(\"free\"); };\n const markers = mini(\"markers\", I_EYE, \"Markers\", \"Show or hide the markers on this page\");\n markers.onclick = () => this.toggleMarkers();\n const hide = mini(\"hide\", I_EYE_OFF, \"Hide launcher\",\n isTouchDevice() ? \"Hide this launcher — the tab at the screen edge brings it back\" : `Hide this launcher — ${LAUNCHER_SHORTCUT} brings it back`);\n hide.onclick = () => this.setLauncherHidden(true);\n minis.append(comment, note, markers, hide);\n // The Connect shortcut only exists when a \"connect\" tab is registered — the\n // panel no longer ships one, so it is opt-in via connectTab().\n if (this.tabList.some((t) => t.id === \"connect\")) {\n const connect = mini(\"connect\", I_PLUG, \"Connect Claude\", \"Set up the Claude/MCP connection\");\n connect.onclick = () => { this.collapseFab(); this.openDock(); this.setTab(\"connect\"); };\n minis.appendChild(connect);\n }\n\n const label = this.cfg.label ?? \"Loupe\";\n const primary = el(\"button\", \"launcher\") as HTMLButtonElement;\n primary.title = `Open ${label} — drag to move`;\n primary.setAttribute(\"aria-label\", `Open ${label}`);\n primary.innerHTML = `<span class=\"logo\">◎</span><span class=\"lcount\"></span>`;\n this.fabBadge = primary.querySelector(\".lcount\") as HTMLElement;\n // A tap opens the panel; a drag moves the launcher. Distance tells them apart, so\n // a shaky tap still opens and a real drag never opens by accident.\n primary.onclick = () => { if (this.fabSuppressClick) return; this.openDock(); };\n primary.addEventListener(\"pointerdown\", this.onFabPointerDown);\n primary.addEventListener(\"pointermove\", this.onFabPointerMove);\n primary.addEventListener(\"pointerup\", this.onFabPointerUp);\n primary.addEventListener(\"pointercancel\", this.onFabPointerUp);\n\n // The chevron is a separate button so the quick actions stay one tap away without\n // costing the primary tap, which now opens the panel.\n const more = el(\"button\", \"fab-more\") as HTMLButtonElement;\n more.dataset.fab = \"more\";\n more.title = \"Quick actions\";\n more.setAttribute(\"aria-label\", \"Quick actions\");\n more.setAttribute(\"aria-expanded\", \"false\");\n more.innerHTML = I_FAB_CHEVRON;\n more.onclick = (e) => { e.stopPropagation(); this.toggleFab(); };\n\n const main = el(\"div\", \"fab-main\");\n main.append(primary, more);\n cluster.append(minis, main);\n this.fabMinis = minis;\n return cluster;\n }\n\n /** Expand/collapse the quick actions out of the primary FAB. */\n private toggleFab() {\n this.fabExpanded = !this.fabExpanded;\n this.applyFab();\n }\n\n // ---- launcher: drag anywhere, hide, bring back ------------------------------\n\n private onFabPointerDown = (e: PointerEvent) => {\n if (e.pointerType === \"mouse\" && e.button !== 0) return;\n const target = e.currentTarget as HTMLElement;\n const r = target.getBoundingClientRect();\n this.fabDrag = { px: e.clientX, py: e.clientY, ox: r.left, oy: r.top, moved: false };\n // Capture the pointer so a fast drag that leaves the button keeps reporting to the\n // button's own listeners. Without capture support, follow the pointer on window.\n let captured = false;\n try {\n if (typeof target.setPointerCapture === \"function\") { target.setPointerCapture(e.pointerId); captured = true; }\n } catch { captured = false; /* pointer already up — a tap */ }\n if (!captured) {\n window.addEventListener(\"pointermove\", this.onFabPointerMove);\n window.addEventListener(\"pointerup\", this.onFabPointerUp);\n window.addEventListener(\"pointercancel\", this.onFabPointerUp);\n }\n };\n\n private onFabPointerMove = (e: PointerEvent) => {\n const d = this.fabDrag;\n if (!d) return;\n const dx = e.clientX - d.px, dy = e.clientY - d.py;\n if (!d.moved && Math.hypot(dx, dy) < FAB_DRAG_THRESHOLD) return;\n if (!d.moved) {\n d.moved = true;\n this.fabCluster.classList.add(\"dragging\");\n this.collapseFab();\n }\n e.preventDefault();\n this.fabPos = this.clampFabPos(d.ox + dx, d.oy + dy);\n this.applyFabPosition();\n };\n\n private onFabPointerUp = () => {\n window.removeEventListener(\"pointermove\", this.onFabPointerMove);\n window.removeEventListener(\"pointerup\", this.onFabPointerUp);\n window.removeEventListener(\"pointercancel\", this.onFabPointerUp);\n const d = this.fabDrag;\n this.fabDrag = null;\n if (!d?.moved) return;\n this.fabCluster.classList.remove(\"dragging\");\n this.saveState();\n this.renderSettings();\n // The browser fires a click right after this pointerup; that one must not open the panel.\n this.fabSuppressClick = true;\n window.setTimeout(() => { this.fabSuppressClick = false; }, 0);\n };\n\n /** Keep the launcher fully on screen, with a small margin so it never kisses the edge. */\n private clampFabPos(x: number, y: number): { x: number; y: number } {\n const m = 8;\n return {\n x: clampPx(Math.round(x), m, Math.max(m, window.innerWidth - FAB_SIZE - m)),\n y: clampPx(Math.round(y), m, Math.max(m, window.innerHeight - FAB_SIZE - m)),\n };\n }\n\n /**\n * Place the cluster. A dragged launcher is anchored to the viewport edge it is\n * nearest, so the quick actions always grow INTO the page: minis open upward from\n * the lower half and downward from the upper half, and their labels point away\n * from the nearest side. With no saved position the cluster sits in the default\n * corner on the dock's side, so reopening feels like the panel sliding back in.\n */\n private applyFabPosition() {\n const s = this.fabCluster.style;\n if (this.fabPos) {\n const { x, y } = this.clampFabPos(this.fabPos.x, this.fabPos.y);\n const atTop = y + FAB_SIZE / 2 < window.innerHeight / 2;\n const atLeft = x + FAB_SIZE / 2 < window.innerWidth / 2;\n s.left = atLeft ? `${x}px` : \"auto\";\n s.right = atLeft ? \"auto\" : `${Math.max(0, window.innerWidth - x - FAB_SIZE)}px`;\n s.top = atTop ? `${y}px` : \"auto\";\n s.bottom = atTop ? \"auto\" : `${Math.max(0, window.innerHeight - y - FAB_SIZE)}px`;\n this.fabCluster.classList.toggle(\"at-top\", atTop);\n this.fabCluster.classList.toggle(\"at-left\", atLeft);\n return;\n }\n const leftSide = this.dockMode === \"left\";\n s.left = leftSide ? \"20px\" : \"auto\";\n s.right = leftSide ? \"auto\" : \"20px\";\n s.top = \"auto\";\n s.bottom = \"\"; // the stylesheet's corner offset (20px, 16px on phones)\n this.fabCluster.classList.remove(\"at-top\");\n this.fabCluster.classList.toggle(\"at-left\", leftSide);\n }\n\n private resetLauncherPosition() {\n this.fabPos = null;\n this.saveState();\n this.applyDockLayout();\n this.renderSettings();\n }\n\n /**\n * Hide or show the collapsed launcher. Hidden is persisted, and the way back is\n * announced at the moment of hiding — a control that vanishes with no stated way\n * to return is a support ticket, not a feature.\n */\n private setLauncherHidden(hidden: boolean) {\n if (this.launcherHidden === hidden) return;\n this.launcherHidden = hidden;\n this.fabExpanded = false;\n this.saveState();\n this.applyDockLayout();\n this.renderSettings();\n const label = this.cfg.label ?? \"Loupe\";\n const back = isTouchDevice() ? \"tap the tab at the right edge of the screen\" : `press <kbd>${LAUNCHER_SHORTCUT}</kbd>`;\n this.toast(hidden\n ? `${escapeHtml(label)} launcher hidden — ${back} to bring it back`\n : `${escapeHtml(label)} launcher is back`);\n }\n\n /** Public seam for the host (`Loupe.showLauncher()`). */\n showLauncher() { this.setLauncherHidden(false); }\n\n /** Public seam for the host (`Loupe.hideLauncher()`). */\n hideLauncher() { this.setLauncherHidden(true); }\n\n /** A short notice at the bottom of the viewport. `html` is trusted markup built by the caller. */\n private toast(html: string, ms = 6000) {\n this.toastEl.innerHTML = html;\n this.toastEl.classList.add(\"show\");\n window.clearTimeout(this.toastTimer);\n this.toastTimer = window.setTimeout(() => this.toastEl.classList.remove(\"show\"), ms);\n }\n\n private collapseFab() {\n if (!this.fabExpanded) return;\n this.fabExpanded = false;\n this.applyFab();\n }\n\n /** Hide/show every pin on the page without losing them (persisted). */\n private toggleMarkers() {\n this.markersHidden = !this.markersHidden;\n this.saveState();\n this.applyFab();\n }\n\n /** Reflect cluster expansion + marker visibility into the DOM. */\n private applyFab() {\n this.fabCluster.classList.toggle(\"expanded\", this.fabExpanded);\n const more = this.fabCluster.querySelector('[data-fab=\"more\"]') as HTMLElement | null;\n more?.setAttribute(\"aria-expanded\", String(this.fabExpanded));\n more?.setAttribute(\"aria-label\", this.fabExpanded ? \"Close quick actions\" : \"Quick actions\");\n const markers = this.fabCluster.querySelector('[data-fab=\"markers\"]') as HTMLElement | null;\n markers?.classList.toggle(\"on\", this.markersHidden);\n markers?.setAttribute(\"aria-pressed\", String(this.markersHidden));\n // !important in CSS so it beats the inline display set by position().\n this.overlay.classList.toggle(\"hide-pins\", this.markersHidden);\n }\n\n /** A tool button with a uniform icon + label layout. `icon` may be an SVG string. */\n private toolBtn(icon: string, label: string, role: string): HTMLButtonElement {\n const b = el(\"button\") as HTMLButtonElement;\n b.dataset.role = role;\n b.setAttribute(\"aria-label\", label);\n b.innerHTML = `<span class=\"ico\">${icon}</span><span class=\"label\">${label}</span>`;\n return b;\n }\n\n // ---- inspector ------------------------------------------------------------\n\n // Pointer Events, not mouse events: a touch drag on a phone never fires\n // mousemove/mouseup, so Region/Record selection was impossible on touch devices.\n // Pointer events cover mouse, touch and pen with one handler each.\n\n private onMove = (e: PointerEvent) => {\n if (this.mode !== \"inspect\") return;\n const target = this.pick(e.clientX, e.clientY);\n if (!target) { this.hl.style.display = \"none\"; return; }\n const r = target.getBoundingClientRect();\n Object.assign(this.hl.style, {\n display: \"block\", left: r.left + \"px\", top: r.top + \"px\",\n width: r.width + \"px\", height: r.height + \"px\",\n });\n (this.hl.firstChild as HTMLElement).textContent =\n target.tagName.toLowerCase() + (target.id ? \"#\" + target.id : \"\");\n };\n\n private onClick = (e: MouseEvent) => {\n if (this.mode !== \"inspect\") return;\n const target = this.pick(e.clientX, e.clientY);\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n const r = target.getBoundingClientRect();\n this.targetOffset = {\n x: r.width ? clamp((e.clientX - r.left) / r.width) : 0.5,\n y: r.height ? clamp((e.clientY - r.top) / r.height) : 0.5,\n };\n this.setMode(\"off\");\n this.openComposer({ kind: \"element\", element: target }, e.clientX, e.clientY);\n };\n\n private onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") { this.cancelDrag(); this.setMode(\"off\"); this.closeComposer(); }\n };\n\n /**\n * Alt+Shift+L toggles the launcher — the way back once it has been hidden, so it is\n * listened for the whole time the widget is mounted (unlike Escape, which only\n * matters while a tool is armed). `code` is checked too: on some keyboard layouts\n * Alt+Shift+L yields a different `key`.\n */\n private onLauncherKey = (e: KeyboardEvent) => {\n if (!e.altKey || !e.shiftKey || e.ctrlKey || e.metaKey) return;\n if (e.code !== \"KeyL\" && (e.key ?? \"\").toLowerCase() !== \"l\") return;\n e.preventDefault();\n this.setLauncherHidden(!this.launcherHidden);\n };\n\n /**\n * The header popovers (position, settings) close on a click anywhere. The shadow-root\n * click listener in buildDom() only sees clicks inside the widget, so a click on the\n * host page used to leave the menu open over it. Capture phase, so a host that stops\n * propagation on its own controls still dismisses the menu.\n */\n private onDocumentClick = (e: MouseEvent) => {\n if (e.composedPath().includes(this.root)) return; // inside the widget: buildDom()'s listener decides\n this.closeMenus();\n };\n\n /** Escape closes an open popover, whether or not a tool is armed (onKey covers tools). */\n private onMenuKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") this.closeMenus();\n };\n\n // ---- region (\"free-size screenshot\") selection ----------------------------\n\n private onRegionDown = (e: PointerEvent) => {\n if (this.mode !== \"region\" && this.mode !== \"record\") return;\n // A mouse must use the primary button; touch/pen always start with button 0.\n if (e.pointerType !== \"touch\" && e.pointerType !== \"pen\" && e.button !== 0) return;\n // Ignore drags that start on our own UI (the panel overlays the page).\n const t = e.target as Element | null;\n if (t && (t.id === \"loupe-root\" || t.closest?.(\"#loupe-root\"))) return;\n e.preventDefault();\n e.stopPropagation();\n this.dragStart = { x: e.clientX, y: e.clientY };\n document.addEventListener(\"pointermove\", this.onRegionMove, true);\n document.addEventListener(\"pointerup\", this.onRegionUp, true);\n document.addEventListener(\"pointercancel\", this.onRegionCancel, true);\n this.drawSelection(e.clientX, e.clientY);\n };\n\n private onRegionMove = (e: PointerEvent) => {\n if (!this.dragStart) return;\n e.preventDefault();\n this.drawSelection(e.clientX, e.clientY);\n };\n\n private onRegionUp = (e: PointerEvent) => {\n if (!this.dragStart) return;\n e.preventDefault();\n e.stopPropagation();\n const start = this.dragStart;\n const wasRecord = this.mode === \"record\";\n this.cancelDrag();\n const vp: RegionRect = {\n x: Math.min(start.x, e.clientX), y: Math.min(start.y, e.clientY),\n w: Math.abs(e.clientX - start.x), h: Math.abs(e.clientY - start.y),\n };\n if (vp.w < 8 || vp.h < 8) { this.selbox.style.display = \"none\"; return; } // stray tap\n this.setMode(\"off\");\n if (wasRecord) void this.finishRecording(vp);\n else this.finishRegion(vp);\n };\n\n /** The OS took over the gesture (e.g. a system swipe): drop the selection. */\n private onRegionCancel = () => {\n this.cancelDrag();\n this.selbox.style.display = \"none\";\n };\n\n private drawSelection(curX: number, curY: number) {\n const s = this.dragStart!;\n Object.assign(this.selbox.style, {\n display: \"block\",\n left: Math.min(s.x, curX) + \"px\", top: Math.min(s.y, curY) + \"px\",\n width: Math.abs(curX - s.x) + \"px\", height: Math.abs(curY - s.y) + \"px\",\n });\n }\n\n private cancelDrag() {\n this.dragStart = null;\n document.removeEventListener(\"pointermove\", this.onRegionMove, true);\n document.removeEventListener(\"pointerup\", this.onRegionUp, true);\n document.removeEventListener(\"pointercancel\", this.onRegionCancel, true);\n }\n\n /**\n * Anchor a dragged viewport rect to the smallest element that covers most of it, so it\n * survives reflow. The rule used to take the element under the region's CENTER, which\n * for a large region is some small control inside it: the stored fractions then ran to\n * −7 and +15, and on any other viewport the pin landed far from the area. `rel`\n * (element-relative fractions) is preferred when an anchor is found; document coords\n * are the fallback. Shared by both the Region (screenshot) and Record (video) tools.\n */\n private regionFromViewport(vp: RegionRect): { region: RegionRect; element: Element | null } {\n const centerEl = this.pick(vp.x + vp.w / 2, vp.y + vp.h / 2);\n const anchorEl = regionContainer(centerEl, vp);\n let rel: RegionRect[\"rel\"];\n if (anchorEl) {\n const er = anchorEl.getBoundingClientRect();\n rel = {\n fx: (vp.x - er.left) / er.width, fy: (vp.y - er.top) / er.height,\n fw: vp.w / er.width, fh: vp.h / er.height,\n };\n }\n const region: RegionRect = { x: vp.x + window.scrollX, y: vp.y + window.scrollY, w: vp.w, h: vp.h, rel };\n return { region, element: anchorEl };\n }\n\n /**\n * Touch path for the Region tool: capture what is on screen right now and open the\n * composer with it already attached. The reporter scrolls to the part of the page they\n * mean FIRST, then taps Region — no drag, so nothing fights the page scroll.\n */\n private async captureViewportForComposer() {\n const vp: RegionRect = { x: 0, y: 0, w: window.innerWidth, h: window.innerHeight };\n const capture = this.cfg.captureRegion ?? captureRegionScreenshot;\n let shot: string | undefined;\n try {\n shot = await capture(vp);\n } catch {\n shot = undefined;\n }\n const file = shot ? dataUrlToFile(shot, \"screenshot.png\") : null;\n const docX = window.scrollX + vp.w / 2;\n const docY = window.scrollY + vp.h / 2;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.setMode(\"off\");\n this.openComposer(\n { kind: \"free\", offset, point: { x: docX, y: docY }, label: \"Screenshot · attached\" },\n 8,\n window.innerHeight / 2,\n file ? [file] : []\n );\n }\n\n /**\n * Attach a video on a phone, where the page cannot record the screen: the reporter\n * records it with the phone's own screen recorder first, then picks the clip here. No\n * `capture` attribute on purpose — that would force the camera open, and a video of the\n * room is not a screen recording.\n */\n private pickVideo() {\n this.setMode(\"off\");\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"video/*\";\n input.style.display = \"none\";\n input.onchange = () => {\n const file = input.files?.[0];\n input.remove();\n if (!file) return;\n const docX = window.scrollX + window.innerWidth / 2;\n const docY = window.scrollY + window.innerHeight / 2;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.openComposer(\n { kind: \"free\", offset, point: { x: docX, y: docY }, label: \"Video · attached\" },\n 8,\n window.innerHeight / 2,\n [file]\n );\n };\n // In the shadow root: keeps the host page's DOM untouched.\n this.shadow.appendChild(input);\n input.click();\n }\n\n /** Capture the selected viewport rect, then open the composer for a region comment. */\n private async finishRegion(vp: RegionRect) {\n this.selbox.style.display = \"none\";\n const { region, element } = this.regionFromViewport(vp);\n const target: ComposeTarget = { kind: \"region\", region, element };\n // Open the composer immediately; capture the screenshot in the background so a\n // slow capture never blocks the UI. It attaches to the comment on submit.\n this.openComposer(target, vp.x + vp.w, vp.y);\n const capture = this.cfg.captureRegion ?? captureRegionScreenshot;\n this.pendingShot = capture(vp);\n void this.pendingShot.then((shot) => {\n if (shot && this.pending === target) target.screenshot = shot;\n }).catch(() => undefined);\n }\n\n /**\n * Record a screen video of the selected rect (same drag-select as Region), then\n * open the composer with the recording attached. Unlike the screenshot flow this\n * is interactive — the browser share prompt and a Stop button drive it — so the\n * composer opens only once recording has finished.\n */\n private async finishRecording(vp: RegionRect) {\n this.selbox.style.display = \"none\";\n const { region, element } = this.regionFromViewport(vp);\n const capture = this.cfg.captureRecording ?? captureRegionRecording;\n this.showRecBar();\n let recording: string | undefined;\n try {\n // Call the capture synchronously (getDisplayMedia needs the click gesture).\n recording = await capture(vp, {\n maxMs: RECORD_MAX_MS,\n register: (stop) => { this.stopRecording = stop; },\n });\n } catch {\n recording = undefined;\n }\n this.hideRecBar();\n if (!recording) return; // user cancelled the share prompt or capture failed\n const target: ComposeTarget = { kind: \"region\", region, element, recording };\n const x = Math.min(vp.x + vp.w, window.innerWidth - 320);\n this.openComposer(target, x, vp.y);\n }\n\n private showRecBar() {\n this.stopRecording = undefined;\n this.recBar.innerHTML = `<span class=\"recdot\"></span><span>Recording… <b>Stop</b></span>`;\n this.recBar.classList.add(\"show\");\n }\n private hideRecBar() {\n this.recBar.classList.remove(\"show\");\n this.stopRecording = undefined;\n }\n\n /** elementFromPoint, ignoring our own UI. */\n private pick(x: number, y: number): Element | null {\n const hitHl = this.hl.style.display;\n this.hl.style.display = \"none\"; // never let the highlight itself be the hit\n const elAt = document.elementFromPoint(x, y);\n this.hl.style.display = hitHl;\n if (!elAt) return null;\n if (elAt.id === \"loupe-root\" || (elAt as Element).closest?.(\"#loupe-root\")) return null;\n return elAt;\n }\n\n private setMode(mode: Mode) {\n // Tools live on the Comments page — entering a mode implies the panel is open there.\n if (mode !== \"off\") {\n if (!this.open) this.open = true;\n if (this.tab !== \"comments\") { this.tab = \"comments\"; this.saveState(); }\n this.applyDockLayout();\n }\n this.mode = mode;\n this.hl.style.display = \"none\";\n this.selbox.style.display = \"none\";\n this.cancelDrag();\n document.body.style.cursor = mode === \"off\" ? \"\" : \"crosshair\";\n (this.dock.querySelector('[data-role=\"inspect\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"inspect\");\n (this.dock.querySelector('[data-role=\"free\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"free\");\n (this.dock.querySelector('[data-role=\"region\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"region\");\n (this.dock.querySelector('[data-role=\"record\"]') as HTMLElement)?.classList.toggle(\"on\", mode === \"record\");\n // On mobile this shrinks the bottom sheet to just header + tools (see styles)\n // so most of the page stays visible while picking an element/region.\n this.dock.classList.toggle(\"inspecting\", mode !== \"off\");\n\n document.removeEventListener(\"pointermove\", this.onMove, true);\n document.removeEventListener(\"pointerdown\", this.onMove, true);\n document.removeEventListener(\"click\", this.onClick, true);\n document.removeEventListener(\"click\", this.onFreeClick, true);\n document.removeEventListener(\"pointerdown\", this.onRegionDown, true);\n\n if (mode === \"off\") return;\n document.addEventListener(\"keydown\", this.onKey, true);\n this.closeComposer();\n if (mode === \"inspect\") {\n document.addEventListener(\"pointermove\", this.onMove, true);\n // Touch has no hover: highlight on finger-down so the user can see what a tap\n // will select before lifting (the tap itself still arrives as a click).\n document.addEventListener(\"pointerdown\", this.onMove, true);\n document.addEventListener(\"click\", this.onClick, true);\n } else if (mode === \"free\") {\n document.addEventListener(\"click\", this.onFreeClick, true);\n } else if (mode === \"region\" && isTouchDevice()) {\n // No drag-select on touch — a finger covers the area it is drawing, and the drag\n // fights the page scroll. Grab the visible viewport instead (the reporter scrolls\n // to what they mean first, then taps Region) and hand it to the composer.\n void this.captureViewportForComposer();\n } else if (mode === \"record\" && isTouchDevice()) {\n // Same one-tap idea for video: nothing to drag with a finger, so record the whole\n // screen. Called synchronously from the tap — getDisplayMedia needs that gesture.\n const vp: RegionRect = { x: 0, y: 0, w: window.innerWidth, h: window.innerHeight };\n this.setMode(\"off\");\n void this.finishRecording(vp);\n } else if (mode === \"region\" || mode === \"record\") {\n document.addEventListener(\"pointerdown\", this.onRegionDown, true);\n }\n }\n\n // ---- free note (drop a comment anywhere, no element / no screenshot) -------\n\n private onFreeClick = (e: MouseEvent) => {\n if (this.mode !== \"free\") return;\n const t = e.target as Element | null;\n if (t && (t.id === \"loupe-root\" || t.closest?.(\"#loupe-root\"))) return; // ignore our own UI\n e.preventDefault();\n e.stopPropagation();\n const docX = e.clientX + window.scrollX;\n const docY = e.clientY + window.scrollY;\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n // Store the drop point as a fraction of the document so it survives reloads\n // and reasonable reflow without needing any element anchor.\n const offset = { x: clamp(docX / docW), y: clamp(docY / docH) };\n this.setMode(\"off\");\n this.openComposer({ kind: \"free\", offset, point: { x: docX, y: docY } }, e.clientX, e.clientY);\n };\n\n // ---- composer -------------------------------------------------------------\n\n private openComposer(target: ComposeTarget, x: number, y: number, seedFiles: File[] = []) {\n this.pending = target;\n const isRecording = target.kind === \"region\" && !!target.recording;\n const c = this.composer;\n c.innerHTML = \"\";\n const label = el(\"div\", \"target\",\n target.kind === \"element\" ? describe(target.element)\n : target.kind === \"region\"\n ? (isRecording\n ? `⏺ Recording · ${Math.round(target.region.w)}×${Math.round(target.region.h)} px`\n : `Region · ${Math.round(target.region.w)}×${Math.round(target.region.h)} px`)\n : target.label ?? \"Free note · anywhere on the page\");\n const title = el(\"input\", \"title\") as HTMLInputElement;\n title.type = \"text\";\n title.placeholder = \"Title — one line: what's wrong, or what you need\";\n\n const ta = el(\"textarea\") as HTMLTextAreaElement;\n ta.placeholder = isRecording ? \"Describe the issue in this recording…\"\n : target.kind === \"region\" ? \"Describe the issue in this area…\"\n : target.kind === \"free\" ? \"Describe this note…\"\n : \"Describe what should change here…\";\n\n // Attachments: images and/or videos, several of each. A touch screenshot capture is\n // seeded here so it needs no extra tap to attach.\n const files: File[] = seedFiles.slice();\n const attach = el(\"div\", \"attach\");\n const pick = el(\"button\", \"pick\", \"+ Attach images / videos\") as HTMLButtonElement;\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*,video/*\";\n input.multiple = true;\n input.style.display = \"none\";\n const chips = el(\"div\", \"chips\");\n const err = el(\"div\", \"err\");\n const drawChips = () => {\n chips.innerHTML = \"\";\n files.forEach((f, idx) => {\n const chip = el(\"span\", \"chip\", `${attachmentKind(f.type) === \"video\" ? \"🎬\" : \"🖼\"} ${f.name}`);\n const x = el(\"button\", \"x\", \"×\") as HTMLButtonElement;\n x.onclick = () => { files.splice(idx, 1); drawChips(); };\n chip.appendChild(x);\n chips.appendChild(chip);\n });\n };\n input.onchange = () => {\n err.textContent = \"\";\n for (const f of Array.from(input.files ?? [])) {\n if (files.length >= MAX_FILES) { err.textContent = `Up to ${MAX_FILES} files.`; break; }\n const cap = attachmentKind(f.type) === \"video\" ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES;\n if (f.size > cap) { err.textContent = `${f.name} is too large.`; continue; }\n files.push(f);\n }\n input.value = \"\";\n drawChips();\n };\n pick.onclick = () => input.click();\n attach.append(pick, input, chips, err);\n if (files.length) drawChips();\n\n const row = el(\"div\", \"row\");\n // Triage metadata. Both default sensibly so a reporter can ignore them and\n // still file something the team can find and rank.\n const meta = el(\"div\", \"meta2\");\n const prioSel = document.createElement(\"select\");\n prioSel.className = \"mini\";\n prioSel.title = \"Priority\";\n prioSel.setAttribute(\"aria-label\", \"Priority\");\n for (const p of COMMENT_PRIORITIES) {\n prioSel.append(optionEl(PRIORITY_LABELS[p], p, p === DEFAULT_PRIORITY));\n }\n const typeSel = document.createElement(\"select\");\n typeSel.className = \"mini\";\n typeSel.title = \"Change type\";\n typeSel.setAttribute(\"aria-label\", \"Change type\");\n for (const t of CHANGE_TYPES) {\n typeSel.append(optionEl(CHANGE_TYPE_LABELS[t], t, t === DEFAULT_CHANGE_TYPE));\n }\n meta.append(prioSel, typeSel);\n // Free notes carry nothing; recordings always attach the video — both skip the checkbox.\n let box: HTMLInputElement | null = null;\n if (target.kind !== \"free\" && !isRecording) {\n const chk = el(\"label\", \"chk\") as HTMLLabelElement;\n box = document.createElement(\"input\"); box.type = \"checkbox\";\n // Default to attaching. Element shots are captured on submit; region shots are\n // captured in the background and awaited on submit (see pendingShot).\n box.checked = true;\n chk.append(box, document.createTextNode(\"Attach screenshot\"));\n row.append(chk);\n } else {\n row.style.justifyContent = \"flex-end\";\n }\n const btns = el(\"div\", \"btns\");\n const cancel = el(\"button\", \"ghost\", \"Cancel\") as HTMLButtonElement;\n cancel.onclick = () => this.closeComposer();\n const save = el(\"button\", \"primary\", \"Comment\") as HTMLButtonElement;\n save.disabled = true;\n const sync = () => { save.disabled = !title.value.trim() || !ta.value.trim(); };\n title.oninput = sync;\n ta.oninput = sync;\n sync();\n save.onclick = () => this.submit(\n target, title.value.trim(), ta.value.trim(), box ? box.checked : false, files.slice(),\n prioSel.value as CommentPriority, typeSel.value as ChangeType,\n );\n btns.append(this.voiceButton(ta), cancel, save);\n row.append(btns);\n c.append(label, title, ta, attach, meta, row);\n\n // Position near the click, clamped to the viewport.\n const w = 320, h = 380;\n const left = Math.min(Math.max(8, x + 12), window.innerWidth - w - 8);\n const top = Math.min(Math.max(8, y + 12), window.innerHeight - h - 8);\n Object.assign(c.style, { display: \"block\", left: left + \"px\", top: top + \"px\" });\n // Do not grab focus on touch: it throws the on-screen keyboard up over the very page\n // the reporter is describing (and over our own form).\n if (!isTouchDevice()) ta.focus();\n }\n\n private closeComposer() {\n this.composer.style.display = \"none\";\n this.pending = null;\n this.pendingShot = undefined;\n }\n\n private async submit(\n target: ComposeTarget,\n title: string,\n body: string,\n withShot: boolean,\n files: File[],\n priority: CommentPriority = DEFAULT_PRIORITY,\n changeType: ChangeType = DEFAULT_CHANGE_TYPE,\n ) {\n if (!title || !body) return;\n const saveBtn = this.composer.querySelector(\".primary\") as HTMLButtonElement;\n if (saveBtn) { saveBtn.disabled = true; saveBtn.textContent = \"Saving…\"; }\n\n let anchor: Anchor, context: Comment[\"context\"], offset: Comment[\"offset\"];\n let screenshot: string | undefined;\n let recording: string | undefined;\n let region: RegionRect | undefined;\n let anchoredEl: Element | null = null;\n\n if (target.kind === \"element\") {\n const capture = this.cfg.captureScreenshot ?? captureScreenshot;\n screenshot = withShot ? await capture(target.element) : undefined;\n anchor = captureAnchor(target.element);\n context = captureElementContext(target.element);\n offset = this.targetOffset;\n anchoredEl = target.element;\n } else if (target.kind === \"free\") {\n // A page-level note: no element, no screenshot. Its position lives in\n // `offset` as a fraction of the document (see onFreeClick + position()).\n screenshot = undefined;\n anchor = pageAnchor(target.point);\n context = { html: \"\", styles: {} };\n offset = target.offset;\n } else {\n // A recording carries its own visuals; a plain region uses the background\n // screenshot (awaited only if it hasn't attached yet).\n recording = target.recording;\n screenshot = !recording && withShot ? (target.screenshot ?? await this.pendingShot) : undefined;\n region = target.region;\n offset = { x: 0, y: 0 };\n // Prefer the real center-element anchor (survives reflow + gives Claude a\n // real element); fall back to a synthetic region anchor when there's none.\n if (target.element) {\n anchor = captureAnchor(target.element);\n context = captureElementContext(target.element);\n anchoredEl = target.element;\n } else {\n anchor = regionAnchor(region);\n context = { html: regionNote(region), styles: {} };\n }\n }\n\n const comment: Comment = {\n id: uid(),\n projectKey: this.cfg.projectKey,\n url: this.url,\n author: this.cfg.user,\n title,\n body,\n status: \"queue\",\n priority,\n changeType,\n kind: target.kind,\n anchor,\n context,\n offset,\n region,\n screenshot,\n recording,\n attachments: await this.uploadAttachments(files),\n // The screen this was captured on, plus enough to tell a stale bundle from a real\n // bug when someone reports \"it still doesn't work\" (see Comment.viewport).\n viewport: {\n w: window.innerWidth,\n h: window.innerHeight,\n v: SDK_VERSION,\n touch: isTouchDevice(),\n coarse: coarsePointer(),\n gdm: canShareScreen(),\n },\n createdAt: new Date().toISOString(),\n };\n await this.store.save(comment);\n this.comments.push(comment);\n this.resolved.set(comment.id, anchoredEl);\n this.closeComposer();\n this.renderPins();\n this.renderList();\n this.flash(comment.id);\n // Loupe's own work joins the same feed an agent bridge writes to.\n this.addActivity({\n kind: \"comment.create\",\n label: `Created “${comment.title || comment.body.split(\"\\n\")[0] || \"comment\"}”`,\n detail: [normalizePriority(comment.priority), comment.kind ?? \"element\", shortPath(comment.url)].join(\" · \"),\n });\n }\n\n /** Upload the reporter's picked files. A file that fails is skipped, not fatal. */\n private async uploadAttachments(files: File[]): Promise<Attachment[] | undefined> {\n if (!files.length) return undefined;\n const out: Attachment[] = [];\n for (const f of files) {\n try {\n out.push(await this.store.upload(this.cfg.projectKey, f));\n } catch (e) {\n console.warn(\"[loupe] attachment upload failed\", f.name, e);\n }\n }\n return out.length ? out : undefined;\n }\n\n // ---- pins + re-anchoring --------------------------------------------------\n\n private renderPins() {\n // Remove pins for deleted comments.\n for (const [id, pin] of this.pins) {\n if (!this.comments.find((c) => c.id === id)) { pin.remove(); this.pins.delete(id); }\n }\n this.comments.forEach((c, i) => {\n // A ticket another project sent here was filed on that project's page, not this one.\n if (c.source) return;\n let pin = this.pins.get(c.id);\n if (!pin) {\n pin = el(\"button\", \"pin\") as HTMLButtonElement;\n pin.onclick = () => { this.openDock(); this.flash(c.id); };\n this.overlay.appendChild(pin);\n this.pins.set(c.id, pin);\n }\n pin.textContent = String(i + 1);\n pin.classList.toggle(\"done\", isResolved(c));\n pin.classList.toggle(\"free\", c.kind === \"free\");\n });\n this.updateCount();\n this.position();\n }\n\n private updateCount(shown = this.comments.length) {\n this.countEl.textContent = String(shown);\n const n = this.comments.length;\n this.fabBadge.textContent = n ? String(n) : \"\";\n }\n\n /** Reposition every pin, re-resolving anchors whose element has gone. */\n private position = () => {\n for (const c of this.comments) {\n const pin = this.pins.get(c.id);\n if (!pin) continue;\n\n if (c.kind === \"free\") {\n // Page-level note: position from the stored document-fraction offset.\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n const px = c.offset.x * docW - window.scrollX;\n const py = c.offset.y * docH - window.scrollY;\n const onScreen = px > -24 && px < window.innerWidth + 24 && py > -24 && py < window.innerHeight + 24;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.remove(\"detached\");\n continue;\n }\n\n let elx = this.resolved.get(c.id) ?? null;\n if (!elx || !elx.isConnected) {\n // A malformed stored anchor (older client, or a row someone hand-wrote)\n // must detach that one pin, not abort the render for every other comment.\n let r: ResolveResult | null = null;\n try { r = resolveAnchor(c.anchor); } catch { r = null; }\n elx = r?.element ?? null;\n this.resolved.set(c.id, elx);\n }\n\n if (c.kind === \"region\") {\n // Compute the region's live viewport rect from its anchor element; fall\n // back to stored document coords (older data / no anchor found). A region\n // that was page-level from the start (synthetic anchor) is not \"moved\".\n const box = this.regionRect(c, elx);\n if (box) {\n const onScreen = box.x + box.w > 0 && box.x < window.innerWidth && box.y + box.h > 0 && box.y < window.innerHeight;\n // Keep the marker on the visible part of a large area: its top-left corner is\n // often scrolled off while most of the area is still on screen.\n const px = box.x < 4 ? Math.min(4, box.x + box.w - 30) : box.x;\n const py = box.y < 4 ? Math.min(4, box.y + box.h - 30) : box.y;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.toggle(\"detached\", !(elx && relUsable(c.region?.rel)) && c.anchor.tag !== \"region\");\n } else {\n pin.style.display = \"none\";\n pin.classList.add(\"detached\");\n }\n continue;\n }\n\n if (elx) {\n const rect = elx.getBoundingClientRect();\n const px = rect.left + c.offset.x * rect.width;\n const py = rect.top + c.offset.y * rect.height;\n const onScreen = rect.bottom > 0 && rect.top < window.innerHeight &&\n rect.right > 0 && rect.left < window.innerWidth && rect.width > 0;\n Object.assign(pin.style, { left: px + \"px\", top: py + \"px\", display: onScreen ? \"grid\" : \"none\" });\n pin.classList.remove(\"detached\");\n } else {\n pin.style.display = \"none\";\n pin.classList.add(\"detached\");\n }\n }\n\n // Keep the highlighted region outline glued to its live rect while scrolling.\n if (this.activeRegionId) {\n const c = this.comments.find((x) => x.id === this.activeRegionId);\n const box = c && this.regionRect(c, this.resolved.get(c.id) ?? null);\n if (box) {\n Object.assign(this.regionBox.style, {\n display: \"block\", left: box.x + \"px\", top: box.y + \"px\", width: box.w + \"px\", height: box.h + \"px\",\n });\n }\n }\n };\n\n /**\n * The current viewport rect for a region comment. Prefers the element-relative\n * fractions (so it tracks reflow across viewports); falls back to the stored\n * document coordinates minus scroll. Returns null if neither is available.\n */\n private regionRect(c: Comment, elx: Element | null): { x: number; y: number; w: number; h: number } | null {\n const rel = c.region?.rel;\n if (elx && relUsable(rel)) {\n const r = elx.getBoundingClientRect();\n return { x: r.left + rel.fx * r.width, y: r.top + rel.fy * r.height, w: rel.fw * r.width, h: rel.fh * r.height };\n }\n if (c.region) {\n return { x: c.region.x - window.scrollX, y: c.region.y - window.scrollY, w: c.region.w, h: c.region.h };\n }\n return null;\n }\n\n private observe() {\n const reposition = () => {\n cancelAnimationFrame(this.raf);\n this.raf = requestAnimationFrame(this.position);\n };\n window.addEventListener(\"scroll\", reposition, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"resize\", this.onWinResize);\n let debounce = 0;\n this.mo = new MutationObserver(() => {\n clearTimeout(debounce);\n debounce = window.setTimeout(() => { this.position(); this.renderList(); }, 120);\n });\n this.mo.observe(document.body, { childList: true, subtree: true, attributes: true, characterData: true });\n // Safety net for animated / late-loading layouts.\n this.tick = window.setInterval(this.position, 800);\n }\n\n // ---- dock: open / close / mode / theme ------------------------------------\n\n private openDock() {\n this.open = true;\n this.fabExpanded = false; // the panel replaces the quick actions\n this.saveState();\n this.applyDockLayout();\n this.renderList();\n }\n\n private closeDock() {\n this.open = false;\n this.setMode(\"off\");\n this.closeComposer();\n this.saveState();\n this.applyDockLayout();\n }\n\n private setDock(mode: DockMode) {\n this.dockMode = mode;\n this.open = true;\n this.saveState();\n this.applyDockLayout();\n }\n\n /** Switch the sidebar page (Home ↔ Comments ↔ Connect Claude). */\n private setTab(tab: Tab) {\n if (this.tab === tab) return;\n if (tab === \"chat\" && !this.chatOn) return;\n // Leaving the Comments page cancels any active picking tool.\n if (tab !== \"comments\") this.setMode(\"off\");\n this.tab = tab;\n this.hintFor = null; // a fresh view is a fresh chance for its hint card\n this.saveState();\n if (tab === \"home\") {\n this.renderHome();\n if (this.scope === \"all\" && !this.allComments.length) void this.loadAllComments();\n }\n if (tab === \"comments\") this.renderList();\n if (tab === \"activity\") {\n this.renderActivity();\n void this.loadActivity();\n }\n this.syncActivityPoll();\n this.applyDockLayout();\n }\n\n private toggleTheme() {\n this.theme = this.theme === \"dark\" ? \"light\" : \"dark\";\n this.saveState();\n this.applyDockLayout();\n }\n\n private onWinResize = () => this.applyDockLayout();\n\n // ---- panel shell: popovers, minimize, accent ------------------------------\n\n private toggleMenu(menu: HTMLElement) {\n const wasOpen = menu.classList.contains(\"open\");\n this.closeMenus();\n if (!wasOpen) menu.classList.add(\"open\");\n }\n\n private closeMenus() {\n this.posMenu?.classList.remove(\"open\");\n this.settingsMenu?.classList.remove(\"open\");\n }\n\n private setAccent(id: string) {\n if (!ACCENT_IDS.includes(id)) return;\n this.accent = id;\n this.saveState();\n this.applyDockLayout();\n }\n\n private setMinimized(v: boolean) {\n this.minimized = v;\n this.closeMenus();\n this.saveState();\n this.applyDockLayout();\n }\n\n /** Flip one of the \"Show …\" settings and repaint whatever it governs. */\n private toggleSetting(key: \"markersHidden\" | \"hoverHints\" | \"showPaths\" | \"launcherHidden\") {\n if (key === \"launcherHidden\") { this.setLauncherHidden(!this.launcherHidden); return; }\n if (key === \"markersHidden\") this.markersHidden = !this.markersHidden;\n else if (key === \"hoverHints\") this.hoverHints = !this.hoverHints;\n else this.showPaths = !this.showPaths;\n this.saveState();\n if (key === \"markersHidden\") this.renderPins();\n if (key === \"showPaths\") { this.renderList(); this.renderHome(); }\n if (key === \"hoverHints\") this.hintFor = null; // the visible card must go too\n this.applyDockLayout();\n }\n\n /** Reflect the current state into the settings menu (never rebuild it). */\n private renderSettings() {\n if (!this.settingsMenu) return;\n const on: Record<string, boolean> = {\n hoverHints: this.hoverHints,\n markersHidden: !this.markersHidden,\n showPaths: this.showPaths,\n launcherHidden: !this.launcherHidden,\n };\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-set]\").forEach((b) => {\n const key = b.dataset.set!;\n if (key in on) b.setAttribute(\"aria-pressed\", String(on[key]));\n // Only offered once there is a custom position to reset.\n if (key === \"fabReset\") b.hidden = !this.fabPos;\n });\n this.settingsMenu.querySelectorAll<HTMLElement>(\"[data-accent]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.accent === this.accent));\n }\n\n /**\n * The contextual hint card for the active view. Shown at most once per view and\n * never again after that — dismissed, or switched off wholesale with \"Turn off\n * hints\" (the same switch as Settings → Hover hints).\n */\n private renderHints() {\n if (!this.homeEl) return;\n if (this.hintFor === this.tab) return;\n this.hintFor = this.tab;\n const slots: Record<string, HTMLElement | null> = {\n home: this.homeEl.querySelector(\"#loupe-hhint\"),\n comments: this.commentsHint ?? null,\n activity: this.activityHint ?? null,\n };\n for (const [id, slot] of this.customHintSlots) slots[id] = slot;\n const slot = slots[this.tab];\n if (!slot) return;\n slot.innerHTML = \"\";\n const hint = this.hintForTab(this.tab);\n if (!hint || !this.hoverHints || this.minimized || this.hintsSeen.has(this.tab)) return;\n\n // Mark it seen the moment it is painted, so a reload does not replay it.\n this.hintsSeen.add(this.tab);\n this.saveState();\n slot.innerHTML =\n `<div class=\"hint\"><div class=\"hint-t\">${escapeHtml(hint.title)}</div>` +\n `<div class=\"hint-b\">${escapeHtml(hint.body)}</div>` +\n `<button class=\"hint-off\" data-role=\"hint-off\">Turn off hints</button>` +\n `<button class=\"hint-x\" aria-label=\"Dismiss hint\">✕</button></div>`;\n (slot.querySelector('[data-role=\"hint-off\"]') as HTMLElement).onclick = () => {\n this.hoverHints = false;\n // Force the next paint to re-evaluate this view, otherwise the early-return\n // above would leave the card it was clicked from on screen.\n this.hintFor = null;\n this.saveState();\n this.applyDockLayout();\n };\n (slot.querySelector(\".hint-x\") as HTMLElement).onclick = () => { slot.innerHTML = \"\"; };\n }\n\n /** Which view's hint has been handled this session (so it is not re-painted). */\n private hintFor: Tab | null = null;\n\n /** The built-in hints, plus any a registered tab declared for itself. */\n private hintForTab(id: string): { title: string; body: string } | undefined {\n if (id in HINTS) return HINTS[id as BuiltinTab];\n return (this.cfg.tabs ?? []).find((t) => t.id === id)?.hint;\n }\n\n // ---- guided tour ----------------------------------------------------------\n\n private startTour() {\n this.tourStep = 0;\n this.open = true;\n this.minimized = false;\n this.applyDockLayout();\n this.renderTour();\n }\n\n private stopTour() {\n this.tourStep = -1;\n this.tourDone = true;\n this.saveState();\n this.tourEl.classList.remove(\"open\");\n this.applyDockLayout();\n }\n\n private gotoTour(step: number) {\n if (step < 0) { this.stopTour(); return; }\n this.tourStep = step;\n this.renderTour();\n }\n\n /** Position the spotlight over the current step's target and lay out the card. */\n private renderTour() {\n if (this.tourStep < 0 || this.tourStep >= TOUR.length) {\n this.tourEl.classList.remove(\"open\");\n return;\n }\n const step = TOUR[this.tourStep]!;\n if (this.tab !== step.tab) this.setTab(step.tab);\n this.tourEl.classList.add(\"open\");\n\n const pad = 4;\n const target = this.shadow.querySelector(step.sel) as HTMLElement | null;\n const box = target?.getBoundingClientRect();\n const r = box && box.width\n ? { left: box.left - pad, top: box.top - pad, width: box.width + pad * 2, height: box.height + pad * 2 }\n // No on-screen target (panel closed, or the view is hidden) — centre the card.\n : { left: window.innerWidth / 2, top: window.innerHeight / 2, width: 0, height: 0 };\n this.tourSpot.style.left = `${r.left}px`;\n this.tourSpot.style.top = `${r.top}px`;\n this.tourSpot.style.width = `${r.width}px`;\n this.tourSpot.style.height = `${r.height}px`;\n\n const last = this.tourStep === TOUR.length - 1;\n this.tourCard.innerHTML =\n `<div class=\"tour-title\">${escapeHtml(step.title)}</div>` +\n `<div class=\"tour-body\">${escapeHtml(step.body)}</div>` +\n `<div class=\"tour-foot\">` +\n `<span class=\"tour-dots\">${TOUR.map((_, i) => `<i class=\"${i === this.tourStep ? \"on\" : \"\"}\"></i>`).join(\"\")}</span>` +\n (this.tourStep > 0 ? `<button class=\"t-back\">Back</button>` : \"\") +\n `<button class=\"t-skip\">Skip</button>` +\n `<button class=\"t-next\">${last ? \"Done\" : \"Next\"}</button>` +\n `</div>`;\n\n // Place the card below the spotlight, else above, else beside it — rejecting any\n // spot that would land on the very thing it points at, and clamping the rest\n // into the viewport. (Clamping alone used to push the card back onto the target.)\n const W = 252;\n const H = this.tourCard.offsetHeight || 130;\n const overlapsTarget = (x: number, y: number) =>\n x < r.left + r.width + 8 && x + W > r.left - 8 && y < r.top + r.height + 8 && y + H > r.top - 8;\n const candidates: [number, number][] = [\n [r.left + r.width / 2 - W / 2, r.top + r.height + 12], // below\n [r.left + r.width / 2 - W / 2, r.top - H - 12], // above\n [r.left - W - 12, r.top + r.height / 2 - H / 2], // beside (left)\n [r.left + r.width + 12, r.top + r.height / 2 - H / 2], // beside (right)\n ];\n let cx = clampPx(candidates[0]![0], 8, Math.max(8, window.innerWidth - W - 8));\n let cy = clampPx(candidates[0]![1], 8, Math.max(8, window.innerHeight - H - 8));\n for (const [x, y] of candidates) {\n const px = clampPx(x, 8, Math.max(8, window.innerWidth - W - 8));\n const py = clampPx(y, 8, Math.max(8, window.innerHeight - H - 8));\n cx = px; cy = py;\n if (!overlapsTarget(px, py)) break;\n }\n this.tourCard.style.left = `${cx}px`;\n this.tourCard.style.top = `${cy}px`;\n\n (this.tourCard.querySelector(\".t-back\") as HTMLElement | null)?.addEventListener(\"click\", () => this.gotoTour(this.tourStep - 1));\n (this.tourCard.querySelector(\".t-skip\") as HTMLElement)!.addEventListener(\"click\", () => this.stopTour());\n (this.tourCard.querySelector(\".t-next\") as HTMLElement)!.addEventListener(\"click\", () => {\n if (last) this.stopTour(); else this.gotoTour(this.tourStep + 1);\n });\n }\n\n /** Narrow viewports render the panel as a bottom sheet, not a side/float dock. */\n private isMobile() { return window.innerWidth <= 640; }\n\n private loadState() {\n try {\n const s = localStorage.getItem(\"loupe:dock\");\n if (!s) return;\n const p = JSON.parse(s);\n if (DOCK_MODES.includes(p?.mode)) this.dockMode = p.mode;\n if (typeof p?.open === \"boolean\") this.open = p.open;\n if (p?.theme === \"light\" || p?.theme === \"dark\") this.theme = p.theme;\n const known = [...BUILTIN_TABS.map((t) => t.id).filter((id) => id !== \"chat\" || this.chatOn), ...(this.cfg.tabs ?? []).map((t) => t.id)];\n if (typeof p?.tab === \"string\" && known.includes(p.tab)) this.tab = p.tab;\n if (p?.scope === \"page\" || p?.scope === \"all\") this.scope = p.scope;\n if (typeof p?.statFilter === \"string\") this.statFilter = p.statFilter as StatFilter;\n if (typeof p?.statusFilter === \"string\" && p.statusFilter in STAGE_LABELS) this.statusFilter = p.statusFilter;\n if ([\"newest\", \"oldest\", \"page\"].includes(p?.sortOrder)) this.sortOrder = p.sortOrder;\n if (p?.float && typeof p.float.w === \"number\") this.floatRect = { ...this.floatRect, ...p.float };\n if (typeof p?.markersHidden === \"boolean\") this.markersHidden = p.markersHidden;\n if (typeof p?.launcherHidden === \"boolean\") this.launcherHidden = p.launcherHidden;\n if (p?.fab && typeof p.fab.x === \"number\" && typeof p.fab.y === \"number\") this.fabPos = { x: p.fab.x, y: p.fab.y };\n if (p?.accent && ACCENT_IDS.includes(p.accent)) this.accent = p.accent;\n if (typeof p?.minimized === \"boolean\") this.minimized = p.minimized;\n if (typeof p?.hoverHints === \"boolean\") this.hoverHints = p.hoverHints;\n if (typeof p?.showPaths === \"boolean\") this.showPaths = p.showPaths;\n if (typeof p?.tourDone === \"boolean\") this.tourDone = p.tourDone;\n if (Array.isArray(p?.hintsSeen)) this.hintsSeen = new Set(p.hintsSeen.filter((x: unknown) => typeof x === \"string\"));\n } catch { /* storage unavailable → defaults */ }\n }\n\n private saveState() {\n try {\n localStorage.setItem(\"loupe:dock\", JSON.stringify({\n mode: this.dockMode, open: this.open, theme: this.theme, tab: this.tab, float: this.floatRect,\n markersHidden: this.markersHidden, launcherHidden: this.launcherHidden, fab: this.fabPos,\n scope: this.scope, statFilter: this.statFilter, statusFilter: this.statusFilter, sortOrder: this.sortOrder,\n accent: this.accent, minimized: this.minimized, hoverHints: this.hoverHints,\n showPaths: this.showPaths, tourDone: this.tourDone, hintsSeen: [...this.hintsSeen],\n }));\n } catch { /* ignore */ }\n }\n\n /** Reflect all control-panel state (theme, dock mode, geometry, launcher) into the DOM. */\n private applyDockLayout() {\n this.root.classList.toggle(\"theme-light\", this.theme === \"light\");\n this.themeBtn.title = this.theme === \"dark\" ? \"Switch to light theme\" : \"Switch to dark theme\";\n this.themeBtn.innerHTML = this.theme === \"dark\" ? I_SUN : I_MOON;\n\n // The accent is an inline custom property on the host, so it beats both token\n // blocks and follows the theme.\n const accent = ACCENTS.find((a) => a.id === this.accent) ?? ACCENTS[0]!;\n this.root.style.setProperty(\"--accent\", this.theme === \"light\" ? accent.light : accent.dark);\n this.root.style.setProperty(\"--accent-soft\", accent.soft);\n\n const d = this.dock;\n d.classList.toggle(\"open\", this.open);\n for (const m of DOCK_MODES) d.classList.toggle(\"mode-\" + m, this.dockMode === m);\n d.classList.toggle(\"minimized\", this.minimized);\n // The minimize bar keeps the panel's context — and a way back — on one line.\n const openCount = this.comments.filter((c) => !isResolved(c)).length;\n this.minBar.innerHTML =\n `<span class=\"logo\">◎</span>` +\n `<span class=\"mtext\"><b>${openCount}</b> open ${this.scope === \"all\" ? \"in this project\" : \"on this page\"}</span>` +\n `<span class=\"mrestore\" aria-hidden=\"true\">▸</span>`;\n for (const t of this.tabList) d.classList.toggle(`tab-${t.id}`, this.tab === t.id);\n for (const [id, view] of this.viewEls) view.classList.toggle(\"on\", id === this.tab);\n this.renderConsent();\n this.renderHome();\n d.querySelectorAll<HTMLElement>(\".tabs .tab\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.tab === this.tab));\n this.posMenu.querySelectorAll<HTMLElement>(\"[data-pos]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.pos === this.dockMode));\n this.renderSettings();\n this.renderHints();\n\n if (this.dockMode === \"float\") {\n const vw = window.innerWidth, vh = window.innerHeight;\n let { x, y, w, h } = this.floatRect;\n w = clampPx(w, 280, Math.min(760, vw - 24));\n h = clampPx(h, 220, vh - 24);\n if (x <= 0 && y <= 0) { x = Math.max(12, vw - w - 24); y = 64; } // first placement\n x = clampPx(x, 8, Math.max(8, vw - w - 8));\n y = clampPx(y, 8, Math.max(8, vh - h - 8));\n this.floatRect = { x, y, w, h };\n Object.assign(d.style, { left: x + \"px\", top: y + \"px\", width: w + \"px\", height: h + \"px\", right: \"auto\", bottom: \"auto\" });\n } else {\n for (const p of [\"left\", \"top\", \"right\", \"bottom\", \"width\", \"height\"] as const) d.style[p] = \"\";\n }\n\n d.querySelectorAll<HTMLElement>(\".dctl [data-dock]\").forEach((b) =>\n b.classList.toggle(\"on\", b.dataset.dock === this.dockMode));\n\n // FAB cluster: visible only while the panel is closed and the user has not hidden\n // it; placed where it was dragged, or on the dock's side by default.\n this.fabCluster.classList.toggle(\"show\", !this.open && !this.launcherHidden);\n // A touch screen has no Alt+Shift+L: while the launcher is hidden and the panel is\n // closed, a slim tab at the screen edge is the only way back, so it has to exist.\n this.fabHandle.classList.toggle(\"show\", !this.open && this.launcherHidden && isTouchDevice());\n this.applyFabPosition();\n this.applyFab();\n\n this.pushPage();\n }\n\n /**\n * Push the host page over so the docked panel never covers content (like real\n * DevTools). We shrink the <html> box with a margin on the docked edge — the\n * panel is `position: fixed` (relative to the viewport), so it sits in the\n * gutter the margin frees up. Float mode and the closed state reserve nothing.\n * Only inline styles are touched, so clearing them restores the host exactly.\n */\n private pushPage() {\n const de = document.documentElement;\n de.style.marginLeft = de.style.marginRight = de.style.marginBottom = \"\";\n // On mobile the panel is a bottom-sheet overlay (see styles) — reserving page\n // space would squeeze content to a sliver, so we never push there.\n if (!this.open || this.dockMode === \"float\" || this.isMobile()) return;\n const r = this.dock.getBoundingClientRect();\n if (this.dockMode === \"left\") de.style.marginLeft = r.width + \"px\";\n else if (this.dockMode === \"right\") de.style.marginRight = r.width + \"px\";\n else if (this.dockMode === \"bottom\") de.style.marginBottom = r.height + \"px\";\n }\n\n // ---- float-mode drag + resize ---------------------------------------------\n\n private onHeadPointerDown = (e: PointerEvent) => {\n if (this.dockMode !== \"float\" || e.button !== 0 || this.isMobile()) return;\n if ((e.target as HTMLElement)?.closest(\".dctl\")) return; // let control buttons work\n this.floatDrag = { px: e.clientX, py: e.clientY, ox: this.floatRect.x, oy: this.floatRect.y };\n this.dock.classList.add(\"dragging\");\n window.addEventListener(\"pointermove\", this.onHeadPointerMove);\n window.addEventListener(\"pointerup\", this.onHeadPointerUp);\n };\n private onHeadPointerMove = (e: PointerEvent) => {\n if (!this.floatDrag) return;\n e.preventDefault();\n this.floatRect.x = this.floatDrag.ox + (e.clientX - this.floatDrag.px);\n this.floatRect.y = this.floatDrag.oy + (e.clientY - this.floatDrag.py);\n this.applyDockLayout();\n };\n private onHeadPointerUp = () => {\n if (!this.floatDrag) return;\n this.floatDrag = null;\n this.dock.classList.remove(\"dragging\");\n window.removeEventListener(\"pointermove\", this.onHeadPointerMove);\n window.removeEventListener(\"pointerup\", this.onHeadPointerUp);\n this.saveState();\n };\n\n private onResizeDown = (e: PointerEvent) => {\n if (this.dockMode !== \"float\") return;\n e.preventDefault(); e.stopPropagation();\n this.floatResize = { px: e.clientX, py: e.clientY, ow: this.floatRect.w, oh: this.floatRect.h };\n window.addEventListener(\"pointermove\", this.onResizeMove);\n window.addEventListener(\"pointerup\", this.onResizeUp);\n };\n private onResizeMove = (e: PointerEvent) => {\n if (!this.floatResize) return;\n e.preventDefault();\n this.floatRect.w = this.floatResize.ow + (e.clientX - this.floatResize.px);\n this.floatRect.h = this.floatResize.oh + (e.clientY - this.floatResize.py);\n this.applyDockLayout();\n };\n private onResizeUp = () => {\n if (!this.floatResize) return;\n this.floatResize = null;\n window.removeEventListener(\"pointermove\", this.onResizeMove);\n window.removeEventListener(\"pointerup\", this.onResizeUp);\n this.saveState();\n };\n\n // ---- comment list ---------------------------------------------------------\n\n private renderList() {\n this.listEl.innerHTML = \"\";\n const q = this.search.trim().toLowerCase();\n const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;\n\n let items = this.visibleComments.filter((c) => {\n const stage = normalizeStatus(c.status);\n if (this.statFilter === \"open\" && stage === \"resolved\") return false;\n if (this.statFilter === \"needs_you\" && !needsYou({ status: c.status }).needs) return false;\n if (this.statFilter === \"resolved\" && stage !== \"resolved\") return false;\n if (this.statFilter === \"stale\" && (stage === \"resolved\" || !(Date.parse(c.createdAt) < weekAgo))) return false;\n if (this.statusFilter && stage !== this.statusFilter) return false;\n return !q || `${c.title ?? \"\"} ${c.body} ${c.author?.name ?? \"\"}`.toLowerCase().includes(q);\n });\n\n // By default the project scope is a timeline, newest first, and the page scope\n // keeps file order, which follows the pins down the page. Either can be overridden.\n const order = this.sortOrder || (this.scope === \"all\" ? \"newest\" : \"page\");\n if (this.sortSel) this.sortSel.value = order;\n if (this.statusSel) this.statusSel.value = this.statusFilter;\n if (order === \"newest\") items = [...items].sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n if (order === \"oldest\") items = [...items].sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n // A date order reads as a timeline, so it is grouped by day; page order is not.\n const grouped = order !== \"page\";\n const perDay = new Map<string, number>();\n if (grouped) for (const c of items) perDay.set(dayLabel(c.createdAt), (perDay.get(dayLabel(c.createdAt)) ?? 0) + 1);\n\n this.renderReviewBar();\n\n if (!items.length) {\n this.listEl.appendChild(el(\"div\", \"empty\",\n this.statFilter\n ? \"Nothing in this bucket.\"\n : this.statusFilter\n ? `Nothing in ${STAGE_LABELS[this.statusFilter as keyof typeof STAGE_LABELS]}.`\n : q\n ? \"No comments match your search.\"\n : this.scope === \"all\"\n ? \"No feedback in this project yet.\"\n : \"No comments yet. Use Inspect to pick an element, or Note to drop a comment anywhere on the page.\"));\n }\n\n let lastDay = \"\";\n items.forEach((c, i) => {\n if (grouped) {\n const day = dayLabel(c.createdAt);\n const shut = this.collapsedDays.has(day);\n if (day !== lastDay) {\n // The caret and the count are drawn by CSS, so the header's text is the day.\n const head = el(\"button\", \"daylabel\" + (shut ? \" shut\" : \"\"), day);\n head.dataset.n = String(perDay.get(day) ?? 0);\n head.setAttribute(\"aria-expanded\", String(!shut));\n head.onclick = () => {\n if (shut) this.collapsedDays.delete(day);\n else this.collapsedDays.add(day);\n this.renderList();\n };\n this.listEl.appendChild(head);\n lastDay = day;\n }\n if (shut) return;\n }\n this.listEl.appendChild(this.itemView(c, i));\n });\n this.updateCount(items.length);\n }\n\n private itemView(c: Comment, i: number): HTMLElement {\n const detached = this.pins.get(c.id)?.classList.contains(\"detached\") && !isResolved(c);\n const open = this.expanded.has(c.id);\n const item = el(\"div\", \"item\" + (open ? \"\" : \" collapsed\"));\n const top = el(\"div\", \"top\");\n const num = el(\"span\", \"num\" + (isResolved(c) ? \" done\" : detached ? \" detached\" : \"\"), String(i + 1));\n top.append(num);\n if (c.recording) top.appendChild(el(\"span\", \"rectag\", \"⏺ recording\"));\n const vw = c.viewport?.w;\n if (vw) {\n const kind = vw < 768 ? \"mobile\" : vw < 1024 ? \"tablet\" : \"desktop\";\n const icon = vw < 768 ? \"📱\" : vw < 1024 ? \"▦\" : \"🖥\";\n top.appendChild(el(\"span\", \"device\", `${icon} ${kind}`));\n }\n if (c.source) {\n const from = el(\"span\", \"srcchip\", `from ${c.source.projectName || c.source.projectId}`);\n from.title = c.source.reporter\n ? `Sent by ${c.source.reporter.name || c.source.reporter.email}`\n : \"Sent from another project\";\n top.appendChild(from);\n }\n const fwd = c.forwarded;\n if (fwd && fwd.status !== \"none\") {\n const where = fwd.destinationName || (fwd.status === \"ok\" ? \"webhook\" : \"Hub\");\n const ok = fwd.status === \"ok\";\n const remote = ok ? fwd.remote : undefined;\n if (remote) {\n // The receiver reported back: show where the ticket is over there.\n const said = remote.label || STAGE_LABELS[normalizeStatus(remote.status)];\n const text = [`→ ${where}`, remote.reference, said].filter(Boolean).join(\" · \");\n const link = remote.url && /^https?:\\/\\//i.test(remote.url) ? remote.url : null;\n const chip = el(link ? \"a\" : \"span\", `fwdchip st-${normalizeStatus(remote.status)}`, text);\n chip.title = `${where}: ${said}${remote.at ? ` — updated ${fmtAgo(remote.at)}` : \"\"}`;\n if (link) {\n (chip as HTMLAnchorElement).href = link;\n chip.setAttribute(\"target\", \"_blank\");\n chip.setAttribute(\"rel\", \"noreferrer\");\n chip.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n top.appendChild(chip);\n } else {\n const chip = el(\"span\", ok ? \"fwdchip\" : \"fwdchip bad\", ok ? `→ ${where}` : `→ ${where} failed`);\n chip.title = ok ? `Sent to ${where}` : `Could not send to ${where}${fwd.error ? `: ${fwd.error}` : \"\"}`;\n top.appendChild(chip);\n }\n }\n if (isResolved(c)) top.appendChild(el(\"span\", \"badge done\", \"resolved\"));\n else if (detached) {\n // Short label, full explanation on hover — the long form ate a third of the\n // row on its own and pushed the lifecycle chips past the card edge.\n const b = el(\"span\", \"badge detached\", \"moved\");\n b.title = \"element moved or removed\";\n top.appendChild(b);\n }\n\n // Where this thread's change has got to: sent to an agent, in a PR, or waiting\n // on a review. A thread with nothing attached stays unbadged.\n const lc = lifecycle(c);\n if (lc) {\n // A resolved thread already wears the \"resolved\" badge, so a second green pill\n // saying \"Reviewed\" is noise. Its PR chip and checks meter are still worth\n // showing — that is the part you cannot read off the badge.\n if (lc.stage !== \"reviewed\") top.appendChild(el(\"span\", `lifechip st-${lc.stage}`, lc.label));\n if (lc.pr) {\n const pr = el(lc.pr.url ? \"a\" : \"span\", `prchip${lc.pr.state ? ` st-${lc.pr.state}` : \"\"}`, `#${lc.pr.number}`);\n pr.title = `Pull request #${lc.pr.number}${lc.pr.state ? ` — ${lc.pr.state}` : \"\"}`;\n if (lc.pr.url) {\n (pr as HTMLAnchorElement).href = lc.pr.url;\n pr.setAttribute(\"target\", \"_blank\");\n pr.setAttribute(\"rel\", \"noreferrer\");\n pr.addEventListener(\"click\", (e) => e.stopPropagation());\n }\n top.appendChild(pr);\n }\n if (lc.checks) {\n const meter = el(\"span\", \"checks\");\n meter.title = `Checks — ${lc.checks.text} passed`;\n meter.innerHTML =\n `<span class=\"checks-n\">${escapeHtml(lc.checks.text)}</span>` +\n `<span class=\"checks-bar\"><i style=\"width:${Math.round(lc.checks.ratio * 100)}%\"></i></span>`;\n top.appendChild(meter);\n }\n // Only when a URL is actually known — a preview is never guessed, so there is\n // no \"deploying…\" state to sit in limbo here.\n if (lc.pr?.previewUrl) {\n const preview = el(\"a\", \"previewchip\", \"Preview\") as HTMLAnchorElement;\n preview.href = lc.pr.previewUrl;\n preview.target = \"_blank\";\n preview.rel = \"noreferrer\";\n preview.title = `Preview live at ${lc.pr.previewUrl}`;\n preview.addEventListener(\"click\", (e) => e.stopPropagation());\n top.appendChild(preview);\n }\n }\n\n // A revision says which thread it revises — the conversation carried over, and a\n // reviewer needs to know that rather than seeing an unconnected duplicate.\n const iteration = iterationLabel(c);\n if (iteration) {\n const chip = el(\"span\", \"iterchip\", iteration);\n chip.title = `Revision of thread #${c.parentThreadId}`;\n top.appendChild(chip);\n }\n\n // Page paths only mean something once the list spans more than one page.\n if (this.showPaths && this.scope === \"all\" && c.url) {\n top.appendChild(el(\"span\", \"pathtag\", shortPath(c.url)));\n }\n top.appendChild(el(\"span\", \"caret\", open ? \"▾\" : \"▸\"));\n item.appendChild(top);\n\n // Collapsed, the item is a single summary line; expanding reveals the detail.\n const summary = c.title || (c.body.split(\"\\n\")[0] ?? \"\").slice(0, 140) || \"(no description)\";\n item.appendChild(el(\"div\", \"summary\", summary));\n\n // Who raised it and when, in the configured time zone — shown collapsed too, so a\n // reporter can find their own thread in the list without opening every card.\n // (This used to be withheld from the widget; teams asked for it back.)\n const who = el(\"div\", \"who\");\n const when = this.fmtWhen(c.createdAt);\n who.innerHTML =\n `<b>${escapeHtml(c.author?.name?.trim() || \"Unknown\")}</b>` +\n (when ? ` · <time datetime=\"${escapeAttr(c.createdAt)}\" title=\"${escapeAttr(fmtAgo(c.createdAt))}\">${escapeHtml(when)}</time>` : \"\");\n item.appendChild(who);\n\n const detail = el(\"div\", \"detail\");\n // With the messages loaded, the predicate can see the two reasons the stage cannot\n // express: an agent's unanswered question, and a failed run. A routine review\n // needs no line — it has the banner below.\n const repliesForState = this.messages.get(c.id) ?? [];\n const lastMsg = repliesForState.length ? repliesForState[repliesForState.length - 1] : undefined;\n const attention = needsYou({\n status: c.status,\n last: lastMsg ? { fromAgent: lastMsg.author.type === \"agent\", body: lastMsg.body } : null,\n agentFailed: this.msgFailed.has(lastMsg?.id ?? \"\"),\n });\n if (c.status !== \"resolved\" && attention.needs && attention.reason !== \"review\") {\n const line = el(\"div\", \"needsline\");\n line.append(el(\"span\", \"needs-dot\"), el(\"span\", \"\", attention.label ?? \"Needs you\"));\n detail.appendChild(line);\n }\n // A thread in review leads with its banner: this is the one place a human is\n // being asked to decide something, so it goes above everything else.\n if (c.status === \"in_review\") detail.appendChild(this.reviewBanner(c));\n // Claude's proposed change, with the original request beside it on demand.\n if (c.proposal) detail.appendChild(this.proposalView(c));\n // With a title, the body is the full description; without one the first line is\n // already the summary, so only multi-line bodies repeat it here.\n if (c.title || c.body.includes(\"\\n\")) detail.appendChild(el(\"div\", \"body\", c.body));\n detail.appendChild(el(\"div\", \"meta\", describeAnchor(c)));\n\n if (c.recording) {\n const v = el(\"video\", \"shot\") as HTMLVideoElement;\n v.src = c.recording;\n v.controls = true;\n v.playsInline = true;\n if (c.screenshot) v.poster = c.screenshot;\n detail.appendChild(v);\n } else if (c.screenshot) {\n const img = el(\"img\", \"shot\") as HTMLImageElement;\n img.src = c.screenshot;\n detail.appendChild(img);\n }\n\n // Files the reporter attached (images and videos).\n for (const a of c.attachments ?? []) {\n if (a.kind === \"video\") {\n const v = el(\"video\", \"shot\") as HTMLVideoElement;\n v.src = a.url;\n v.controls = true;\n v.playsInline = true;\n detail.appendChild(v);\n } else {\n const img = el(\"img\", \"shot\") as HTMLImageElement;\n img.src = a.url;\n img.alt = a.name ?? \"attachment\";\n detail.appendChild(img);\n }\n }\n\n const actions = el(\"div\", \"actions\");\n const doneBtn = el(\"button\", \"\", isResolved(c) ? \"Reopen\" : \"Resolve\") as HTMLButtonElement;\n doneBtn.onclick = (e) => { e.stopPropagation(); void this.toggleResolved(c); };\n const del = el(\"button\", \"\", \"Delete\") as HTMLButtonElement;\n del.onclick = (e) => { e.stopPropagation(); void this.deleteComment(c); };\n actions.append(doneBtn, del);\n detail.appendChild(actions);\n // The conversation: replies, a reply box, the timeline and the copy actions.\n detail.appendChild(this.conversationView(c));\n // Generating a change for this thread, and its iteration history.\n detail.appendChild(this.generateView(c));\n item.appendChild(detail);\n\n item.onclick = () => {\n if (open) this.expanded.delete(c.id);\n else {\n this.expanded.add(c.id);\n // Replies are fetched the first time a card is opened, not for the whole list.\n void this.loadMessages(c);\n }\n this.renderList();\n };\n return item;\n }\n\n /**\n * Resolve or reopen a comment. Shared by the card and the Home feed. The page list\n * and the project list are separate reads, so the change is applied to both.\n */\n private async toggleResolved(c: Comment) {\n const status = isResolved(c) ? \"queue\" : \"resolved\";\n await this.store.update(c.id, { status });\n for (const x of [c, ...this.comments, ...this.allComments]) if (x.id === c.id) x.status = status;\n this.renderPins(); this.renderList(); this.renderHome();\n this.addActivity({\n kind: status === \"resolved\" ? \"comment.resolve\" : \"comment.reopen\",\n label: `${status === \"resolved\" ? \"Resolved\" : \"Reopened\"} “${c.title || c.body.split(\"\\n\")[0] || \"comment\"}”`,\n });\n }\n\n /** Delete a comment, from the card or the Home feed. */\n private async deleteComment(c: Comment) {\n await this.store.remove(c.id);\n this.comments = this.comments.filter((x) => x.id !== c.id);\n this.allComments = this.allComments.filter((x) => x.id !== c.id);\n this.resolved.delete(c.id);\n this.renderPins(); this.renderList(); this.renderHome();\n this.addActivity({\n kind: \"comment.delete\",\n label: `Deleted “${c.title || c.body.split(\"\\n\")[0] || \"comment\"}”`,\n level: \"warn\",\n });\n }\n\n /**\n * The review banner. This is the one place the panel asks a human to decide\n * something, so it sits above everything else in the detail.\n *\n * Approving resolves the thread. That asymmetry is the rule the whole flow rests\n * on: an agent moves work to In Review, only a person closes it.\n */\n private reviewBanner(c: Comment): HTMLElement {\n const label = c.title || c.body.split(\"\\n\")[0] || \"this thread\";\n const banner = el(\"div\", \"revbanner\");\n banner.innerHTML = `<span class=\"rev-dot\"></span><span class=\"rev-t\">Waiting on your review</span><span class=\"rev-spacer\"></span>`;\n\n const approve = el(\"button\", \"rev-approve\", \"Approve\") as HTMLButtonElement;\n approve.onclick = async (e) => {\n e.stopPropagation();\n approve.disabled = true;\n approve.textContent = \"Approving…\";\n await this.store.update(c.id, { status: \"resolved\" });\n c.status = \"resolved\";\n this.renderPins();\n this.renderList();\n this.renderHome();\n this.addActivity({ kind: \"review.approve\", label: `Approved “${label}”` });\n };\n\n const discuss = el(\"button\", \"rev-comment\", \"Add comment\") as HTMLButtonElement;\n discuss.onclick = (e) => {\n e.stopPropagation();\n // Comment on the same element when it is still on the page; otherwise drop a\n // page-level note rather than refusing the action.\n const target = this.resolved.get(c.id);\n if (target && target.isConnected) {\n const r = target.getBoundingClientRect();\n this.openComposer({ kind: \"element\", element: target }, r.left + r.width / 2, r.top + r.height);\n } else {\n this.setMode(\"free\");\n }\n };\n\n banner.append(approve, discuss);\n\n // The origin toggle only means something once there is a change to compare to.\n if (c.proposal) {\n const origin = el(\"button\", \"rev-origin\", \"Show original\") as HTMLButtonElement;\n origin.onclick = (e) => {\n e.stopPropagation();\n const view = banner.parentElement?.querySelector(\".origin\") as HTMLElement | null;\n if (!view) return;\n const shown = view.classList.toggle(\"show\");\n view.style.display = shown ? \"\" : \"none\";\n origin.textContent = shown ? \"Hide original\" : \"Show original\";\n };\n banner.appendChild(origin);\n }\n return banner;\n }\n\n /**\n * The original request beside Claude's proposed change. Hidden until the review\n * banner's toggle asks for it — a reviewer who does not care should not pay for\n * the markup.\n */\n private proposalView(c: Comment): HTMLElement {\n const p = c.proposal!;\n const wrap = el(\"div\", \"origin\");\n wrap.style.display = \"none\";\n wrap.innerHTML =\n `<div class=\"or-col\"><div class=\"or-h\">Original request</div>` +\n `<div class=\"or-b\">${escapeHtml(c.title ? `${c.title}\\n\\n${c.body}` : c.body)}</div>` +\n (c.context?.html ? `<pre class=\"or-code\">${escapeHtml(c.context.html)}</pre>` : \"\") +\n `</div>` +\n `<div class=\"or-col\"><div class=\"or-h\">Proposed change${p.author ? ` · ${escapeHtml(p.author)}` : \"\"}</div>` +\n (p.notes ? `<div class=\"or-b\">${escapeHtml(p.notes)}</div>` : \"\") +\n (p.html ? `<pre class=\"or-code\">${escapeHtml(p.html)}</pre>` : \"\") +\n (p.css ? `<pre class=\"or-code\">${escapeHtml(p.css)}</pre>` : \"\") +\n `</div>`;\n return wrap;\n }\n\n /** The strips above the list: how many threads are waiting on a human. */\n private renderReviewBar() {\n if (!this.reviewBar) return;\n const waiting = awaitingReview(this.visibleComments);\n if (!waiting.length) {\n this.reviewBar.innerHTML = \"\";\n this.reviewBar.style.display = \"none\";\n return;\n }\n const on = this.statFilter === \"needs_you\";\n this.reviewBar.style.display = \"\";\n this.reviewBar.innerHTML =\n `<span class=\"rb-dot\"></span>` +\n `<span class=\"rb-t\"><b>${waiting.length}</b> waiting on your review</span>` +\n `<button class=\"rb-b\" data-role=\"rb-toggle\">${on ? \"Show all\" : \"Review\"}</button>`;\n (this.reviewBar.querySelector('[data-role=\"rb-toggle\"]') as HTMLElement).onclick = () => {\n this.statFilter = on ? \"\" : \"needs_you\";\n this.renderList();\n this.renderHome();\n };\n }\n\n // ---- generate + iterate ---------------------------------------------------\n\n /**\n * The generate pane for one thread: the preview plane, its opacity comparison\n * against the original capture, the iteration stack and the iterate input.\n *\n * The panel owns all of that; producing the markup is the host's `generate`\n * function. Without one there is nothing to preview, so the pane offers the\n * access gate instead of a dead button.\n */\n private generateView(c: Comment): HTMLElement {\n const wrap = el(\"div\", \"genwrap\");\n const state = this.iterations.get(c.id) ?? emptyIterations();\n const cur = currentIteration(state);\n const busy = this.genBusy.has(c.id);\n\n if (this.genOpen !== c.id) {\n const open = el(\"button\", \"gen-open\", cur ? \"✦ Change preview\" : \"✦ Generate a change\") as HTMLButtonElement;\n open.onclick = (e) => {\n e.stopPropagation();\n this.genOpen = c.id;\n this.renderList();\n };\n wrap.appendChild(open);\n return wrap;\n }\n\n if (!this.cfg.generate) {\n // The access gate. Ties to whatever the host does with the request — the Team\n // tab does not exist yet, so this is the seam it will land on.\n const gate = el(\"div\", \"gengate\");\n gate.innerHTML =\n `<div class=\"gate-t\">Generating needs access</div>` +\n `<div class=\"gate-b\">This project has no generator configured for you yet. ` +\n `Ask for access and an owner can switch it on.</div>`;\n const ask = el(\"button\", \"gate-ask\", \"Request access to generate\") as HTMLButtonElement;\n ask.onclick = async (e) => {\n e.stopPropagation();\n ask.disabled = true;\n ask.textContent = \"Request sent\";\n await this.cfg.onRequestAccess?.({\n capability: \"generate\", user: this.cfg.user, projectKey: this.cfg.projectKey,\n });\n this.addActivity({\n kind: \"access.request\", label: \"Requested access to generate\",\n detail: this.cfg.projectKey, level: \"warn\",\n });\n };\n gate.appendChild(ask);\n if (!this.cfg.onRequestAccess) {\n gate.appendChild(el(\"div\", \"gate-hint\", \"Pass onRequestAccess to init() to route this somewhere.\"));\n }\n wrap.appendChild(gate);\n wrap.appendChild(this.genClose(c));\n return wrap;\n }\n\n const head = el(\"div\", \"genhead\");\n head.innerHTML = `<span class=\"gen-t\">Generate</span>`;\n const nav = el(\"span\", \"gen-nav\");\n const prev = el(\"button\", \"gen-step\", \"‹\") as HTMLButtonElement;\n prev.disabled = !canMove(state, -1);\n prev.setAttribute(\"aria-label\", \"Previous iteration\");\n prev.onclick = (e) => { e.stopPropagation(); this.setIterations(c.id, moveIteration(state, -1)); };\n const label = el(\"span\", \"gen-n\", stackLabel(state));\n const next = el(\"button\", \"gen-step\", \"›\") as HTMLButtonElement;\n next.disabled = !canMove(state, 1);\n next.setAttribute(\"aria-label\", \"Next iteration\");\n next.onclick = (e) => { e.stopPropagation(); this.setIterations(c.id, moveIteration(state, 1)); };\n nav.append(prev, label, next);\n head.appendChild(nav);\n\n const undo = el(\"button\", \"gen-undo\", \"Undo\") as HTMLButtonElement;\n undo.disabled = !canUndo(state) || busy;\n undo.onclick = (e) => {\n e.stopPropagation();\n this.setIterations(c.id, undoIteration(state));\n this.addActivity({ kind: \"generate.undo\", label: \"Undid a generated change\" });\n };\n head.append(undo, this.genClose(c));\n wrap.appendChild(head);\n\n if (busy) {\n wrap.appendChild(el(\"div\", \"genbusy\", \"Generating…\"));\n } else if (cur) {\n // The preview plane. Sandboxed: generated markup must never reach the host page,\n // and `allow-scripts` is deliberately absent.\n const plane = el(\"div\", \"genplane\");\n if (c.screenshot) {\n const base = el(\"img\", \"genbase\") as HTMLImageElement;\n base.src = c.screenshot;\n base.alt = \"Original capture\";\n plane.appendChild(base);\n }\n const frame = el(\"iframe\", \"genframe\") as HTMLIFrameElement;\n frame.setAttribute(\"sandbox\", \"\");\n frame.setAttribute(\"title\", \"Generated change preview\");\n // A generated change is usually a *fragment*, so the plane needs a surface under\n // it or it reads as an empty dark box. White, like any other design preview.\n frame.srcdoc = `<!doctype html><meta charset=\"utf-8\"><style>html,body{margin:0;padding:10px;` +\n `background:#fff;font:13px -apple-system,system-ui,sans-serif;color:#111}${cur.css ?? \"\"}</style>${cur.html}`;\n frame.style.opacity = String(this.genOpacity);\n plane.appendChild(frame);\n wrap.appendChild(plane);\n\n const slider = el(\"div\", \"genslider\");\n slider.innerHTML = `<span class=\"gs-lab\">Compare</span>`;\n const range = el(\"input\", \"gs-range\") as HTMLInputElement;\n range.type = \"range\";\n range.min = \"0\";\n range.max = \"100\";\n range.value = String(Math.round(this.genOpacity * 100));\n range.setAttribute(\"aria-label\", \"Generated change opacity\");\n // No re-render on input: only the plane's opacity changes, so the slider keeps\n // its grip while dragging.\n range.oninput = () => {\n this.genOpacity = Number(range.value) / 100;\n frame.style.opacity = String(this.genOpacity);\n };\n slider.append(range, el(\"span\", \"gs-n\", `${Math.round(this.genOpacity * 100)}%`));\n wrap.appendChild(slider);\n\n if (cur.notes) wrap.appendChild(el(\"div\", \"gennotes\", cur.notes));\n } else {\n wrap.appendChild(el(\"div\", \"genempty\", \"Nothing generated yet.\"));\n }\n\n // The iterate input. Sending is the only thing that re-renders, so typing is safe.\n const iter = el(\"div\", \"geniter\");\n const kind = document.createElement(\"select\");\n kind.className = \"mini\";\n kind.title = \"How to treat your follow-up\";\n kind.setAttribute(\"aria-label\", \"Iteration kind\");\n kind.append(\n optionEl(\"Refine\", \"refine\", true),\n optionEl(\"Revise\", \"revise\", false),\n );\n const input = el(\"input\", \"iter-in\") as HTMLInputElement;\n input.type = \"text\";\n input.placeholder = cur ? \"Refine it, e.g. “larger button”\" : \"What should change?\";\n input.value = this.iterDraft.get(c.id) ?? \"\";\n input.oninput = () => this.iterDraft.set(c.id, input.value);\n // Keep clicks inside the pane from toggling the card.\n for (const n of [kind, input]) n.addEventListener(\"click\", (e) => e.stopPropagation());\n const send = el(\"button\", \"iter-send\", \"Send\") as HTMLButtonElement;\n send.disabled = busy;\n send.onclick = (e) => {\n e.stopPropagation();\n const prompt = (this.iterDraft.get(c.id) ?? \"\").trim();\n if (!prompt) return;\n this.iterDraft.delete(c.id);\n void this.runGenerate(c, prompt, kind.value as \"refine\" | \"revise\");\n };\n input.onkeydown = (e) => { if (e.key === \"Enter\") send.click(); };\n iter.append(kind, input, send);\n wrap.appendChild(iter);\n return wrap;\n }\n\n private genClose(c: Comment): HTMLElement {\n const x = el(\"button\", \"gen-x\", \"✕\") as HTMLButtonElement;\n x.setAttribute(\"aria-label\", \"Close\");\n x.onclick = (e) => { e.stopPropagation(); this.genOpen = null; this.renderList(); };\n return x;\n }\n\n private setIterations(id: string, state: IterationState) {\n this.iterations.set(id, state);\n this.renderList();\n }\n\n /** Draft follow-ups, kept out of the render path so the input never loses focus. */\n private iterDraft = new Map<string, string>();\n\n /** Ask the host's generator for a change, and stack the result. */\n private async runGenerate(c: Comment, prompt: string, kind: \"generate\" | \"refine\" | \"revise\") {\n const generate = this.cfg.generate;\n if (!generate) return;\n const state = this.iterations.get(c.id) ?? emptyIterations();\n this.genBusy.add(c.id);\n this.genOpen = c.id;\n this.renderList();\n const started = Date.now();\n try {\n const out = await generate({\n comment: c,\n prompt,\n kind,\n previous: currentIteration(state) ?? undefined,\n localAi: this.project.localAi,\n });\n const next = addIteration(state, {\n id: `it${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n at: new Date().toISOString(),\n html: out.html,\n css: out.css,\n notes: out.notes,\n prompt,\n kind,\n });\n this.genBusy.delete(c.id);\n this.iterations.set(c.id, next);\n this.addActivity({\n kind: `generate.${kind}`,\n label: `${kind === \"generate\" ? \"Generated\" : \"Iterated on\"} “${c.title || prompt}”`,\n detail: `${Math.round((Date.now() - started) / 1000)}s · ${stackLabel(next)}`,\n });\n } catch (e) {\n this.genBusy.delete(c.id);\n this.addActivity({\n kind: \"generate.error\",\n label: `Generation failed: ${e instanceof Error ? e.message : String(e)}`,\n level: \"error\",\n });\n }\n this.renderList();\n }\n\n // ---- agent navigation (consent-gated) -------------------------------------\n\n /**\n * An agent asks to move the browser. Nothing navigates here — the request is\n * queued and the user answers it. `decide()` is the only thing that ever yields a\n * URL, and it yields one only on an explicit grant.\n */\n requestNavigation(url: string, opts: { reason?: string; requester?: string } = {}) {\n const next = requestNav(this.consent, { url, ...opts });\n if (next === this.consent) return; // not a navigable URL — refused outright\n this.consent = next;\n this.open = true;\n this.saveState();\n this.applyDockLayout();\n this.renderConsent();\n this.addActivity({\n kind: \"nav.request\",\n label: `Asked to open ${url}`,\n detail: opts.requester,\n level: \"warn\",\n });\n }\n\n /** Local-AI settings, used as the default in GenerateRequest.localAi. */\n setLocalAi(config: LocalAiConfig | null) {\n this.project = { ...this.project, localAi: config ?? undefined };\n this.saveProject();\n this.renderProject();\n }\n\n private setLocalAiStatus(text: string) {\n const box = this.homeEl?.querySelector(\"#loupe-pp-ai\") as HTMLElement | null;\n if (box) box.textContent = text;\n }\n\n /**\n * Ask the configured endpoint what it serves. A real check against the real\n * server — an OpenAI-compatible `/v1/models` is what Ollama, llama.cpp and the\n * rest all expose — with a timeout, so a wrong port reports rather than hangs.\n */\n private async testLocalAi(pop: HTMLElement) {\n const url = normalizeEnvUrl((pop.querySelector(\".pp-ai-url\") as HTMLInputElement).value);\n const model = (pop.querySelector(\".pp-ai-model\") as HTMLInputElement).value.trim();\n if (!url) {\n this.projError = \"Enter a full http:// or https:// endpoint URL.\";\n this.renderProjectError();\n return;\n }\n this.projError = \"\";\n this.setLocalAiStatus(\"Checking…\");\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), 4000);\n try {\n const res = await fetch(`${url}/v1/models`, { signal: ctl.signal });\n if (!res.ok) {\n this.setLocalAiStatus(`Reachable, but it answered ${res.status}.`);\n return;\n }\n const body: any = await res.json().catch(() => null);\n const ids: string[] = Array.isArray(body?.data)\n ? body.data.map((m: any) => String(m?.id ?? \"\")).filter(Boolean)\n : [];\n // If a model is named and the server lists models, say when it is not among them\n // — a typo'd model name is the most common way this silently does nothing.\n if (model && ids.length && !ids.some((i) => i === model || i.startsWith(`${model}:`))) {\n const shown = ids.slice(0, 4).join(\", \");\n this.setLocalAiStatus(`Connected, but no “${model}” — it serves: ${shown}${ids.length > 4 ? \", …\" : \"\"}`);\n return;\n }\n this.setLocalAiStatus(\n ids.length ? `Connected — ${ids.length} model${ids.length === 1 ? \"\" : \"s\"} available.` : \"Connected.\",\n );\n } catch (e) {\n this.setLocalAiStatus((e as Error)?.name === \"AbortError\"\n ? \"Timed out. Is the server running, and does it allow this origin (CORS)?\"\n : \"Could not reach it. Check the URL, and that the server allows this origin (CORS).\");\n } finally {\n clearTimeout(timer);\n }\n }\n\n private renderConsent() {\n if (!this.consentEl) return;\n if (!consentPending(this.consent)) {\n this.consentEl.innerHTML = \"\";\n this.consentEl.style.display = \"none\";\n return;\n }\n const r = this.consent.request!;\n this.consentEl.style.display = \"\";\n this.consentEl.innerHTML =\n `<div class=\"cs-head\"><span class=\"cs-dot\"></span>` +\n `<b>${escapeHtml(r.requester ?? \"An agent\")}</b> wants to open a page</div>` +\n `<div class=\"cs-url\">${escapeHtml(r.url)}</div>` +\n (r.reason ? `<div class=\"cs-why\">${escapeHtml(r.reason)}</div>` : \"\") +\n `<div class=\"cs-btns\"><button class=\"cs-deny\">Stay here</button><button class=\"cs-go\">Go there</button></div>`;\n\n (this.consentEl.querySelector(\".cs-deny\") as HTMLElement).onclick = () => {\n const { record } = decideConsent(this.consent, false);\n this.consent = record;\n this.renderConsent();\n this.addActivity({ kind: \"nav.deny\", label: `Declined opening ${r.url}` });\n };\n (this.consentEl.querySelector(\".cs-go\") as HTMLElement).onclick = () => {\n const { record, navigateTo } = decideConsent(this.consent, true);\n this.consent = record;\n this.renderConsent();\n this.addActivity({ kind: \"nav.grant\", label: `Opened ${navigateTo}` });\n // The only line in the SDK that navigates, and it cannot run without a grant.\n if (navigateTo) window.location.assign(navigateTo);\n };\n }\n\n /** Drop a pending request without deciding it — e.g. the panel is closing. */\n private abandonNavigation() {\n this.consent = withdrawConsent(this.consent);\n this.renderConsent();\n }\n\n /** The dictation button, or nothing at all where the browser has no speech API. */\n private voiceButton(target: HTMLTextAreaElement): HTMLElement {\n const Ctor = (window as any).SpeechRecognition ?? (window as any).webkitSpeechRecognition;\n const b = el(\"button\", \"voice\", \"\") as HTMLButtonElement;\n this.voiceEl = b;\n if (!Ctor) {\n // No API: say so rather than offering a button that cannot work.\n b.textContent = \"🎤\";\n b.disabled = true;\n b.title = \"Dictation is not available in this browser\";\n b.setAttribute(\"aria-label\", \"Dictation unavailable\");\n return b;\n }\n const idle = () => {\n b.classList.remove(\"on\");\n b.textContent = \"🎤\";\n b.setAttribute(\"aria-label\", \"Dictate\");\n b.title = \"Dictate\";\n };\n const listening = () => {\n b.classList.add(\"on\");\n b.textContent = \"⏺\";\n b.setAttribute(\"aria-label\", \"Stop dictating\");\n b.title = \"Listening — click to stop\";\n };\n idle();\n b.onclick = (e) => {\n e.stopPropagation();\n if (this.voice) { this.stopVoice(); idle(); return; }\n const rec = new Ctor();\n rec.continuous = true;\n rec.interimResults = true;\n rec.lang = document.documentElement.lang || \"en-US\";\n let base = target.value ? `${target.value} ` : \"\";\n rec.onresult = (ev: any) => {\n let text = \"\";\n for (let i = ev.resultIndex; i < ev.results.length; i++) text += ev.results[i][0].transcript;\n target.value = (base + text).replace(/\\s+/g, \" \").trimStart();\n target.dispatchEvent(new Event(\"input\", { bubbles: true }));\n };\n rec.onerror = (ev: any) => {\n this.stopVoice();\n idle();\n this.addActivity({ kind: \"voice.error\", label: `Dictation failed: ${ev?.error ?? \"unknown\"}`, level: \"error\" });\n };\n rec.onend = () => { this.voice = null; idle(); };\n this.voice = rec;\n this.voiceTarget = target;\n try {\n rec.start();\n listening();\n } catch {\n this.voice = null;\n idle();\n }\n };\n return b;\n }\n\n private voiceTarget: HTMLTextAreaElement | null = null;\n\n private stopVoice() {\n try { this.voice?.stop(); } catch { /* already stopped */ }\n this.voice = null;\n this.voiceTarget = null;\n }\n\n /** Replies per thread, loaded lazily when a card is expanded. */\n private messages = new Map<string, ThreadMessage[]>();\n /** Reply drafts, kept out of the render path so the textarea keeps focus. */\n private msgDrafts = new Map<string, string>();\n /** Optimistic replies awaiting the store. */\n private msgPending = new Set<string>();\n /** Optimistic replies the store rejected — offered for retry rather than lost. */\n private msgFailed = new Set<string>();\n private msgErr = new Map<string, string>();\n\n /**\n * The conversation: the replies, a reply box, the activity timeline and the copy\n * actions. Loaded lazily — a list of twenty cards should not fire twenty requests.\n */\n private conversationView(c: Comment): HTMLElement {\n const wrap = el(\"div\", \"convo\");\n const replies = this.messages.get(c.id);\n\n if (replies === undefined) {\n wrap.appendChild(el(\"div\", \"convo-loading\", \"Loading conversation…\"));\n return wrap;\n }\n\n const asRows = replies.map((m) => ({\n at: m.createdAt, authorName: m.author.name, body: m.body, fromAgent: m.author.type === \"agent\",\n }));\n const conversation = threadConversation(c, replies);\n\n const list = el(\"div\", \"msgs\");\n for (const m of conversation) {\n const fromAgent = m.author.type === \"agent\";\n const state = this.msgPending.has(m.id) ? \" pending\" : this.msgFailed.has(m.id) ? \" failed\" : \"\";\n const row = el(\"div\", \"msg\" + (fromAgent ? \" agent\" : \"\") + state);\n const initials = (m.author.name || \"?\").trim().slice(0, 1).toUpperCase();\n const head = el(\"div\", \"msg-head\");\n head.append(\n el(\"span\", \"msg-av\" + (fromAgent ? \" agent\" : \"\"), initials),\n el(\"b\", \"msg-name\", m.author.name),\n el(\"span\", \"msg-when\", fmtAgo(m.createdAt)),\n );\n (head.lastElementChild as HTMLElement).title = this.fmtWhen(m.createdAt);\n if (fromAgent) head.appendChild(el(\"span\", \"msg-tag\", \"agent\"));\n if (m.origin) head.appendChild(el(\"span\", \"msg-tag origin\", `from ${m.origin.projectName || m.origin.projectId}`));\n // The body is rendered as segments so a mentioned name is highlightable — and\n // so the highlight lands on the right occurrence rather than the first.\n const body = el(\"div\", \"msg-body\");\n for (const seg of mentionSegments(m.body, parseMentions(m.body))) {\n if (seg.mention) body.appendChild(el(\"span\", \"mention\", seg.text));\n else body.appendChild(document.createTextNode(seg.text));\n }\n row.append(head, body);\n\n // Reaction pills. The picker is a popup rather than an always-visible row of six\n // emoji, because a permanent picker under every message is visual noise for a\n // thing most people do occasionally.\n const pills = el(\"div\", \"rxns\");\n for (const r of summarizeReactions(this.reactionsOf(c.id, m.id), this.cfg.user.id)) {\n const pill = el(\"button\", \"rxn\" + (r.mine ? \" mine\" : \"\")) as HTMLButtonElement;\n pill.append(document.createTextNode(r.emoji), el(\"span\", \"rxn-n\", String(r.count)));\n pill.title = r.users.join(\", \");\n pill.onclick = (e) => { e.stopPropagation(); void this.react(c, m.id, r.emoji); };\n pills.appendChild(pill);\n }\n const add = el(\"button\", \"rxn-add\", \"+\") as HTMLButtonElement;\n add.title = \"Add a reaction\";\n add.onclick = (e) => {\n e.stopPropagation();\n const open = pills.querySelector(\".rxn-pick\");\n pills.querySelectorAll(\".rxn-pick\").forEach((n) => n.remove());\n if (open) return;\n const pick = el(\"div\", \"rxn-pick\");\n for (const emoji of REACTION_CHOICES) {\n const b = el(\"button\", \"rxn-opt\", emoji) as HTMLButtonElement;\n b.onclick = (ev) => { ev.stopPropagation(); void this.react(c, m.id, emoji); };\n pick.appendChild(b);\n }\n pills.appendChild(pick);\n };\n pills.appendChild(add);\n row.appendChild(pills);\n\n // A message's own attachments, inline. Images and video only — the accept list\n // already limits the picker, and anything else would have no way to render.\n if (m.attachments?.length) {\n const strip = el(\"div\", \"msg-atts\");\n for (const a of m.attachments) {\n if (a.kind === \"image\") {\n const img = el(\"img\", \"msg-att\") as HTMLImageElement;\n img.src = a.url;\n img.alt = a.name ?? \"attachment\";\n img.loading = \"lazy\";\n img.onclick = (e) => { e.stopPropagation(); window.open(a.url, \"_blank\", \"noopener\"); };\n strip.appendChild(img);\n } else if (a.kind === \"video\") {\n const video = el(\"video\", \"msg-att\") as HTMLVideoElement;\n video.src = a.url;\n video.controls = true;\n video.preload = \"metadata\";\n video.onclick = (e) => e.stopPropagation();\n strip.appendChild(video);\n }\n }\n if (strip.childElementCount) row.appendChild(strip);\n }\n\n if (this.msgPending.has(m.id)) row.appendChild(el(\"div\", \"msg-state\", \"Sending…\"));\n if (this.msgFailed.has(m.id)) {\n const failed = el(\"div\", \"msg-state failed\");\n failed.append(document.createTextNode(this.msgErr.get(m.id) ?? \"Could not send.\"));\n const retry = el(\"button\", \"msg-retry\", \"Retry\") as HTMLButtonElement;\n retry.onclick = (e) => { e.stopPropagation(); void this.resend(c, m.id); };\n failed.appendChild(retry);\n row.appendChild(failed);\n }\n list.appendChild(row);\n }\n wrap.appendChild(list);\n\n // ---- reply box ---------------------------------------------------------\n const reply = el(\"div\", \"reply\");\n const input = el(\"textarea\", \"reply-in\") as HTMLTextAreaElement;\n input.rows = 2;\n input.placeholder = \"Reply… use @ to mention\";\n input.value = this.msgDrafts.get(c.id) ?? \"\";\n // Typing must not re-render, or the caret jumps on every keystroke.\n input.oninput = () => this.msgDrafts.set(c.id, input.value);\n input.addEventListener(\"click\", (e) => e.stopPropagation());\n input.onkeydown = (e) => {\n // Enter sends; Shift+Enter is a newline. Attachments ride along.\n if (e.key === \"Enter\" && !e.shiftKey) { e.preventDefault(); void this.sendReply(c, input.value, [...pending]); }\n };\n const foot = el(\"div\", \"reply-foot\");\n const send = el(\"button\", \"reply-send\", \"➤ Send\") as HTMLButtonElement;\n send.setAttribute(\"aria-label\", \"Send reply\");\n send.onclick = (e) => { e.stopPropagation(); void this.sendReply(c, input.value, [...pending]); };\n // Attachments on a reply, through the same blob seam the comment form uses.\n const fileIn = el(\"input\") as HTMLInputElement;\n fileIn.type = \"file\";\n fileIn.multiple = true;\n fileIn.accept = \"image/*,video/*\";\n fileIn.style.display = \"none\";\n const attachBtn = el(\"button\", \"reply-attach\", \"📎\") as HTMLButtonElement;\n attachBtn.title = \"Attach an image or video\";\n attachBtn.setAttribute(\"aria-label\", \"Attach a file\");\n attachBtn.onclick = (e) => { e.stopPropagation(); fileIn.click(); };\n const pending: File[] = [];\n const chips = el(\"div\", \"reply-chips\");\n const repaintChips = () => {\n chips.textContent = \"\";\n pending.forEach((f, i) => {\n const chip = el(\"span\", \"chip\", `${attachmentKind(f.type) === \"video\" ? \"🎬\" : \"🖼\"} ${f.name}`);\n const x = el(\"button\", \"chip-x\", \"✕\") as HTMLButtonElement;\n x.title = \"Remove\";\n x.onclick = (ev) => { ev.stopPropagation(); pending.splice(i, 1); repaintChips(); };\n chip.appendChild(x);\n chips.appendChild(chip);\n });\n };\n fileIn.onchange = () => {\n for (const f of Array.from(fileIn.files ?? [])) {\n const cap = attachmentKind(f.type) === \"video\" ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES;\n if (f.size > cap) {\n this.addActivity({ kind: \"error\", level: \"error\", label: `${f.name} is too large to attach` });\n continue;\n }\n pending.push(f);\n }\n fileIn.value = \"\";\n repaintChips();\n };\n // Typing and the picker must not bubble into the card's own click handling.\n chips.addEventListener(\"click\", (e) => e.stopPropagation());\n foot.append(el(\"span\", \"reply-hint\", \"@ to mention\"), attachBtn, send);\n // Autocomplete: shown while a handle is being typed, hidden otherwise. The list is\n // replaced in place rather than re-rendering the card, so the caret never moves.\n const suggest = el(\"div\", \"mention-list\");\n suggest.style.display = \"none\";\n const refreshSuggestions = () => {\n const matches = mentionSuggestions(input.value, input.selectionStart ?? input.value.length, this.people.get(this.cfg.projectKey) ?? []);\n suggest.textContent = \"\";\n if (!matches.length) { suggest.style.display = \"none\"; return; }\n suggest.style.display = \"\";\n for (const person of matches) {\n const b = el(\"button\", \"mention-pick\", person.name) as HTMLButtonElement;\n b.onclick = (e) => {\n e.stopPropagation();\n const before = input.value.slice(0, input.selectionStart ?? input.value.length);\n const at = before.lastIndexOf(\"@\");\n const after = input.value.slice(input.selectionStart ?? input.value.length);\n // Insert the squashed name so it resolves against the same person later.\n input.value = `${before.slice(0, at)}@${person.name.replace(/\\s+/g, \"\")} ${after}`;\n this.msgDrafts.set(c.id, input.value);\n suggest.style.display = \"none\";\n input.focus();\n };\n suggest.appendChild(b);\n }\n };\n input.oninput = () => { this.msgDrafts.set(c.id, input.value); refreshSuggestions(); };\n input.onkeyup = () => refreshSuggestions();\n input.onblur = () => setTimeout(() => { suggest.style.display = \"none\"; }, 150);\n reply.append(input, suggest, chips, fileIn, foot);\n wrap.appendChild(reply);\n\n // ---- timeline ----------------------------------------------------------\n const timeline = threadTimeline(c, asRows);\n const tl = el(\"div\", \"tl\");\n tl.appendChild(el(\"div\", \"tl-h\", \"Activity\"));\n for (const entry of timeline) {\n const item = el(\"div\", `tl-i tl-${entry.kind}`);\n item.append(el(\"span\", \"tl-dot\"), el(\"span\", \"tl-l\", entry.label));\n if (entry.detail) item.appendChild(el(\"span\", \"tl-d\", entry.detail));\n tl.appendChild(item);\n }\n wrap.appendChild(tl);\n\n // ---- copy --------------------------------------------------------------\n const copyRow = el(\"div\", \"copyrow\");\n const copyTextBtn = el(\"button\", \"copy-b\", \"Copy thread text\") as HTMLButtonElement;\n copyTextBtn.onclick = (e) => {\n e.stopPropagation();\n const text = threadAsText(\n {\n id: c.id, body: c.body, title: c.title, url: c.url, status: c.status, createdAt: c.createdAt,\n kind: c.kind, anchor: { tag: c.anchor?.tag, selector: c.anchor?.cssPath },\n proposal: c.proposal, pr: c.pr,\n },\n asRows,\n );\n void this.copyText(copyTextBtn, text);\n };\n const copyImagesBtn = el(\"button\", \"copy-b\", \"Copy images\") as HTMLButtonElement;\n copyImagesBtn.onclick = (e) => { e.stopPropagation(); void this.copyImages(copyImagesBtn, c); };\n copyRow.append(copyTextBtn, copyImagesBtn);\n wrap.appendChild(copyRow);\n\n return wrap;\n }\n\n /** Other people on this page. Empty unless a bridge is configured. */\n private peers: Peer[] = [];\n private peerId?: string;\n private peerEl!: HTMLElement;\n private peerTimer?: ReturnType<typeof setInterval>;\n\n /**\n * Join, then keep talking.\n *\n * Presence is a heartbeat, not a flag, because a browser that is closed or crashes\n * sends no goodbye. The bridge expires anything silent past the TTL, and the panel\n * re-joins on a 404 rather than assuming it is still known.\n */\n private startPresence() {\n const bridge = this.cfg.bridge;\n if (!bridge) return;\n const base = bridge.replace(/\\/$/, \"\");\n const pageUrl = location.pathname + location.search;\n\n const tick = async () => {\n try {\n if (!this.peerId) {\n const res = await fetch(`${base}/presence`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ url: pageUrl, userId: this.cfg.user.id, name: this.cfg.user.name }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as { peer?: Peer };\n this.peerId = data.peer?.id;\n } else {\n const res = await fetch(`${base}/presence/${encodeURIComponent(this.peerId)}/heartbeat`, { method: \"POST\" });\n // The bridge forgot us (it restarted, or we were swept). Re-join rather than\n // beating forever against an id it does not know.\n if (res.status === 404) this.peerId = undefined;\n }\n const listed = await fetch(\n `${base}/presence?url=${encodeURIComponent(pageUrl)}&viewer=${encodeURIComponent(this.peerId ?? \"\")}`,\n );\n if (listed.ok) {\n const data = (await listed.json()) as { peers?: Peer[] };\n this.peers = Array.isArray(data.peers) ? data.peers : [];\n this.renderPeers();\n }\n } catch {\n // A bridge that went away is not an error worth surfacing; the list empties.\n this.peers = [];\n this.renderPeers();\n }\n };\n\n void tick();\n this.peerTimer = setInterval(() => void tick(), PEER_HEARTBEAT_MS);\n }\n\n private renderPeers() {\n if (!this.peerEl) return;\n this.peerEl.textContent = \"\";\n if (!this.peers.length) { this.peerEl.style.display = \"none\"; return; }\n this.peerEl.style.display = \"\";\n for (const p of this.peers.slice(0, 4)) {\n const av = el(\"span\", \"peer-av\", initialsOf(p.name));\n av.title = `${p.name} is on this page`;\n this.peerEl.appendChild(av);\n }\n if (this.peers.length > 4) this.peerEl.appendChild(el(\"span\", \"peer-more\", `+${this.peers.length - 4}`));\n }\n\n private stopPresence() {\n if (this.peerTimer) clearInterval(this.peerTimer);\n this.peerTimer = undefined;\n // Best-effort goodbye; the TTL covers us if this never lands.\n if (this.cfg.bridge && this.peerId) {\n const base = this.cfg.bridge.replace(/\\/$/, \"\");\n void fetch(`${base}/presence/${encodeURIComponent(this.peerId)}`, { method: \"DELETE\", keepalive: true }).catch(() => {});\n }\n this.peerId = undefined;\n this.peers = [];\n }\n\n private liveSource?: EventSource;\n\n /**\n * Follow the bridge's thread channel while the panel is open.\n *\n * The SSE channel lives in the MCP process, so a reply posted by anyone — an agent, a\n * teammate's browser — arrives here rather than being discovered by the 4 s list\n * poll. Only the threads whose messages are already loaded are refetched: pulling a\n * conversation nobody has open would be work for nothing.\n */\n private startLiveThreads() {\n const bridge = this.cfg.bridge;\n if (!bridge || this.liveSource) return;\n // Absent in some test environments; the poll still covers us if it is.\n if (typeof EventSource === \"undefined\") return;\n try {\n const source = new EventSource(`${bridge.replace(/\\/$/, \"\")}/thread-updates`);\n // Named event: the bridge writes `event: thread`, so `onmessage` never fires.\n source.addEventListener(\"thread\", (ev) => {\n let parsed: any;\n try { parsed = JSON.parse((ev as MessageEvent).data); } catch { return; }\n if (!parsed || typeof parsed.threadId !== \"string\") return;\n if (!this.messages.has(parsed.threadId)) return;\n void this.refreshMessages(parsed.threadId);\n });\n // The browser reconnects on its own; a dead bridge is not worth surfacing.\n source.onerror = () => {};\n this.liveSource = source;\n } catch {\n // EventSource construction can throw on a malformed URL — never fatal.\n }\n }\n\n /** Re-read one thread's replies, replacing the cache. */\n private async refreshMessages(threadId: string) {\n try {\n const list = await this.store.listMessages(threadId);\n if (!Array.isArray(list)) return;\n this.messages.set(threadId, list);\n this.renderList();\n } catch {\n // Leave what is on screen; the next poll or event will try again.\n }\n }\n\n /** Reactions per thread, keyed `${threadId}:${messageId}`, so a re-render is free. */\n private reactions = new Map<string, Reaction[]>();\n\n private reactionsOf(threadId: string, messageId: string): Reaction[] {\n return this.reactions.get(`${threadId}:${messageId}`) ?? [];\n }\n\n /**\n * Toggle a reaction.\n *\n * Optimistic, then replaced by the server's own set: the server returns the whole\n * list precisely so the count can never drift from what was stored.\n */\n private async react(c: Comment, messageId: string, emoji: string) {\n const key = `${c.id}:${messageId}`;\n const before = this.reactionsOf(c.id, messageId);\n this.reactions.set(key, toggleReaction(before, {\n messageId, emoji, userId: this.cfg.user.id, userName: this.cfg.user.name,\n }));\n this.renderList();\n try {\n const next = await this.store.toggleReaction({\n threadId: c.id, messageId, emoji, userId: this.cfg.user.id, userName: this.cfg.user.name,\n });\n this.reactions.set(key, Array.isArray(next) ? next : this.reactionsOf(c.id, messageId));\n } catch {\n // Put it back rather than showing a reaction that did not save.\n this.reactions.set(key, before);\n }\n this.renderList();\n }\n\n /** Everyone who has taken part, for mention autocomplete. Fetched once. */\n private people = new Map<string, { id: string; name: string; email?: string }[]>();\n\n private async loadPeople() {\n if (this.people.has(this.cfg.projectKey)) return;\n try {\n this.people.set(this.cfg.projectKey, await this.store.listPeople(this.cfg.projectKey));\n } catch {\n this.people.set(this.cfg.projectKey, []);\n }\n }\n\n /** Fetch replies once, when a card is first expanded. */\n private async loadMessages(c: Comment) {\n if (this.messages.has(c.id)) return;\n // A mention needs the people list; fetch it alongside the first thread opened.\n void this.loadPeople();\n // Reactions are secondary — a failure to load them must not cost us the thread.\n void this.store.listReactions(c.id).then((all) => {\n if (!Array.isArray(all)) return;\n for (const r of all) {\n const key = `${c.id}:${r.messageId}`;\n const list = this.reactions.get(key) ?? [];\n if (!list.some((x) => x.userId === r.userId && x.emoji === r.emoji)) list.push(r);\n this.reactions.set(key, list);\n }\n this.renderList();\n }).catch(() => {});\n try {\n this.messages.set(c.id, await this.store.listMessages(c.id));\n } catch {\n this.messages.set(c.id, []);\n }\n this.renderList();\n }\n\n /**\n * Post a reply, optimistically.\n *\n * The row appears immediately; if the store rejects it the row stays with a Retry,\n * because losing what someone typed is worse than showing a failed row.\n */\n private async sendReply(c: Comment, raw: string, files: File[] = []) {\n const body = raw.trim();\n // A reply with only an attachment is still a reply; one with neither is not.\n if (!body && !files.length) return;\n const author: ThreadAuthor = {\n id: this.cfg.user.id, name: this.cfg.user.name, email: this.cfg.user.email, type: \"user\",\n };\n // Uploaded before the optimistic row renders, so the row shows the real URLs and\n // never has to be patched once the blobs land.\n const attachments = files.length ? await this.uploadAttachments(files) : undefined;\n const optimistic: ThreadMessage = {\n id: `pending-${Date.now().toString(36)}`, threadId: c.id, author, body,\n attachments, createdAt: new Date().toISOString(),\n };\n this.messages.set(c.id, [...(this.messages.get(c.id) ?? []), optimistic]);\n this.msgPending.add(optimistic.id);\n this.msgDrafts.delete(c.id);\n this.renderList();\n\n try {\n const saved = await this.store.addMessage(c.id, { author, body, attachments });\n this.messages.set(c.id, (this.messages.get(c.id) ?? []).map((m) => (m.id === optimistic.id ? saved : m)));\n this.msgPending.delete(optimistic.id);\n this.addActivity({ kind: \"message.create\", label: `Replied on “${c.title || body.slice(0, 40)}”` });\n } catch (e) {\n this.msgPending.delete(optimistic.id);\n this.msgFailed.add(optimistic.id);\n this.msgErr.set(optimistic.id, e instanceof Error ? e.message : \"Could not send.\");\n }\n this.renderList();\n }\n\n /** Try a failed optimistic reply again, in place. */\n private async resend(c: Comment, id: string) {\n const found = (this.messages.get(c.id) ?? []).find((m) => m.id === id);\n if (!found) return;\n this.msgFailed.delete(id);\n this.msgErr.delete(id);\n this.msgPending.add(id);\n this.renderList();\n try {\n const saved = await this.store.addMessage(c.id, { author: found.author, body: found.body });\n this.messages.set(c.id, (this.messages.get(c.id) ?? []).map((m) => (m.id === id ? saved : m)));\n this.msgPending.delete(id);\n } catch (e) {\n this.msgPending.delete(id);\n this.msgFailed.add(id);\n this.msgErr.set(id, e instanceof Error ? e.message : \"Could not send.\");\n }\n this.renderList();\n }\n\n /** Copy text, and say so — silence looks like a no-op. */\n private async copyText(button: HTMLButtonElement, text: string) {\n const original = button.textContent;\n try {\n if (!navigator.clipboard?.writeText) throw new Error(\"clipboard unavailable\");\n await navigator.clipboard.writeText(text);\n button.textContent = \"Copied ✓\";\n } catch {\n button.textContent = \"Copy failed\";\n }\n setTimeout(() => { button.textContent = original; }, 1500);\n }\n\n /**\n * Copy the captured images. Best-effort and reported as such: an image clipboard\n * write needs a secure context and a user gesture, and a silent failure would look\n * like it worked.\n */\n private async copyImages(button: HTMLButtonElement, c: Comment) {\n const original = button.textContent;\n const sources = [c.screenshot, ...(c.attachments ?? []).filter((a) => a.kind === \"image\").map((a) => a.url)]\n .filter((s): s is string => !!s);\n if (!sources.length) {\n button.textContent = \"No images\";\n setTimeout(() => { button.textContent = original; }, 1500);\n return;\n }\n try {\n const blobs = await Promise.all(sources.slice(0, 4).map(async (src) => (await fetch(src)).blob()));\n const items: Record<string, Blob> = {};\n blobs.forEach((blob, i) => { items[i === 0 ? \"image/png\" : `image/png-${i}`] = blob; });\n await (navigator.clipboard as any).write([new (window as any).ClipboardItem(items)]);\n button.textContent = \"Copied ✓\";\n } catch {\n button.textContent = \"Copy failed\";\n }\n setTimeout(() => { button.textContent = original; }, 1500);\n }\n\n private flash(id: string) {\n const c = this.comments.find((x) => x.id === id);\n const pin = this.pins.get(id);\n\n if (c?.kind === \"free\") {\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin?.classList.add(\"active\");\n const docW = Math.max(1, document.documentElement.scrollWidth);\n const docH = Math.max(1, document.documentElement.scrollHeight);\n window.scrollTo({\n top: Math.max(0, c.offset.y * docH - window.innerHeight / 2),\n left: Math.max(0, c.offset.x * docW - window.innerWidth / 2),\n behavior: \"smooth\",\n });\n this.position();\n return;\n }\n\n if (c?.kind === \"region\" && c.region) {\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin?.classList.add(\"active\");\n // Show the outline, keep it tracking scroll, then fade it out.\n this.activeRegionId = id;\n window.clearTimeout(this.regionTimer);\n this.regionTimer = window.setTimeout(() => {\n this.activeRegionId = null;\n this.regionBox.style.display = \"none\";\n }, 2400);\n // Scroll to the anchor element when we have it (correct across reflow),\n // otherwise to the stored document position.\n const elx = this.resolved.get(id);\n if (elx) elx.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n else window.scrollTo({ top: Math.max(0, c.region.y - 120), left: Math.max(0, c.region.x - 120), behavior: \"smooth\" });\n this.position();\n return;\n }\n\n if (!pin || pin.classList.contains(\"detached\")) return;\n for (const p of this.pins.values()) p.classList.remove(\"active\");\n pin.classList.add(\"active\");\n const elx = this.resolved.get(id);\n if (elx) elx.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n }\n\n /** Absolute timestamp in the host's configured time zone and locale (see `LoupeConfig.timeZone`). */\n private fmtWhen(iso: string): string {\n return fmtAbsolute(iso, this.cfg.locale, this.cfg.timeZone);\n }\n\n /**\n * \" · package v0.11.0\", flagged, when the host's package version differs from this\n * bundle's. The two agree on a healthy install; they differ exactly when the\n * package was upgraded but its published JS was not — the trap this makes visible.\n */\n private packageVersionNote(): string {\n const pkg = (this.cfg.packageVersion ?? \"\").trim().replace(/^v/i, \"\");\n if (!pkg || pkg === SDK_VERSION) return \"\";\n const why = `This widget bundle is v${SDK_VERSION} but the installed package is v${pkg}. ` +\n `Re-publish the package assets so the served bundle matches.`;\n return ` · <span class=\"ver-stale\" title=\"${escapeAttr(why)}\">package v${escapeHtml(pkg)}</span>`;\n }\n\n destroy() {\n this.liveSource?.close();\n this.liveSource = undefined;\n this.companionSource?.close();\n this.companionSource = undefined;\n if (this.companionPoll) clearInterval(this.companionPoll);\n if (this.activityPoll) clearInterval(this.activityPoll);\n this.activityPoll = undefined;\n if (this.syncPoll) clearInterval(this.syncPoll);\n this.syncPoll = undefined;\n document.removeEventListener(\"visibilitychange\", this.onSyncVisible);\n this.stopVoice();\n this.stopPresence();\n this.stopRecording?.();\n this.setMode(\"off\");\n this.mo?.disconnect();\n if (this.tick) clearInterval(this.tick);\n window.clearTimeout(this.regionTimer);\n window.removeEventListener(\"resize\", this.onWinResize);\n window.removeEventListener(\"pointermove\", this.onHeadPointerMove);\n window.removeEventListener(\"pointerup\", this.onHeadPointerUp);\n window.removeEventListener(\"pointermove\", this.onResizeMove);\n window.removeEventListener(\"pointerup\", this.onResizeUp);\n window.removeEventListener(\"pointermove\", this.onFabPointerMove);\n window.removeEventListener(\"pointerup\", this.onFabPointerUp);\n window.removeEventListener(\"pointercancel\", this.onFabPointerUp);\n window.clearTimeout(this.toastTimer);\n document.removeEventListener(\"keydown\", this.onLauncherKey);\n document.removeEventListener(\"click\", this.onDocumentClick, true);\n document.removeEventListener(\"keydown\", this.onMenuKey);\n document.removeEventListener(\"keydown\", this.onKey, true);\n // Release the page-push margins we set for docked modes.\n const de = document.documentElement;\n de.style.marginLeft = de.style.marginRight = de.style.marginBottom = \"\";\n this.root?.remove();\n }\n}\n\n// ---- tiny DOM helpers -------------------------------------------------------\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, cls = \"\", text = \"\"): HTMLElementTagNameMap[K] {\n const n = document.createElement(tag);\n if (cls) n.className = cls;\n if (text) n.textContent = text;\n return n;\n}\nfunction clamp(n: number) { return Math.max(0, Math.min(1, n)); }\n/** \"just now\" / \"3m ago\" / \"2d ago\" for the Home feed. */\nfunction fmtAgo(iso: string): string {\n const then = Date.parse(iso);\n if (Number.isNaN(then)) return \"\";\n const s = Math.max(0, Math.round((Date.now() - then) / 1000));\n if (s < 60) return \"just now\";\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\nlet warnedBadTimeZone = false;\n/**\n * \"4 Oct 2026, 3:42 PM\" — the absolute form, in the given zone and locale (both\n * optional: the browser's by default). An unknown zone or locale falls back to the\n * browser's and says so once, rather than throwing out of a render: a wrong clock\n * is recoverable, a panel that never paints is not.\n */\nfunction fmtAbsolute(iso: string, locale?: string, timeZone?: string): string {\n const t = Date.parse(iso);\n if (Number.isNaN(t)) return \"\";\n const opts: Intl.DateTimeFormatOptions = {\n day: \"numeric\", month: \"short\", year: \"numeric\", hour: \"numeric\", minute: \"2-digit\",\n };\n try {\n return new Intl.DateTimeFormat(locale || undefined, { ...opts, timeZone: timeZone || undefined }).format(t);\n } catch (err) {\n if (!warnedBadTimeZone) {\n warnedBadTimeZone = true;\n console.warn(`[loupe] unusable timeZone/locale (${timeZone ?? \"-\"} / ${locale ?? \"-\"}); using the browser's`, err);\n }\n return new Intl.DateTimeFormat(undefined, opts).format(t);\n }\n}\n/** \"https://x.test/a/b?q=1\" → \"/a/b\" — what the page-path tag shows. */\nfunction shortPath(url: string): string {\n try { return new URL(url, location.origin).pathname || \"/\"; } catch { return url; }\n}\n/**\n * Validate and normalize an environment URL. Only absolute http(s) URLs qualify —\n * a bare \"staging.example.com\" is a typo, not an environment, and normalizing away\n * a trailing slash keeps two spellings of the same place from both being listed.\n */\nfunction normalizeEnvUrl(raw: string): string | null {\n const s = raw.trim();\n if (!s) return null;\n try {\n const u = new URL(s);\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return null;\n if (!u.hostname) return null;\n const path = u.pathname.replace(/\\/+$/, \"\");\n return u.origin + path;\n } catch {\n return null;\n }\n}\n/** The day bucket a comment falls in, for the All-scope timeline grouping. */\nfunction dayLabel(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"Earlier\";\n const today = new Date();\n const startOf = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const days = Math.round((startOf(today) - startOf(d)) / 86_400_000);\n if (days <= 0) return \"Today\";\n if (days === 1) return \"Yesterday\";\n if (days < 7) return `${days} days ago`;\n return d.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n}\nfunction clampPx(n: number, min: number, max: number) { return Math.max(min, Math.min(max, n)); }\n/** An `<option>`. Built as an element rather than `new Option(...)`, which some\n * DOM implementations (and the test environment) do not provide. */\nfunction optionEl(text: string, value: string, selected: boolean): HTMLOptionElement {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = text;\n o.selected = selected;\n return o;\n}\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (m) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[m]!));\n}\n/** Escape for a double-quoted attribute value (escapeHtml already covers the rest). */\nfunction escapeAttr(s: string): string {\n return escapeHtml(s);\n}\n\n// ---- inline icons (font-independent, currentColor) --------------------------\n\nconst svg = (inner: string) =>\n `<svg viewBox=\"0 0 16 16\" width=\"15\" height=\"15\" fill=\"none\" aria-hidden=\"true\">${inner}</svg>`;\nconst DOCK_FRAME = `<rect x=\"1.5\" y=\"2.5\" width=\"13\" height=\"11\" rx=\"1.6\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`;\nconst I_DOCK_LEFT = svg(`${DOCK_FRAME}<rect x=\"2.2\" y=\"3.2\" width=\"4\" height=\"9.6\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_DOCK_RIGHT = svg(`${DOCK_FRAME}<rect x=\"9.8\" y=\"3.2\" width=\"4\" height=\"9.6\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_DOCK_BOTTOM = svg(`${DOCK_FRAME}<rect x=\"2.2\" y=\"9\" width=\"11.6\" height=\"3.8\" rx=\"1\" fill=\"currentColor\"/>`);\nconst I_FLOAT = svg(\n `<rect x=\"2.5\" y=\"3.5\" width=\"11\" height=\"9\" rx=\"1.6\" stroke=\"currentColor\" stroke-width=\"1.3\"/>` +\n `<path d=\"M2.5 6.1h11\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`);\nconst I_SUN = svg(\n `<circle cx=\"8\" cy=\"8\" r=\"3\" stroke=\"currentColor\" stroke-width=\"1.3\"/>` +\n `<g stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\">` +\n `<path d=\"M8 1.4v1.7\"/><path d=\"M8 12.9v1.7\"/><path d=\"M1.4 8h1.7\"/><path d=\"M12.9 8h1.7\"/>` +\n `<path d=\"M3.3 3.3l1.2 1.2\"/><path d=\"M11.5 11.5l1.2 1.2\"/><path d=\"M12.7 3.3l-1.2 1.2\"/><path d=\"M4.5 11.5l-1.2 1.2\"/></g>`);\nconst I_MOON = svg(\n `<path d=\"M13 9.4A5.3 5.3 0 1 1 6.6 3 4.3 4.3 0 0 0 13 9.4z\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linejoin=\"round\"/>`);\nconst I_CLOSE = svg(\n `<path d=\"M4.2 4.2l7.6 7.6M11.8 4.2l-7.6 7.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>`);\nconst I_GEAR = svg(\n `<circle cx=\"8\" cy=\"8\" r=\"2.2\" stroke=\"currentColor\" stroke-width=\"1.4\"/>` +\n `<path d=\"M8 1.6v1.5M8 12.9v1.5M1.6 8h1.5M12.9 8h1.5M3.5 3.5l1.1 1.1M11.4 11.4l1.1 1.1M12.5 3.5l-1.1 1.1M4.6 11.4l-1.1 1.1\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/>`);\nconst I_MINIMIZE = svg(\n `<path d=\"M3.5 8h9\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/>`);\n\n/** FAB cluster quick-action icons (font-independent, currentColor). */\nconst I_COMMENT = svg(\n `<path d=\"M2 3.1h12v7.4H6.5l-3.3 2.6v-2.6H2z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M8 5.1v3.4M6.3 6.8h3.4\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>`);\n/** A sticky note for the \"Note\" quick action — deliberately unlike the comment bubble. */\nconst I_NOTE = svg(\n `<path d=\"M2.6 2.6h10.8v7.2l-3.6 3.6H2.6z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M13.4 9.8h-3.6v3.6\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>`);\nconst I_EYE = svg(\n `<path d=\"M1.4 8S3.9 4 8 4s6.6 4 6.6 4-2.5 4-6.6 4S1.4 8 1.4 8z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<circle cx=\"8\" cy=\"8\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.3\"/>`);\nconst I_PLUG = svg(\n `<path d=\"M6 1.8v3.1M10 1.8v3.1\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>` +\n `<path d=\"M4.4 4.9h7.2v2.3a3.6 3.6 0 0 1-7.2 0z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `<path d=\"M8 10.8v3.4\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\"/>`);\n/** Points up when collapsed, flips down (via CSS) when the actions are out. */\nconst I_EYE_OFF = svg(\n `<path d=\"M2 2l12 12M6.6 6.7A2 2 0 0 0 9.3 9.4M4.3 4.5C2.9 5.4 1.9 6.7 1.5 8c1.1 3 3.7 5 6.5 5 1.3 0 2.5-.4 3.6-1.1M6.9 3.2C7.3 3.1 7.6 3 8 3c2.8 0 5.4 2 6.5 5-.3.8-.8 1.6-1.4 2.3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`,\n);\nconst I_FAB_CHEVRON =\n `<span class=\"lchev\">${svg(`<path d=\"M4.4 9.6 8 6l3.6 3.6\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`)}</span>`;\n\n/** Dashed marquee icon for the \"Region\" button — inline SVG so it never depends on a font. */\nconst REGION_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-dasharray=\"2.4 1.8\"/>` +\n `</svg>`;\n\n/** Speech-bubble icon for the free-\"Note\" button. */\nconst NOTE_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<path d=\"M2 2.5h11v7.5H6l-3 2.5v-2.5H2z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linejoin=\"round\"/>` +\n `</svg>`;\n\n/** Camera/record icon for the \"Record\" button — dashed marquee with a record dot. */\nconst RECORD_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-dasharray=\"2.4 1.8\"/>` +\n `<circle cx=\"7.5\" cy=\"7.5\" r=\"2.4\" fill=\"currentColor\"/>` +\n `</svg>`;\n\n/** Video icon for the \"Video\" button — attach a screen recording made on the phone. */\nconst VIDEO_ICON =\n `<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">` +\n `<rect x=\"1.5\" y=\"2.5\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\"/>` +\n `<path d=\"M6.3 5.5l3.9 2.2-3.9 2.2z\" fill=\"currentColor\"/>` +\n `</svg>`;\n\n// ---- integration icons (brand marks for the \"Integrates with\" footer) -------\nconst I_GITHUB =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M8 .2a8 8 0 0 0-2.5 15.6c.4.07.55-.17.55-.38v-1.3c-2.2.48-2.67-1.07-2.67-1.07-.36-.92-.88-1.16-.88-1.16-.72-.5.05-.48.05-.48.8.056 1.22.82 1.22.82.71 1.22 1.87.87 2.33.66.07-.52.28-.87.5-1.07-1.76-.2-3.6-.88-3.6-3.9 0-.86.3-1.57.82-2.12-.08-.2-.36-1 .08-2.1 0 0 .67-.21 2.2.8a7.6 7.6 0 0 1 4 0c1.53-1.02 2.2-.8 2.2-.8.44 1.1.16 1.9.08 2.1.5.55.82 1.26.82 2.12 0 3.03-1.85 3.7-3.61 3.9.28.24.54.72.54 1.46v2.16c0 .21.14.46.55.38A8 8 0 0 0 8 .2z\"/>` +\n `</svg>`;\nconst I_SLACK =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M3.4 10.1a1.6 1.6 0 1 1-1.6-1.6h1.6v1.6zm.8 0a1.6 1.6 0 0 1 3.2 0v4a1.6 1.6 0 1 1-3.2 0v-4zM5.8 3.4a1.6 1.6 0 1 1 1.6-1.6v1.6H5.8zm0 .8a1.6 1.6 0 0 1 0 3.2h-4a1.6 1.6 0 1 1 0-3.2h4zm6.7 1.6a1.6 1.6 0 1 1 1.6 1.6h-1.6V5.8zm-.8 0a1.6 1.6 0 0 1-3.2 0v-4a1.6 1.6 0 1 1 3.2 0v4zm-1.6 6.7a1.6 1.6 0 1 1-1.6 1.6v-1.6h1.6zm0-.8a1.6 1.6 0 0 1 0-3.2h4a1.6 1.6 0 1 1 0 3.2h-4z\"/>` +\n `</svg>`;\nconst I_TELEGRAM =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0zm3.7 5.4-1.24 5.85c-.09.41-.34.51-.69.32l-1.9-1.4-.92.88c-.1.1-.19.19-.38.19l.14-1.93 3.5-3.17c.15-.13-.03-.2-.24-.07l-4.32 2.72-1.86-.58c-.4-.13-.41-.4.09-.6l7.26-2.8c.34-.12.63.08.52.6z\"/>` +\n `</svg>`;\nconst I_LINEAR =\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">` +\n `<path d=\"M.6 9.2a7.4 7.4 0 0 0 6.2 6.2c.3.04.44-.33.22-.55L1.15 9a.33.33 0 0 0-.55.22zM.5 6.9c-.01.13.04.25.13.34l8.13 8.13c.09.09.21.14.34.13a7.4 7.4 0 0 0 1.3-.26c.28-.08.36-.43.15-.63L1.4 5.45c-.2-.2-.55-.13-.63.15-.12.42-.21.86-.26 1.3zM2.05 4c-.1.13-.09.32.03.44l9.48 9.48c.12.12.31.13.44.03.3-.23.58-.48.85-.75.15-.15.15-.4 0-.55L3.35 3.15a.39.39 0 0 0-.55 0c-.27.27-.52.55-.75.85zM4.5 1.9a.35.35 0 0 0-.04.53l9.11 9.11c.16.16.42.13.53-.04A7.4 7.4 0 1 0 4.5 1.9z\"/>` +\n `</svg>`;\n\n/** Synthesize an Anchor for a free page-level note so downstream (dashboard/MCP) stays happy. */\nfunction pageAnchor(point: { x: number; y: number }): Anchor {\n return {\n tag: \"page\",\n cssPath: \"page\",\n xpath: \"\",\n testid: null,\n text: \"\",\n attrs: {},\n nthOfType: 1,\n rect: { x: Math.round(point.x), y: Math.round(point.y), w: 0, h: 0 },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\n\n/** Synthesize an Anchor for a free region so downstream (dashboard/MCP) stays happy. */\nfunction regionAnchor(region: RegionRect): Anchor {\n return {\n tag: \"region\",\n cssPath: `region ${Math.round(region.w)}×${Math.round(region.h)}`,\n xpath: \"\",\n testid: null,\n text: \"\",\n attrs: {},\n nthOfType: 1,\n rect: { x: Math.round(region.x), y: Math.round(region.y), w: Math.round(region.w), h: Math.round(region.h) },\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\nfunction regionNote(region: RegionRect): string {\n return `<!-- Loupe free-region annotation: ${Math.round(region.w)}×${Math.round(region.h)}px at document (${Math.round(region.x)}, ${Math.round(region.y)}). No single DOM element — see the attached screenshot. -->`;\n}\n\nfunction describe(elx: Element): string {\n const testid = elx.getAttribute(\"data-testid\") || elx.getAttribute(\"data-test\");\n const tag = elx.tagName.toLowerCase();\n if (testid) return `${tag}[data-testid=\"${testid}\"]`;\n if (elx.id) return `${tag}#${elx.id}`;\n const txt = (elx.textContent || \"\").trim().replace(/\\s+/g, \" \").slice(0, 32);\n return txt ? `${tag} · “${txt}”` : tag;\n}\n/**\n * Where a thread points, for a reader: the element's visible text or label, or its test\n * id, before any selector. The raw cssPath (`#delPanel > div:nth-of-type(3) >\n * button:nth-of-type(24)`) is the last resort, not the headline.\n */\nfunction describeAnchor(c: Comment): string {\n if (c.kind === \"free\") return \"Free note · page-level\";\n if (c.kind === \"region\" && c.region) {\n const size = `${Math.round(c.region.w)}×${Math.round(c.region.h)}`;\n if (c.anchor.tag === \"region\") return `Area ${size} · page-level`;\n // \"in\" only when the stored fractions say the area sits inside the anchor; a region\n // saved by an earlier version was anchored to whatever was under its center.\n return `Area ${size} · ${relUsable(c.region.rel) ? \"in\" : \"near\"} ${anchorLabel(c.anchor)}`;\n }\n return anchorLabel(c.anchor);\n}\nfunction anchorLabel(a: Anchor): string {\n const tag = a.tag || \"element\";\n if (a.testid) return `${tag}[data-testid=\"${a.testid}\"]`;\n const text = (a.text || \"\").replace(/\\s+/g, \" \").trim();\n if (text) return `${tag} · “${text.length > 32 ? text.slice(0, 32).trimEnd() + \"…\" : text}”`;\n const attrs = a.attrs ?? {};\n const named = attrs[\"aria-label\"] || attrs.title || attrs.placeholder || attrs.alt || attrs.name;\n if (named) return `${tag} · “${named}”`;\n return a.cssPath || tag;\n}\n\n/** How much of a region an element must cover to anchor it. */\nconst REGION_COVER_MIN = 0.6;\n\n/**\n * The nearest ancestor of `from` (itself included) whose box covers at least\n * REGION_COVER_MIN of the region. `body` and `html` never qualify: a region nothing\n * smaller contains is page-level, and says so through a synthetic anchor.\n */\nfunction regionContainer(from: Element | null, vp: RegionRect): Element | null {\n const area = vp.w * vp.h;\n if (area <= 0) return null;\n for (let n: Element | null = from; n && n !== document.body && n !== document.documentElement; n = n.parentElement) {\n const r = n.getBoundingClientRect();\n if (r.width <= 0 || r.height <= 0) continue;\n const ix = Math.max(0, Math.min(r.right, vp.x + vp.w) - Math.max(r.left, vp.x));\n const iy = Math.max(0, Math.min(r.bottom, vp.y + vp.h) - Math.max(r.top, vp.y));\n if ((ix * iy) / area >= REGION_COVER_MIN) return n;\n }\n return null;\n}\n\n/**\n * Stored fractions a region can trust: ones that keep it roughly within its anchor.\n * Regions saved before 0.11.1 anchored to the element under their center, so a\n * full-screen recording anchored to one word carries fx≈−7 and fw≈15; those place the\n * pin from document coordinates instead.\n */\nfunction relUsable(rel: RegionRect[\"rel\"]): rel is NonNullable<RegionRect[\"rel\"]> {\n if (!rel) return false;\n const lo = -1.5, hi = 2.5;\n return rel.fw > 0 && rel.fh > 0 && rel.fx > lo && rel.fy > lo && rel.fx + rel.fw < hi && rel.fy + rel.fh < hi;\n}\n\n/**\n * A comment is done only at the last stage. Normalizing first means a row still\n * carrying a legacy status (`done`) reads correctly without a data migration.\n */\nfunction isResolved(c: Comment): boolean {\n return normalizeStatus(c.status) === \"resolved\";\n}\n","import type { LoupeTab, LoupeTabContext } from \"./types.js\";\n\n/**\n * The Claude/MCP onboarding page, as a **reusable tab** rather than something the\n * panel forces on every host. Register it if you want it:\n *\n * import { init, connectTab } from \"@loupekit/sdk\";\n * init({ projectKey, user, tabs: [connectTab()] });\n *\n * It is also the worked example for `LoupeTab`: it reads only from the context it\n * is handed, and returns markup.\n */\n\nconst escapeHtml = (s: string) =>\n s.replace(/[&<>\"']/g, (m) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[m]!));\n\nexport function connectTab(): LoupeTab {\n return {\n id: \"connect\",\n label: \"Connect\",\n hint: {\n title: \"Hand it to Claude\",\n body: \"Add the MCP server to your client and it can list, read and answer this feedback — screenshot included.\",\n },\n render: (ctx: LoupeTabContext) => {\n const apiHint = ctx.apiBase ?? \"http://localhost:8787\";\n const config = JSON.stringify(\n {\n mcpServers: {\n loupe: {\n command: \"npx\",\n args: [\"-y\", \"@loupekit/mcp\"],\n env: { LOUPE_API: apiHint, LOUPE_PROJECT_KEY: ctx.projectKey, LOUPE_ADMIN_KEY: \"<your project secret>\" },\n },\n },\n },\n null,\n 2,\n );\n const steps: [string, string][] = [\n [\"Pin your feedback\", \"Use Inspect, Region, Record, or Note to leave comments right on the live app.\"],\n [\"Add the Loupe MCP server\", \"Drop this into your Claude Code config so Claude can read this project's backlog:\"],\n [\"Let Claude fix it\", \"Claude reads each comment (with the screenshot, HTML & CSS), rewrites the UI, and calls propose_change — the modified HTML/CSS then shows up for your dev team in the dashboard.\"],\n ];\n\n return (\n `<div class=\"connect-hero\">` +\n `<div class=\"chero-logo\">◎</div>` +\n `<div class=\"chero-title\">Hand your feedback to <span class=\"accentink\">Claude</span></div>` +\n `<div class=\"chero-sub\">Every pinned comment becomes an actionable, fully-contextualized task Claude Code can act on.</div>` +\n `</div>` +\n `<ol class=\"connect-steps\">` +\n steps.map(([title, body], i) =>\n `<li><div class=\"cstep-t\">${i + 1}. ${escapeHtml(title)}</div>` +\n `<div class=\"cstep-d\">${escapeHtml(body)}</div>` +\n (i === 1 ? `<pre class=\"cstep-code\">${escapeHtml(config)}</pre>` : \"\") +\n `</li>`).join(\"\") +\n `</ol>`\n );\n },\n };\n}\n","import { LoupeApp } from \"./app.js\";\nimport type { ActivityEventInput, ActivityStatus, LoupeConfig } from \"./types.js\";\n\nexport { connectTab } from \"./connect.js\";\n/** The version baked into this bundle — `Loupe.version` from a script tag. \"dev\" from source. */\nexport { SDK_VERSION as version } from \"./app.js\";\nexport type {\n LoupeConfig, LoupeUser, Comment, Anchor, RegionRect, LoupeTab, LoupeTabContext,\n LocalAiConfig, GenerateRequest, GenerateResult, AccessRequest,\n} from \"./types.js\";\nexport type {\n ActivityEvent, ActivityEventInput, ActivityStatus, ActivityLevel,\n} from \"./types.js\";\n\nlet app: LoupeApp | null = null;\n\n/**\n * Initialize Loupe on the current page. Call once, after your app knows who the\n * user is. The toolbar renders only for the identified user.\n *\n * Loupe.init({ projectKey: \"pk_live_…\", user: { id, name, email }, userHmac });\n */\nexport function init(config: LoupeConfig): void {\n if (app) return; // idempotent\n if (!config?.projectKey) { console.error(\"[loupe] init requires a projectKey\"); return; }\n if (!config.user?.id) { console.error(\"[loupe] init requires user.id\"); return; }\n // NOTE: in production the backend verifies config.userHmac before serving data.\n app = new LoupeApp(config);\n const boot = () => app!.start();\n if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", boot);\n else boot();\n}\n\n/** Tear down the toolbar and all listeners. */\nexport function destroy(): void {\n app?.destroy();\n app = null;\n}\n\n/**\n * Push one event into the panel's Activity view — the seam an agent bridge (or the\n * host application) uses to make its work visible without leaving the page.\n * Loupe's own operations feed the same stream, so the view is never empty.\n *\n * Loupe.trackActivity({ kind: \"Read\", label: \"Read src/app.ts\", files: [\"src/app.ts\"] });\n */\nexport function trackActivity(event: ActivityEventInput): void {\n app?.addActivity(event);\n}\n\n/** Set the Activity view's status dot — idle, working, or error. */\nexport function setActivityStatus(status: ActivityStatus): void {\n app?.setActivityStatus(status);\n}\n\n/** Drop everything currently in the Activity view. */\nexport function clearActivity(): void {\n app?.clearActivity();\n}\n\n/**\n * Ask the user to let an agent move the browser. **Nothing navigates here** — the\n * panel shows a prompt and only an explicit grant produces a navigation, which is\n * recorded. Use this rather than driving `location` yourself.\n */\nexport function requestNavigation(url: string, opts?: { reason?: string; requester?: string }): void {\n app?.requestNavigation(url, opts);\n}\n\n/** Store the local-AI endpoint + model the Generate pane should pass to `generate`. */\nexport function setLocalAi(config: { url: string; model: string } | null): void {\n app?.setLocalAi(config);\n}\n\n/** Arm a tool from outside the panel — e.g. a browser context menu. */\nexport function openTool(tool: \"inspect\" | \"note\"): void {\n app?.openTool(tool);\n}\n\n/**\n * Bring the collapsed launcher back after a user hid it (the quick action, the\n * Settings switch, or Alt+Shift+L). The host can wire this to its own menu item.\n */\nexport function showLauncher(): void {\n app?.showLauncher();\n}\n\n/** Hide the collapsed launcher. Persisted per browser; `showLauncher()` or Alt+Shift+L undoes it. */\nexport function hideLauncher(): void {\n app?.hideLauncher();\n}\n"],"mappings":";AACO,IAAM;AAAA;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGhC,IAAM,WAAW;AACjB,IAAM,YAAY,CAAC,QAAQ,cAAc,QAAQ,QAAQ,OAAO,QAAQ,eAAe,OAAO;AAE9F,IAAM,mBAAmB;AAEzB,IAAM,IAAI,EAAE,KAAK,MAAM,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,SAAS,KAAK,UAAU,IAAI;AAInF,SAAS,cAAcA,KAAqB;AACjD,QAAM,OAAOA,IAAG,sBAAsB;AACtC,SAAO;AAAA,IACL,KAAKA,IAAG,QAAQ,YAAY;AAAA,IAC5B,SAAS,QAAQA,GAAE;AAAA,IACnB,OAAO,MAAMA,GAAE;AAAA,IACf,QAAQ,SAASA,GAAE;AAAA,IACnB,MAAM,SAASA,IAAG,WAAW;AAAA,IAC7B,OAAO,UAAUA,GAAE;AAAA,IACnB,WAAW,UAAUA,GAAE;AAAA,IACvB,MAAM;AAAA,MACJ,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,OAAO;AAAA,MACxC,GAAG,KAAK,MAAM,KAAK,MAAM,OAAO,OAAO;AAAA,MACvC,GAAG,KAAK,MAAM,KAAK,KAAK;AAAA,MACxB,GAAG,KAAK,MAAM,KAAK,MAAM;AAAA,IAC3B;AAAA,IACA,UAAU,EAAE,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AAAA,EAC1D;AACF;AASO,SAAS,cAAc,QAAgB,OAAmB,UAAgC;AAE/F,MAAI,OAAO,QAAQ;AACjB,UAAM,WAAW,aAAa,MAAM,iBAAiB,OAAO,OAAO,MAAM,CAAC,mBAAmB,OAAO,OAAO,MAAM,CAAC,IAAI;AACtH,UAAM,OAAO,SAAS,eAAe,OAAO,MAAM;AAClD,UAAM,OAAO,OAAO,CAAC,GAAG,UAAU,GAAI,OAAO,CAAC,IAAI,IAAI,CAAC,CAAE,CAAC,EAAE,OAAO,MAAM;AACzE,QAAI,KAAK,WAAW,EAAG,QAAO,EAAE,SAAS,KAAK,CAAC,GAAI,OAAO,MAAM,KAAK,SAAS;AAAA,EAEhF;AAKA,MAAI,sBAAsB,KAAK,OAAO,OAAO,GAAG;AAC9C,UAAM,OAAO,aAAa,MAAM,OAAO,OAAO,EAAE,OAAO,MAAM;AAC7D,QAAI,KAAK,WAAW,KAAK,KAAK,CAAC,EAAG,QAAQ,YAAY,MAAM,OAAO,KAAK;AACtE,aAAO,EAAE,SAAS,KAAK,CAAC,GAAI,OAAO,KAAK,KAAK,UAAU;AAAA,IACzD;AAAA,EACF;AAEA,QAAM,aAAa,oBAAI,IAAmC;AAC1D,QAAM,WAAW,CAACA,KAAoB,QAA8B;AAClE,QAAIA,OAAM,OAAOA,GAAE,KAAK,CAAC,WAAW,IAAIA,GAAE,EAAG,YAAW,IAAIA,KAAI,GAAG;AAAA,EACrE;AAGA,WAAS,UAAU,MAAM,OAAO,OAAO,GAAG,SAAS;AACnD,WAAS,QAAQ,OAAO,KAAK,GAAG,OAAO;AACvC,aAAWA,OAAM,aAAa,MAAM,OAAO,GAAG,EAAG,UAASA,KAAI,MAAM;AAGpE,MAAI,OAAO,MAAM;AACf,eAAWA,OAAM,aAAa,MAAM,GAAG,GAAG;AACxC,UAAI,WAAW,OAAO,IAAM;AAC5B,UAAI,SAASA,IAAG,WAAW,MAAM,OAAO,KAAM,UAASA,KAAI,MAAM;AAAA,IACnE;AAAA,EACF;AAEA,MAAI,OAA6B;AACjC,aAAW,CAACA,KAAI,GAAG,KAAK,YAAY;AAClC,UAAM,QAAQ,WAAW,QAAQA,KAAI,GAAG;AACxC,QAAI,CAAC,QAAQ,QAAQ,KAAK,MAAO,QAAO,EAAE,SAASA,KAAI,OAAO,IAAI;AAAA,EACpE;AACA,SAAO,QAAQ,KAAK,SAAS,mBAAmB,OAAO;AACzD;AAEA,SAAS,WAAW,GAAWA,KAAa,KAAmC;AAC7E,MAAI,MAAM;AACV,MAAI,QAAQ;AAEZ,QAAM,MAAM,CAAC,GAAW,MAAc;AAAE,WAAO,IAAI;AAAG,aAAS;AAAA,EAAG;AAElE,MAAI,EAAE,KAAKA,IAAG,QAAQ,YAAY,MAAM,EAAE,MAAM,IAAI,CAAC;AAErD,MAAI,EAAE,MAAM;AACV,UAAM,IAAI,SAASA,IAAG,WAAW;AACjC,QAAI,EAAE,MAAM,MAAM,EAAE,OAAO,IAAI,MAAM,EAAE,SAAS,EAAE,IAAI,KAAK,EAAE,KAAK,SAAS,CAAC,KAAK,MAAM,CAAC;AAAA,EAC1F;AAKA,QAAM,WAAW,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC;AAC1C,MAAI,SAAS,QAAQ;AACnB,QAAI,UAAU;AACd,eAAW,KAAK,SAAU,KAAIA,IAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAG;AACzE,QAAI,EAAE,OAAO,UAAU,SAAS,MAAM;AAAA,EACxC;AAEA,MAAI,EAAE,OAAQ,KAAI,EAAE,QAAQ,SAASA,GAAE,MAAM,EAAE,SAAS,IAAI,CAAC;AAE7D,MAAI,EAAE,SAAS,QAAQ,YAAY,IAAI,CAAC;AAGxC,QAAM,IAAIA,IAAG,sBAAsB;AACnC,QAAM,KAAK,EAAE,OAAO,OAAO,UAAU,EAAE,QAAQ;AAC/C,QAAM,KAAK,EAAE,MAAM,OAAO,UAAU,EAAE,SAAS;AAC/C,QAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAC9C,QAAM,KAAK,EAAE,YAAY,EAAE,GAAG,GAAG,GAAG,EAAE;AACtC,QAAM,KAAK,GAAG,IAAI,GAAG,IAAI;AACzB,QAAM,KAAK,GAAG,IAAI,GAAG,IAAI;AACzB,QAAM,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK;AACvC,QAAM,OAAO,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE;AACxC,MAAI,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,OAAO,IAAI,CAAC;AAE5C,SAAO,QAAQ,MAAM,QAAQ;AAC/B;AAIA,SAAS,QAAQA,KAAqB;AACpC,QAAM,OAAiB,CAAC;AACxB,MAAI,OAAuBA;AAC3B,SAAO,QAAQ,KAAK,aAAa,KAAK,SAAS,SAAS,iBAAiB;AACvE,UAAM,KAAK,KAAK,aAAa,IAAI;AACjC,UAAM,SAAS,KAAK,aAAa,aAAa,KAAK,KAAK,aAAa,WAAW;AAChF,QAAI,MAAM,SAAS,EAAE,GAAG;AAAE,WAAK,QAAQ,IAAI,OAAO,EAAE,CAAC,EAAE;AAAG;AAAA,IAAO;AACjE,QAAI,QAAQ;AAAE,WAAK,QAAQ,iBAAiB,OAAO,MAAM,CAAC,IAAI;AAAG;AAAA,IAAO;AACxE,SAAK,QAAQ,GAAG,KAAK,QAAQ,YAAY,CAAC,gBAAgB,UAAU,IAAI,CAAC,GAAG;AAC5E,WAAO,KAAK;AACZ,QAAI,SAAS,SAAS,MAAM;AAAE,WAAK,QAAQ,MAAM;AAAG;AAAA,IAAO;AAAA,EAC7D;AACA,SAAO,KAAK,KAAK,KAAK;AACxB;AAEA,SAAS,MAAMA,KAAqB;AAClC,QAAM,OAAiB,CAAC;AACxB,MAAI,OAAuBA;AAC3B,SAAO,QAAQ,KAAK,aAAa,KAAK,SAAS,SAAS,iBAAiB;AACvE,SAAK,QAAQ,GAAG,KAAK,QAAQ,YAAY,CAAC,IAAI,UAAU,IAAI,CAAC,GAAG;AAChE,WAAO,KAAK;AAAA,EACd;AACA,SAAO,WAAW,KAAK,KAAK,GAAG;AACjC;AAIA,SAAS,UAAUA,KAAqB;AACtC,MAAI,IAAI;AACR,MAAI,MAAMA,IAAG;AACb,SAAO,KAAK;AACV,QAAI,IAAI,YAAYA,IAAG,QAAS;AAChC,UAAM,IAAI;AAAA,EACZ;AACA,SAAO;AACT;AAEA,SAAS,SAASA,KAA4B;AAC5C,QAAM,SAASA,IAAG,aAAa,aAAa,KAAKA,IAAG,aAAa,WAAW;AAC5E,MAAI,OAAQ,QAAO;AACnB,QAAM,KAAKA,IAAG,aAAa,IAAI;AAC/B,SAAO,MAAM,SAAS,EAAE,IAAI,KAAK;AACnC;AAGA,SAAS,SAAS,IAAqB;AACrC,MAAI,GAAG,SAAS,GAAI,QAAO;AAC3B,MAAI,sCAAsC,KAAK,EAAE,EAAG,QAAO;AAC3D,MAAI,MAAM,KAAK,EAAE,EAAG,QAAO;AAC3B,SAAO;AACT;AAEA,SAAS,UAAUA,KAAqC;AACtD,QAAM,MAA8B,CAAC;AACrC,aAAW,KAAK,WAAW;AACzB,UAAM,IAAIA,IAAG,aAAa,CAAC;AAC3B,QAAI,KAAK,QAAQ,MAAM,GAAI,KAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI;AAAA,EACzE;AACA,SAAO;AACT;AAEA,SAAS,SAAS,GAA0B;AAC1C,UAAQ,KAAK,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;AAChE;AAOA,SAAS,OAAOA,KAAsB;AACpC,MAAIA,IAAG,OAAO,gBAAgBA,IAAG,QAAQ,aAAa,EAAG,QAAO;AAChE,MAAIA,QAAO,SAAS,QAAQA,QAAO,SAAS,gBAAiB,QAAO;AACpE,MAAI,OAAOA,IAAG,oBAAoB,cAAc,CAACA,IAAG,gBAAgB,EAAG,QAAO;AAC9E,SAAO;AACT;AAEA,SAAS,QAAQ,IAA4B;AAC3C,MAAI;AACF,UAAM,IAAI,SAAS,SAAS,IAAI,UAAU,MAAM,YAAY,yBAAyB,IAAI;AACzF,WAAO,EAAE,2BAA2B,UAAU,EAAE,kBAAkB;AAAA,EACpE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,MAAkB,KAA6B;AAChE,MAAI;AAAE,WAAO,MAAM,KAAK,cAAc,GAAG,IAAI;AAAA,EAAM,QAAQ;AAAE,WAAO;AAAA,EAAM;AAC5E;AACA,SAAS,aAAa,MAAkB,KAAwB;AAC9D,MAAI;AAAE,WAAO,MAAM,MAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC,IAAI,CAAC;AAAA,EAAG,QAAQ;AAAE,WAAO,CAAC;AAAA,EAAG;AACvF;AACA,SAAS,OAAO,KAA2B;AACzC,SAAO,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC;AAChC;AACA,SAAS,OAAO,GAAmB;AACjC,SAAQ,OAAO,OAAO,IAAI,SAAU,IAAI,OAAO,CAAC,IAAI,EAAE,QAAQ,UAAU,MAAM;AAChF;AAEA,SAAS,OAAO,GAAmB;AACjC,SAAO,EAAE,QAAQ,UAAU,MAAM;AACnC;;;ACvOA,SAAS,cAAc,YAAY,KAAK;AACtC,aAAW,EAAE,IAAI;AACjB,aAAW,EAAE,IAAI,OAAO;AACxB,aAAW,EAAE,IAAI,MAAM;AACvB,aAAW,EAAE,IAAI,OAAO;AACxB,aAAW,EAAE,IAAI,MAAM;AACvB,SAAO;AACT;AAEA,IAAM,KAAK,IAAI,WAAW,CAAC;AAC3B,IAAM,KAAK,IAAI,WAAW,CAAC;AAC3B,IAAM,KAAK,IAAI,WAAW,CAAC;AAC3B,IAAM,KAAK,IAAI,WAAW,CAAC;AAC3B,IAAI;AACJ,SAAS,qBAAqB;AAC5B,QAAM,WAAW,IAAI,WAAW,GAAG;AACnC,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,QAAI,IAAI;AACR,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,IAAI,IAAI,aAAa,MAAM,IAAI,MAAM;AAAA,IAC3C;AACA,aAAS,CAAC,IAAI;AAAA,EAChB;AACA,SAAO;AACT;AACA,SAAS,QAAQ,YAAY;AAC3B,MAAI,IAAI;AACR,MAAI,CAAC;AACH,mBAAe,mBAAmB;AACpC,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,QAAI,cAAc,IAAI,WAAW,CAAC,KAAK,GAAG,IAAI,MAAM;AAAA,EACtD;AACA,SAAO,IAAI;AACb;AACA,SAAS,kBAAkB,YAAY;AACrC,QAAM,SAAS,WAAW,SAAS;AACnC,WAAS,IAAI,QAAQ,KAAK,GAAG,KAAK;AAChC,QAAI,WAAW,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,MAAM,WAAW,IAAI,CAAC,MAAM,MAAM,WAAW,IAAI,CAAC,MAAM,MAAM,WAAW,CAAC,MAAM,IAAI;AACvI,aAAO,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AACA,SAAS,aAAa,YAAY,KAAK,gBAAgB,OAAO;AAC5D,QAAM,YAAY,IAAI,WAAW,EAAE;AACnC,SAAO;AACP,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI;AACf,YAAU,CAAC,IAAI,QAAQ;AACvB,YAAU,CAAC,IAAI,QAAQ;AACvB,YAAU,CAAC,IAAI,QAAQ;AACvB,YAAU,CAAC,IAAI,MAAM;AACrB,YAAU,CAAC,IAAI,UAAU,CAAC;AAC1B,YAAU,CAAC,IAAI,UAAU,CAAC;AAC1B,YAAU,EAAE,IAAI,UAAU,CAAC;AAC3B,YAAU,EAAE,IAAI,UAAU,CAAC;AAC3B,YAAU,EAAE,IAAI;AAChB,QAAM,MAAM,QAAQ,SAAS;AAC7B,QAAM,WAAW,IAAI,WAAW,CAAC;AACjC,WAAS,CAAC,IAAI,QAAQ;AACtB,WAAS,CAAC,IAAI,QAAQ;AACtB,WAAS,CAAC,IAAI,QAAQ;AACtB,WAAS,CAAC,IAAI,MAAM;AACpB,MAAI,eAAe;AACjB,UAAM,gBAAgB,kBAAkB,UAAU;AAClD,eAAW,IAAI,WAAW,aAAa;AACvC,eAAW,IAAI,UAAU,gBAAgB,EAAE;AAC3C,WAAO;AAAA,EACT,OAAO;AACL,UAAM,cAAc,IAAI,WAAW,CAAC;AACpC,gBAAY,CAAC,IAAI;AACjB,gBAAY,CAAC,IAAI;AACjB,gBAAY,CAAC,IAAI;AACjB,gBAAY,CAAC,IAAI;AACjB,UAAM,cAAc,IAAI,WAAW,EAAE;AACrC,gBAAY,IAAI,YAAY,CAAC;AAC7B,gBAAY,IAAI,aAAa,EAAE;AAC/B,gBAAY,IAAI,WAAW,EAAE;AAC7B,gBAAY,IAAI,UAAU,EAAE;AAC5B,WAAO;AAAA,EACT;AACF;AACA,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,SAAS,2BAA2B,SAAS;AAC3C,MAAI,WAAW,QAAQ,QAAQ,iBAAiB;AAChD,MAAI,aAAa,IAAI;AACnB,eAAW,QAAQ,QAAQ,iBAAiB;AAAA,EAC9C;AACA,MAAI,aAAa,IAAI;AACnB,eAAW,QAAQ,QAAQ,iBAAiB;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,IAAM,SAAS;AACf,IAAM,aAAa,OAAO,WAAW;AACrC,IAAM,qBAAqB,cAAc,YAAY;AACrD,IAAM,eAAe,cAAc,UAAU;AAC7C,IAAM,eAAe,cAAc,UAAU;AAC7C,IAAM,aAAa,aAAa,OAAO,WAAW,YAAY;AAC9D,IAAM,YAAY,WAAW,SAAS,QAAQ;AAC9C,IAAM,YAAY,WAAW,SAAS,aAAa,KAAK,CAAC;AACzD,IAAM,aAAa,WAAW,SAAS,SAAS;AAChD,IAAM,YAAY,CAAC,UAAU,SAAS,iBAAiB;AACvD,IAAM,oBAAoB,CAAC,SAAS,KAAK,YAAY,SAAS;AAC9D,IAAM,kBAAkB,CAAC,SAAS,KAAK,YAAY,SAAS;AAC5D,IAAM,mBAAmB,CAAC,SAAS,KAAK,YAAY,SAAS;AAC7D,IAAM,gBAAgB,CAAC,SAAS,KAAK,aAAa;AAClD,IAAM,mBAAmB,CAAC,SAAS,OAAO,KAAK,cAAc;AAC7D,IAAM,wBAAwB,CAAC,SAAS,KAAK,YAAY;AACzD,IAAM,sBAAsB,CAAC,SAAS,KAAK,YAAY;AACvD,IAAM,oBAAoB,CAAC,SAAS,cAAc,IAAI,KAAK,OAAO,KAAK,UAAU,eAAe,CAAC,iBAAiB,IAAI;AACtH,IAAM,gBAAgB,CAAC,SAAS,KAAK,aAAa;AAClD,IAAM,aAAa,CAAC,SAAS,KAAK,aAAa;AAC/C,IAAM,iBAAiB,CAAC,SAAS,KAAK,YAAY;AAClD,IAAM,iBAAiB,CAAC,SAAS,KAAK,YAAY;AAClD,IAAM,kBAAkB,CAAC,SAAS,KAAK,YAAY;AACnD,IAAM,oBAAoB,CAAC,SAAS,KAAK,YAAY;AACrD,IAAM,iBAAiB,CAAC,SAAS,KAAK,YAAY;AAClD,IAAM,iBAAiB,CAAC,SAAS,KAAK,YAAY;AAClD,IAAM,kBAAkB,CAAC,SAAS,KAAK,YAAY;AACnD,IAAM,kBAAkB,CAAC,SAAS,KAAK,YAAY;AACnD,IAAM,gBAAgB,CAAC,SAAS,KAAK,YAAY;AACjD,IAAM,kBAAkB,CAAC,SAAS,KAAK,YAAY;AACnD,IAAM,cAAc,IAAI,SAAS,QAAQ,KAAK,QAAQ,GAAG,IAAI;AAC7D,SAAS,YAAY,eAAe;AAClC,QAAM,SAAS,eAAe,gBAAgB,QAAQ;AACtD,MAAI,QAAQ;AACV,WAAO,SAAS,OAAO,QAAQ;AAAA,EACjC;AACA,SAAO,QAAQ,MAAM,KAAK,eAAe,UAAU,QAAQ,OAAO,UAAU,YAAY,EAAE,SAAS,YAAY,CAAC;AAClH;AACA,IAAM,YAAY,CAAC,QAAQ,IAAI,WAAW,OAAO;AACjD,SAAS,WAAW,KAAK,SAAS;AAChC,MAAI,IAAI,MAAM,eAAe;AAC3B,WAAO;AACT,MAAI,cAAc,IAAI,MAAM,OAAO;AACjC,WAAO,OAAO,SAAS,WAAW;AACpC,MAAI,IAAI,MAAM,WAAW;AACvB,WAAO;AACT,MAAI,CAAC;AACH,WAAO;AACT,QAAM,MAAM,YAAY,EAAE,eAAe,mBAAmB;AAC5D,QAAM,OAAO,IAAI,cAAc,MAAM;AACrC,QAAM,IAAI,IAAI,cAAc,GAAG;AAC/B,MAAI,KAAK,YAAY,IAAI;AACzB,MAAI,KAAK,YAAY,CAAC;AACtB,MAAI;AACF,SAAK,OAAO;AACd,IAAE,OAAO;AACT,SAAO,EAAE;AACX;AACA,SAAS,YAAY,QAAQ;AAC3B,UAAQ,UAAU,cAAc,MAAM,IAAI,QAAQ,gBAAgB,WAAW,OAAO;AACtF;AACA,IAAM,QAAQ;AACd,SAAS,UAAU,OAAO,QAAQ,eAAe;AAC/C,QAAMC,OAAM,YAAY,aAAa,EAAE,gBAAgB,OAAO,KAAK;AACnE,EAAAA,KAAI,eAAe,MAAM,SAAS,MAAM,SAAS,CAAC;AAClD,EAAAA,KAAI,eAAe,MAAM,UAAU,OAAO,SAAS,CAAC;AACpD,EAAAA,KAAI,eAAe,MAAM,WAAW,OAAO,KAAK,IAAI,MAAM,EAAE;AAC5D,SAAOA;AACT;AACA,SAAS,aAAaA,MAAK,wBAAwB;AACjD,MAAI,QAAQ,IAAI,cAAc,EAAE,kBAAkBA,IAAG;AACrD,MAAI,wBAAwB;AAC1B,YAAQ,MAAM,QAAQ,+DAA+D,EAAE;AAAA,EACzF;AACA,SAAO,oCAAoC,mBAAmB,KAAK,CAAC;AACtE;AA8BA,SAAS,SAAS,MAAM,MAAM;AAC5B,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM,QAAQ,OAAO,MAAM;AAC3C,WAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAC1C,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,uBAAuB,IAAI,EAAE,CAAC;AACtE,QAAI,SAAS,WAAW;AACtB,aAAO,cAAc,IAAI;AAAA,IAC3B,WAAW,SAAS,eAAe;AACjC,aAAO,kBAAkB,IAAI;AAAA,IAC/B;AAAA,EACF,CAAC;AACH;AACA,IAAM,gBAAgB,CAAC,SAAS,SAAS,MAAM,SAAS;AAExD,SAAS,YAAY,KAAK,eAAe;AACvC,QAAM,MAAM,YAAY,aAAa,EAAE,cAAc,KAAK;AAC1D,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,MAAM;AACV,SAAO;AACT;AACA,SAAS,UAAU,OAAO,SAAS;AACjC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,EAAE,SAAS,eAAe,SAAS,aAAa,OAAO,IAAI,WAAW,CAAC;AAC7E,UAAM,OAAO,OAAO,UAAU,WAAW,YAAY,OAAO,YAAY,aAAa,CAAC,IAAI;AAC1F,QAAI,QAAQ;AACZ,QAAI,uBAAuB;AAC3B,aAAS,YAAY;AACnB,cAAQ,IAAI;AACZ,eAAS,aAAa,KAAK;AAC3B,6BAAuB;AAAA,IACzB;AACA,QAAI,SAAS;AACX,cAAQ,WAAW,WAAW,OAAO;AAAA,IACvC;AACA,QAAI,eAAe,IAAI,GAAG;AACxB,YAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,UAAI,CAAC,YAAY;AACf,YAAI,KAAK,QAAQ;AACf,iBAAO,UAAU,KAAK,QAAQ,OAAO,EAAE,KAAK,OAAO;AAAA,QACrD;AACA,eAAO,UAAU;AAAA,MACnB;AACA,UAAI,KAAK,cAAc,GAAG;AACxB,eAAO,UAAU;AAAA,MACnB;AACA,YAAM,eAAe;AACrB,YAAM,UAAU,CAAC,UAAU;AACzB;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,sBAAc,KAAK;AACnB,kBAAU;AAAA,MACZ;AACA,6BAAuB,MAAM;AAC3B,aAAK,oBAAoB,cAAc,YAAY;AACnD,aAAK,oBAAoB,SAAS,OAAO;AAAA,MAC3C;AACA,WAAK,iBAAiB,cAAc,cAAc,EAAE,MAAM,KAAK,CAAC;AAChE,WAAK,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IACxD,OAAO;AACL,YAAM,aAAa,sBAAsB,IAAI,IAAI,KAAK,KAAK,UAAU,KAAK,cAAc,KAAK;AAC7F,UAAI,CAAC,YAAY;AACf,eAAO,UAAU;AAAA,MACnB;AACA,YAAM,SAAS,YAAY;AACzB,YAAI,eAAe,IAAI,KAAK,YAAY,MAAM;AAC5C,cAAI;AACF,kBAAM,KAAK,OAAO;AAAA,UACpB,SAAS,OAAO;AACd;AAAA,cACE;AAAA,cACA,KAAK,QAAQ,eAAe;AAAA,cAC5B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,kBAAU;AAAA,MACZ;AACA,YAAM,UAAU,CAAC,UAAU;AACzB;AAAA,UACE;AAAA,UACA,KAAK,QAAQ,eAAe;AAAA,UAC5B;AAAA,QACF;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,eAAe,IAAI,KAAK,KAAK,UAAU;AACzC,eAAO,OAAO;AAAA,MAChB;AACA,6BAAuB,MAAM;AAC3B,aAAK,oBAAoB,QAAQ,MAAM;AACvC,aAAK,oBAAoB,SAAS,OAAO;AAAA,MAC3C;AACA,WAAK,iBAAiB,QAAQ,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpD,WAAK,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AACH;AACA,eAAe,cAAc,MAAM,SAAS;AAC1C,MAAI,kBAAkB,IAAI,GAAG;AAC3B,QAAI,eAAe,IAAI,KAAK,eAAe,IAAI,GAAG;AAChD,YAAM,UAAU,MAAM,OAAO;AAAA,IAC/B,OAAO;AACL,YAAM,QAAQ;AAAA,QACZ,CAAC,OAAO,OAAO,EAAE,QAAQ,CAAC,cAAc;AACtC,iBAAO,MAAM,KAAK,KAAK,iBAAiB,SAAS,CAAC,EAAE,IAAI,CAACC,QAAO,UAAUA,KAAI,OAAO,CAAC;AAAA,QACxF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AACA,IAAM,OAAuB,0BAAS,QAAQ;AAC5C,MAAI,UAAU;AACd,QAAM,SAAS,MAAM,QAAQ,KAAK,OAAO,IAAI,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC,GAAG,MAAM,EAAE;AAClF,SAAO,MAAM;AACX,eAAW;AACX,WAAO,IAAI,OAAO,CAAC,GAAG,OAAO;AAAA,EAC/B;AACF,GAAE;AACF,SAAS,gBAAgB,YAAY;AACnC,SAAO,YAAY,MAAM,GAAG,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK,EAAE,QAAQ,QAAQ,EAAE,EAAE,YAAY,CAAC,EAAE,OAAO,OAAO;AACzG;AAEA,IAAI,MAAM;AACV,SAAS,aAAa,OAAO;AAC3B,QAAM,SAAS,GAAG,MAAM,KAAK,GAAG;AAChC;AACA,SAAO;AAAA;AAAA,IAEL,MAAM,CAAC,UAAU,SAAS,QAAQ,KAAK,GAAG,MAAM,IAAI,KAAK,EAAE;AAAA;AAAA,IAE3D,SAAS,CAAC,UAAU,SAAS,QAAQ,QAAQ,GAAG,MAAM,IAAI,KAAK,EAAE;AAAA,IACjE,MAAM,IAAI,SAAS,SAAS,YAAY,GAAG,IAAI;AAAA,EACjD;AACF;AAEA,SAAS,sBAAsB,gBAAgB;AAC7C,SAAO;AAAA,IACL,OAAO,iBAAiB,aAAa;AAAA,EACvC;AACF;AAEA,eAAe,gBAAgB,MAAM,SAAS;AAC5C,SAAO,UAAU,IAAI,IAAI,OAAO,cAAc,MAAM,EAAE,GAAG,SAAS,cAAc,KAAK,CAAC;AACxF;AACA,eAAe,cAAc,MAAM,SAAS;AAC1C,QAAM,EAAE,QAAQ,GAAG,WAAW,eAAe,EAAE,IAAI,WAAW,CAAC;AAC/D,QAAM,QAAQ,QAAQ,SAAS,KAAK;AACpC,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,gBAAgB,KAAK,kBAAkB,aAAa,OAAO,WAAW;AAC5E,QAAM,cAAc,KAAK,eAAe,gBAAgB,aAAa,SAAS;AAC9E,QAAM,WAA2B,oBAAI,IAAI;AACzC,QAAM,UAAU;AAAA;AAAA,IAEd,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN;AAAA,IACA,iBAAiB;AAAA,IACjB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,SAAS;AAAA,IACT,UAAU;AAAA,IACV;AAAA,IACA,OAAO;AAAA,MACL,aAAa,sBAAsB,SAAS,OAAO,cAAc;AAAA,MACjE,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,MAChB,GAAG,SAAS;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,MAAM,CAAC;AAAA,IACP,mBAAmB;AAAA,IACnB,WAAW;AAAA,IACX;AAAA,IACA,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,cAAc;AAAA,IACd,GAAG;AAAA;AAAA,IAEH,aAAa;AAAA,IACb,KAAK,aAAa,KAAK;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,UAAU,IAAI,OAAO,KAAK;AAAA,IAC/B,iBAAiB,mBAAmB,aAAa;AAAA,IACjD,gBAAgB,eAAe,gBAAgB,OAAO,MAAM;AAAA,IAC5D,WAA2B,oBAAI,IAAI;AAAA,IACnC,uBAAuC,oBAAI,IAAI;AAAA,IAC/C,SAAS;AAAA,MACP,GAAG,MAAM,KAAK;AAAA,QACZ,QAAQ,sBAAsB,aAAa,eAAe,eAAe;AAAA,MAC3E,CAAC;AAAA,IACH,EAAE,IAAI,MAAM;AACV,UAAI;AACF,cAAM,SAAS,IAAI,OAAO,SAAS;AACnC,eAAO,YAAY,OAAO,UAAU;AAClC,gBAAM,EAAE,KAAK,OAAO,IAAI,MAAM;AAC9B,cAAI,QAAQ;AACV,qBAAS,IAAI,GAAG,GAAG,UAAU,MAAM;AAAA,UACrC,OAAO;AACL,qBAAS,IAAI,GAAG,GAAG,SAAS,IAAI,MAAM,wCAAwC,GAAG,EAAE,CAAC;AAAA,UACtF;AAAA,QACF;AACA,eAAO,iBAAiB,CAAC,UAAU;AACjC,gBAAM,EAAE,IAAI,IAAI,MAAM;AACtB,mBAAS,IAAI,GAAG,GAAG,SAAS,IAAI,MAAM,wCAAwC,GAAG,EAAE,CAAC;AAAA,QACtF;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,gBAAQ,IAAI,KAAK,wBAAwB,KAAK;AAC9C,eAAO;AAAA,MACT;AAAA,IACF,CAAC,EAAE,OAAO,OAAO;AAAA,IACjB,cAA8B,oBAAI,IAAI;AAAA,IACtC,cAA8B,oBAAI,IAAI;AAAA,IACtC,eAAe,GAAG;AAAA,MAChB,YAAY,aAAa,KAAK;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAAC;AAAA,IAC3B;AAAA,IACA,gBAAgB;AAAA,IAChB,OAAO,CAAC;AAAA,IACR;AAAA,IACA,UAAU,CAAC,QAAQ;AACjB,UAAI,QAAQ,yBAAyB;AACnC,eAAO,OAAO,aAAa,YAAY,QAAQ,SAAS,GAAG,KAAK;AAAA,MAClE;AACA,UAAI,OAAO,aAAa,WAAW;AACjC,eAAO;AAAA,MACT;AACA,aAAO,SAAS,GAAG,KAAK;AAAA,IAC1B;AAAA,IACA,aAAa,CAAC;AAAA,EAChB;AACA,UAAQ,IAAI,KAAK,iBAAiB;AAClC,QAAM,cAAc,MAAM,EAAE,SAAS,QAAQ,SAAS,QAAQ,QAAQ,IAAI,KAAK,CAAC;AAChF,UAAQ,IAAI,QAAQ,iBAAiB;AACrC,QAAM,EAAE,OAAO,OAAO,IAAI,mBAAmB,MAAM,OAAO;AAC1D,UAAQ,QAAQ;AAChB,UAAQ,SAAS;AACjB,SAAO;AACT;AACA,SAAS,mBAAmB,eAAe;AACzC,MAAI,CAAC;AACH,WAAO;AACT,QAAM,QAAQ,cAAc,cAAc,OAAO;AACjD,QAAM,UAAU,MAAM,cAAc,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,CAKpD;AACC,QAAM,YAAY,OAAO;AACzB,SAAO;AACT;AACA,SAAS,mBAAmB,MAAM,SAAS;AACzC,MAAI,EAAE,OAAO,OAAO,IAAI;AACxB,MAAI,cAAc,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS;AAC9C,UAAM,MAAM,KAAK,sBAAsB;AACvC,YAAQ,SAAS,IAAI,SAAS,OAAO,KAAK,aAAa,OAAO,CAAC,KAAK;AACpE,aAAS,UAAU,IAAI,UAAU,OAAO,KAAK,aAAa,QAAQ,CAAC,KAAK;AAAA,EAC1E;AACA,SAAO,EAAE,OAAO,OAAO;AACzB;AAEA,eAAe,cAAc,OAAO,SAAS;AAC3C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,KAAK,iBAAiB;AAC1B,QAAM,SAAS,MAAM,UAAU,OAAO,EAAE,SAAS,QAAQ,QAAQ,IAAI,KAAK,CAAC;AAC3E,QAAM,EAAE,QAAQ,UAAU,IAAI,aAAa,MAAM,eAAe,OAAO;AACvE,QAAM,YAAY,MAAM;AACtB,QAAI;AACF,iBAAW,UAAU,QAAQ,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAAA,IAChE,SAAS,OAAO;AACd,cAAQ,IAAI,KAAK,uBAAuB,KAAK;AAAA,IAC/C;AAAA,EACF;AACA,YAAU;AACV,MAAI,QAAQ,SAAS,iBAAiB,GAAG;AACvC,aAAS,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACvC,YAAM,IAAI,QAAQ,CAAC,YAAY;AAC7B,mBAAW,MAAM;AACf,qBAAW,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACtD,oBAAU;AACV,kBAAQ;AAAA,QACV,GAAG,IAAI,iBAAiB;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF;AACA,UAAQ,iBAAiB;AACzB,MAAI,QAAQ,iBAAiB;AAC7B,SAAO;AACT;AACA,SAAS,aAAa,eAAe,SAAS;AAC5C,QAAM,EAAE,OAAO,QAAQ,OAAO,iBAAiB,mBAAmB,IAAI,IAAI;AAC1E,QAAM,SAAS,cAAc,cAAc,QAAQ;AACnD,SAAO,QAAQ,KAAK,MAAM,QAAQ,KAAK;AACvC,SAAO,SAAS,KAAK,MAAM,SAAS,KAAK;AACzC,SAAO,MAAM,QAAQ,GAAG,KAAK;AAC7B,SAAO,MAAM,SAAS,GAAG,MAAM;AAC/B,MAAI,KAAK;AACP,QAAI,OAAO,QAAQ,OAAO,OAAO,SAAS,KAAK;AAC7C,UAAI,OAAO,QAAQ,OAAO,OAAO,SAAS,KAAK;AAC7C,YAAI,OAAO,QAAQ,OAAO,QAAQ;AAChC,iBAAO,UAAU,MAAM,OAAO;AAC9B,iBAAO,QAAQ;AAAA,QACjB,OAAO;AACL,iBAAO,SAAS,MAAM,OAAO;AAC7B,iBAAO,SAAS;AAAA,QAClB;AAAA,MACF,WAAW,OAAO,QAAQ,KAAK;AAC7B,eAAO,UAAU,MAAM,OAAO;AAC9B,eAAO,QAAQ;AAAA,MACjB,OAAO;AACL,eAAO,SAAS,MAAM,OAAO;AAC7B,eAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,QAAM,YAAY,OAAO,WAAW,IAAI;AACxC,MAAI,aAAa,iBAAiB;AAChC,cAAU,YAAY;AACtB,cAAU,SAAS,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAAA,EACtD;AACA,SAAO,EAAE,QAAQ,UAAU;AAC7B;AAEA,SAAS,YAAY,QAAQ,SAAS;AACpC,MAAI,OAAO,eAAe;AACxB,QAAI;AACF,YAAM,UAAU,OAAO,UAAU;AACjC,UAAI,YAAY,UAAU;AACxB,eAAO,YAAY,SAAS,OAAO,aAAa;AAAA,MAClD;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,IAAI,KAAK,0BAA0B,KAAK;AAAA,IAClD;AAAA,EACF;AACA,QAAM,SAAS,OAAO,UAAU,KAAK;AACrC,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAM,YAAY,OAAO,WAAW,IAAI;AACxC,MAAI;AACF,QAAI,OAAO,WAAW;AACpB,gBAAU;AAAA,QACR,IAAI,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,0BAA0B,KAAK;AAAA,EAClD;AACA,SAAO;AACT;AAEA,SAAS,YAAY,QAAQ,SAAS;AACpC,MAAI;AACF,QAAI,QAAQ,iBAAiB,iBAAiB;AAC5C,aAAO,UAAU,OAAO,gBAAgB,iBAAiB,OAAO;AAAA,IAClE;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,0BAA0B,KAAK;AAAA,EAClD;AACA,SAAO,OAAO,UAAU,KAAK;AAC/B;AAEA,SAAS,WAAW,OAAO;AACzB,QAAM,SAAS,MAAM,UAAU,KAAK;AACpC,MAAI,MAAM,cAAc,MAAM,eAAe,MAAM,KAAK;AACtD,WAAO,MAAM,MAAM;AACnB,WAAO,SAAS;AAAA,EAClB;AACA,MAAI,OAAO,YAAY,QAAQ;AAC7B,WAAO,UAAU;AAAA,EACnB;AACA,SAAO;AACT;AAEA,eAAe,WAAW,OAAO,SAAS;AACxC,MAAI,MAAM,iBAAiB,CAAC,MAAM,cAAc,MAAM,QAAQ;AAC5D,WAAO,YAAY,MAAM,QAAQ,MAAM,aAAa;AAAA,EACtD;AACA,QAAM,SAAS,MAAM,UAAU,KAAK;AACpC,SAAO,cAAc;AACrB,MAAI,MAAM,cAAc,MAAM,eAAe,MAAM,KAAK;AACtD,WAAO,MAAM,MAAM;AAAA,EACrB;AACA,QAAM,gBAAgB,OAAO;AAC7B,MAAI,eAAe;AACjB,QAAI,UAAU;AACd,UAAM,UAAU,QAAQ,EAAE,SAAS,MAAM,UAAU,OAAO,QAAQ,QAAQ,IAAI,KAAK,CAAC;AACpF,QAAI,CAAC,SAAS;AACZ,UAAI,MAAM,QAAQ;AAChB,eAAO,YAAY,MAAM,QAAQ,MAAM,aAAa;AAAA,MACtD;AACA,aAAO;AAAA,IACT;AACA,WAAO,cAAc,MAAM;AAC3B,UAAM,IAAI,QAAQ,CAAC,YAAY;AAC7B,aAAO,iBAAiB,UAAU,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAC3D,CAAC;AACD,UAAM,SAAS,cAAc,cAAc,QAAQ;AACnD,WAAO,QAAQ,MAAM;AACrB,WAAO,SAAS,MAAM;AACtB,QAAI;AACF,YAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAI;AACF,YAAI,UAAU,QAAQ,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAAA,IAC3D,SAAS,OAAO;AACd,cAAQ,IAAI,KAAK,yBAAyB,KAAK;AAC/C,UAAI,MAAM,QAAQ;AAChB,eAAO,YAAY,MAAM,QAAQ,MAAM,aAAa;AAAA,MACtD;AACA,aAAO;AAAA,IACT;AACA,WAAO,YAAY,QAAQ,OAAO;AAAA,EACpC;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAM,SAAS;AACnC,MAAI,gBAAgB,IAAI,GAAG;AACzB,WAAO,YAAY,MAAM,OAAO;AAAA,EAClC;AACA,MAAI,gBAAgB,IAAI,GAAG;AACzB,WAAO,YAAY,MAAM,OAAO;AAAA,EAClC;AACA,MAAI,eAAe,IAAI,GAAG;AACxB,WAAO,WAAW,IAAI;AAAA,EACxB;AACA,MAAI,eAAe,IAAI,GAAG;AACxB,WAAO,WAAW,MAAM,OAAO;AAAA,EACjC;AACA,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,WAAW,SAAS;AAC3B,MAAI,UAAU,QAAQ;AACtB,MAAI,CAAC,SAAS;AACZ,UAAM,EAAE,cAAc,IAAI;AAC1B,QAAI;AACF,UAAI,eAAe;AACjB,kBAAU,cAAc,cAAc,QAAQ;AAC9C,gBAAQ,KAAK,cAAc,KAAK,CAAC;AACjC,gBAAQ,QAAQ;AAChB,gBAAQ,SAAS;AACjB,gBAAQ,MAAM,aAAa;AAC3B,gBAAQ,MAAM,WAAW;AACzB,sBAAc,KAAK,YAAY,OAAO;AACtC,gBAAQ,SAAS;AACjB,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,IAAI,KAAK,wBAAwB,KAAK;AAAA,IAChD;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AACF;AACA,SAAS,gBAAgB,MAAM,eAAe,SAAS;AACrD,QAAM,EAAE,sBAAsB,IAAI;AAClC,QAAM,WAAW,KAAK,SAAS,YAAY;AAC3C,QAAM,YAAY,iBAAiB,IAAI,KAAK,aAAa;AACzD,QAAM,aAAa,YAAY,mBAAmB,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC;AAC1I,QAAM,MAAM;AAAA,IACV,aAAa;AAAA,IACb;AAAA,IACA,WAAW,IAAI,CAAC,MAAM,UAAU,GAAG,IAAI,IAAI,KAAK,EAAE,EAAE,KAAK,GAAG;AAAA,IAC5D;AAAA,EACF,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC1B,MAAI,sBAAsB,IAAI,GAAG;AAC/B,WAAO,sBAAsB,IAAI,GAAG;AACtC,QAAM,UAAU,WAAW,OAAO;AAClC,QAAM,gBAAgB,SAAS;AAC/B,MAAI,CAAC;AACH,WAAuB,oBAAI,IAAI;AACjC,QAAM,kBAAkB,eAAe;AACvC,MAAI;AACJ,MAAIA;AACJ,MAAI,WAAW;AACb,WAAO,gBAAgB,gBAAgB,OAAO,KAAK;AACnD,IAAAA,MAAK,KAAK,cAAc,gBAAgB,KAAK,cAAc,QAAQ;AACnE,eAAW,QAAQ,CAAC,CAAC,MAAM,KAAK,MAAM;AACpC,MAAAA,IAAG,eAAe,MAAM,MAAM,KAAK;AAAA,IACrC,CAAC;AACD,SAAK,YAAYA,GAAE;AAAA,EACrB,OAAO;AACL,WAAOA,MAAK,gBAAgB,cAAc,QAAQ;AAAA,EACpD;AACA,EAAAA,IAAG,cAAc;AACjB,kBAAgB,KAAK,YAAY,IAAI;AACrC,QAAM,gBAAgB,cAAc,iBAAiBA,KAAI,aAAa;AACtE,QAAM,SAAyB,oBAAI,IAAI;AACvC,WAAS,MAAM,cAAc,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK;AACxD,UAAM,OAAO,cAAc,KAAK,CAAC;AACjC,QAAI,cAAc,SAAS,IAAI;AAC7B;AACF,WAAO,IAAI,MAAM,cAAc,iBAAiB,IAAI,CAAC;AAAA,EACvD;AACA,kBAAgB,KAAK,YAAY,IAAI;AACrC,wBAAsB,IAAI,KAAK,MAAM;AACrC,SAAO;AACT;AAEA,SAAS,aAAa,OAAO,cAAc,wBAAwB;AACjE,QAAM,YAA4B,oBAAI,IAAI;AAC1C,QAAM,UAAU,CAAC;AACjB,QAAM,aAA6B,oBAAI,IAAI;AAC3C,MAAI,wBAAwB;AAC1B,eAAW,QAAQ,wBAAwB;AACzC,cAAQ,IAAI;AAAA,IACd;AAAA,EACF,OAAO;AACL,aAAS,MAAM,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK;AAChD,YAAM,OAAO,MAAM,KAAK,CAAC;AACzB,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AACA,WAAS,MAAM,QAAQ,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK;AAClD,eAAW,IAAI,QAAQ,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,SAAS,UAAU,IAAI,MAAM,KAAK,CAAC;AAAA,EACjF;AACA,WAAS,QAAQ,MAAM;AACrB,UAAM,QAAQ,MAAM,iBAAiB,IAAI;AACzC,UAAM,WAAW,MAAM,oBAAoB,IAAI;AAC/C,UAAM,WAAW,KAAK,YAAY,GAAG;AACrC,UAAM,SAAS,WAAW,KAAK,KAAK,UAAU,GAAG,QAAQ,IAAI;AAC7D,QAAI,QAAQ;AACV,UAAI,MAAM,WAAW,IAAI,MAAM;AAC/B,UAAI,CAAC,KAAK;AACR,cAAsB,oBAAI,IAAI;AAC9B,mBAAW,IAAI,QAAQ,GAAG;AAAA,MAC5B;AACA,UAAI,IAAI,MAAM,CAAC,OAAO,QAAQ,CAAC;AAAA,IACjC;AACA,QAAI,aAAa,IAAI,IAAI,MAAM,SAAS,CAAC;AACvC;AACF,QAAI,QAAQ;AACV,cAAQ,KAAK,MAAM;AAAA,IACrB,OAAO;AACL,gBAAU,IAAI,MAAM,CAAC,OAAO,QAAQ,CAAC;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAAM,QAAQ,QAAQ,SAAS;AACpD,QAAM,EAAE,aAAa,wBAAwB,uBAAuB,IAAI;AACxE,QAAM,cAAc,OAAO;AAC3B,QAAM,gBAAgB,YAAY,iBAAiB,IAAI;AACvD,QAAM,eAAe,gBAAgB,MAAM,MAAM,OAAO;AACxD,0BAAwB,QAAQ,CAAC,GAAG,QAAQ;AAC1C,iBAAa,OAAO,GAAG;AAAA,EACzB,CAAC;AACD,QAAM,QAAQ,aAAa,eAAe,cAAc,sBAAsB;AAC9E,QAAM,OAAO,qBAAqB;AAClC,QAAM,OAAO,KAAK;AAClB,QAAM,OAAO,GAAG;AAChB,QAAM,OAAO,SAAS;AACtB,MAAI,QAAQ;AACV,UAAM,OAAO,UAAU;AACvB,UAAM,OAAO,YAAY;AACzB,UAAM,OAAO,cAAc;AAC3B,UAAM,OAAO,eAAe;AAC5B,UAAM,OAAO,aAAa;AAC1B,UAAM,OAAO,oBAAoB;AACjC,UAAM,OAAO,kBAAkB;AAC/B,UAAM,OAAO,qBAAqB;AAClC,UAAM,OAAO,mBAAmB;AAChC,UAAM,IAAI,cAAc,CAAC,cAAc,EAAE,CAAC;AAAA,EAC5C;AACA,MAAI,MAAM,IAAI,iBAAiB,IAAI,CAAC,MAAM,QAAQ;AAChD,WAAO,UAAU,IAAI,6BAA6B;AAAA,EACpD;AACA,MAAI,WAAW;AACb,QAAI,CAAC,MAAM,IAAI,cAAc;AAC3B,YAAM,IAAI,gBAAgB,CAAC,UAAU,EAAE,CAAC;AAC1C,SAAK,MAAM,IAAI,YAAY,IAAI,CAAC,MAAM,YAAY,MAAM,IAAI,YAAY,IAAI,CAAC,MAAM,aAAa,MAAM,IAAI,eAAe,IAAI,CAAC,MAAM,cAAc,KAAK,gBAAgB,KAAK,aAAa;AACvL,YAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,CAAC;AAAA,IACzC;AAAA,EACF;AACA,WAAS,MAAM,YAAY,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK;AACtD,gBAAY,eAAe,YAAY,KAAK,CAAC,CAAC;AAAA,EAChD;AACA,QAAM,QAAQ,CAAC,CAAC,OAAO,QAAQ,GAAG,SAAS;AACzC,gBAAY,YAAY,MAAM,OAAO,QAAQ;AAAA,EAC/C,CAAC;AACD,SAAO;AACT;AAEA,SAAS,eAAe,MAAM,QAAQ;AACpC,MAAI,kBAAkB,IAAI,KAAK,eAAe,IAAI,KAAK,gBAAgB,IAAI,GAAG;AAC5E,WAAO,aAAa,SAAS,KAAK,KAAK;AAAA,EACzC;AACF;AAEA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA;AAEF;AACA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AACF;AACA,SAAS,gBAAgB,MAAM,QAAQ,eAAe,SAAS,uBAAuB;AACpF,QAAM,EAAE,aAAa,iBAAiB,WAAW,iBAAiB,IAAI;AACtE,MAAI,CAAC,mBAAmB,CAAC;AACvB;AACF,WAAS,OAAO,aAAa;AAC3B,UAAM,gBAAgB,YAAY,iBAAiB,MAAM,WAAW;AACpE,QAAI,UAAU,cAAc,iBAAiB,SAAS;AACtD,QAAI,CAAC,WAAW,YAAY;AAC1B;AACF,4BAAwB,OAAO;AAC/B,cAAU,QAAQ,QAAQ,4BAA4B,EAAE;AACxD,UAAM,UAAU,CAAC,KAAK,CAAC;AACvB,UAAM,eAAe,gBAAgB,MAAM,aAAa,OAAO;AAC/D,sBAAkB,QAAQ,CAAC,GAAG,QAAQ;AACpC,mBAAa,OAAO,GAAG;AAAA,IACzB,CAAC;AACD,UAAM,QAAQ,aAAa,eAAe,cAAc,QAAQ,sBAAsB;AACtF,UAAM,OAAO,SAAS;AACtB,UAAM,OAAO,gBAAgB;AAC7B,QAAI,MAAM,IAAI,iBAAiB,IAAI,CAAC,MAAM,QAAQ;AAChD,aAAO,UAAU,IAAI,6BAA6B;AAAA,IACpD;AACA,UAAM,aAAa;AAAA,MACjB,aAAa,OAAO;AAAA,IACtB;AACA,UAAM,QAAQ,CAAC,CAAC,OAAO,QAAQ,GAAG,SAAS;AACzC,iBAAW,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,WAAW,gBAAgB,EAAE,GAAG;AAAA,IACtE,CAAC;AACD,QAAI,WAAW,WAAW;AACxB;AACF,QAAI;AACF,aAAO,YAAY,CAAC,OAAO,WAAW,GAAG,OAAO,EAAE,KAAK,GAAG;AAAA,IAC5D,SAAS,KAAK;AACZ,cAAQ,IAAI,KAAK,6BAA6B,GAAG;AACjD;AAAA,IACF;AACA,UAAM,UAAU,WAAW,KAAK,MAAM;AACtC,QAAI,aAAa,UAAU,IAAI,OAAO;AACtC,QAAI,CAAC,YAAY;AACf,mBAAa,CAAC;AACd,gBAAU,IAAI,SAAS,UAAU;AAAA,IACnC;AACA,eAAW,KAAK,IAAI,QAAQ,CAAC,CAAC,GAAG,WAAW,EAAE;AAAA,EAChD;AACA,gBAAc,QAAQ,MAAM;AAC5B,MAAI;AACF,2BAAuB,QAAQ,MAAM;AACzC;AAEA,IAAM,qBAAqC,oBAAI,IAAI;AAAA,EACjD;AAAA;AAEF,CAAC;AACD,eAAe,gBAAgB,MAAM,QAAQ,OAAO,SAAS,uBAAuB;AAClF,MAAI,cAAc,KAAK,MAAM,eAAe,KAAK,KAAK,gBAAgB,KAAK;AACzE;AACF,MAAI,QAAQ,UAAU,CAAC,QAAQ,OAAO,KAAK;AACzC;AACF,MAAI,mBAAmB,IAAI,OAAO,QAAQ,KAAK,mBAAmB,IAAI,MAAM,QAAQ,GAAG;AACrF,YAAQ,yBAAyB;AAAA,EACnC,OAAO;AACL,YAAQ,yBAAyB,QAAQ;AAAA,EAC3C;AACA,QAAM,cAAc,MAAM,UAAU,OAAO,SAAS,OAAO,qBAAqB;AAChF,MAAI,QAAQ,SAAS,uBAAuB,GAAG;AAC7C,0BAAsB,MAAM,WAAW;AAAA,EACzC;AACA,SAAO,YAAY,WAAW;AAChC;AACA,eAAe,gBAAgB,MAAM,QAAQ,SAAS,uBAAuB;AAC3E,MAAI,aAAa,KAAK;AACtB,MAAI,cAAc,IAAI,GAAG;AACvB,QAAI,KAAK,YAAY;AACnB,mBAAa,KAAK,YAAY;AAC9B,cAAQ,YAAY,KAAK,KAAK,UAAU;AAAA,IAC1C;AAAA,EACF;AACA,WAAS,QAAQ,YAAY,OAAO,QAAQ,MAAM,aAAa;AAC7D,QAAI,cAAc,KAAK;AACrB;AACF,QAAI,cAAc,KAAK,KAAK,cAAc,KAAK,KAAK,OAAO,MAAM,kBAAkB,YAAY;AAC7F,YAAM,QAAQ,MAAM,cAAc;AAClC,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAM,gBAAgB,MAAM,QAAQ,MAAM,CAAC,GAAG,SAAS,qBAAqB;AAAA,MAC9E;AAAA,IACF,OAAO;AACL,YAAM,gBAAgB,MAAM,QAAQ,OAAO,SAAS,qBAAqB;AAAA,IAC3E;AAAA,EACF;AACF;AACA,SAAS,sBAAsB,MAAM,aAAa;AAChD,MAAI,CAAC,kBAAkB,IAAI,KAAK,CAAC,kBAAkB,WAAW;AAC5D;AACF,QAAM,EAAE,WAAW,WAAW,IAAI;AAClC,MAAI,CAAC,aAAa,CAAC,YAAY;AAC7B;AAAA,EACF;AACA,QAAM,EAAE,UAAU,IAAI,YAAY;AAClC,QAAM,SAAS,IAAI,UAAU,SAAS;AACtC,QAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACvB,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO,cAAc,CAAC,YAAY,CAAC,SAAS;AAC5C,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO,IAAI;AACX,cAAY,MAAM,YAAY,OAAO,SAAS;AAChD;AACA,SAAS,yBAAyB,QAAQ,SAAS;AACjD,QAAM,EAAE,iBAAiB,OAAO,QAAQ,OAAO,OAAO,IAAI;AAC1D,QAAM,cAAc,OAAO;AAC3B,MAAI;AACF,gBAAY,YAAY,oBAAoB,iBAAiB,WAAW;AAC1E,MAAI;AACF,gBAAY,YAAY,SAAS,GAAG,KAAK,MAAM,WAAW;AAC5D,MAAI;AACF,gBAAY,YAAY,UAAU,GAAG,MAAM,MAAM,WAAW;AAC9D,MAAI,QAAQ;AACV,eAAW,QAAQ,OAAQ,aAAY,IAAI,IAAI,OAAO,IAAI;AAAA,EAC5D;AACF;AACA,IAAM,sBAAsB;AAC5B,eAAe,UAAU,MAAM,SAAS,SAAS,OAAO,uBAAuB;AAC7E,QAAM,EAAE,eAAe,aAAa,cAAc,gBAAgB,IAAI;AACtE,MAAI,iBAAiB,WAAW,IAAI,GAAG;AACrC,QAAI,yBAAyB,KAAK,KAAK,KAAK,IAAI,GAAG;AACjD,4BAAsB,KAAK,IAAI;AAAA,IACjC;AACA,WAAO,cAAc,eAAe,KAAK,IAAI;AAAA,EAC/C;AACA,MAAI,iBAAiB,eAAe,cAAc,IAAI,MAAM,kBAAkB,IAAI,KAAK,iBAAiB,IAAI,IAAI;AAC9G,UAAM,UAAU,MAAM,aAAa,MAAM,OAAO;AAChD,QAAI,QAAQ,SAAS,0BAA0B,GAAG;AAChD,YAAM,QAAQ,QAAQ,kBAAkB;AACxC,eAAS,MAAM,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK;AAChD,cAAM,OAAO,MAAM,CAAC;AACpB,YAAI,CAAC,oBAAoB,KAAK,IAAI,GAAG;AACnC,kBAAQ,gBAAgB,IAAI;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AACA,UAAM,QAAQ,QAAQ,mBAAmB,cAAc,MAAM,SAAS,QAAQ,OAAO;AACrF,QAAI;AACF,+BAAyB,SAAS,OAAO;AAC3C,QAAI,gBAAgB;AACpB,QAAI,QAAQ,SAAS,eAAe,GAAG;AACrC,YAAM,WAAW;AAAA,QACf,MAAM,IAAI,YAAY,IAAI,CAAC;AAAA,QAC3B,MAAM,IAAI,YAAY,IAAI,CAAC;AAAA,MAC7B;AACA,sBAAgB,SAAS,SAAS,QAAQ,MAAM,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,SAAS,OAAO,KAAK,eAAe,KAAK,gBAAgB,KAAK,cAAc,KAAK;AAAA,IAClL;AACA,UAAM,gBAAgB,MAAM,IAAI,gBAAgB,IAAI,CAAC;AACrD,UAAM,WAAW,gBAAgB,MAAM,IAAI,aAAa,IAAI,CAAC,CAAC;AAC9D,UAAM,yBAAyB,WAAW,CAAC,SAAS;AAClD,UAAI,kBAAkB,aAAa;AACjC,eAAO,KAAK,YAAY;AAAA,MAC1B,WAAW,kBAAkB,aAAa;AACxC,eAAO,KAAK,YAAY;AAAA,MAC1B,WAAW,kBAAkB,cAAc;AACzC,eAAO,KAAK,CAAC,EAAE,YAAY,IAAI,KAAK,UAAU,CAAC;AAAA,MACjD;AACA,eAAS,QAAQ,CAAC,WAAW;AAC3B,YAAI,aAAa,aAAa,IAAI,MAAM;AACxC,YAAI,CAAC,YAAY;AACf,uBAAa,IAAI,QAAQ,aAA6B,oBAAI,IAAI,CAAC;AAAA,QACjE;AACA,aAAK,MAAM,EAAE,EAAE,QAAQ,CAAC,SAAS,WAAW,IAAI,IAAI,CAAC;AAAA,MACvD,CAAC;AAAA,IACH,IAAI;AACJ;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,mBAAe,MAAM,OAAO;AAC5B,QAAI,CAAC,eAAe,IAAI,GAAG;AACzB,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,kBAAkB,OAAO;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,SAAS,KAAK,UAAU,KAAK;AACnC,QAAM,gBAAgB,MAAM,QAAQ,OAAO;AAC3C,QAAM,kBAAkB,MAAM;AAC9B,SAAO;AACT;AAEA,SAAS,eAAe,SAAS;AAC/B,UAAQ,gBAAgB;AACxB,UAAQ,cAAc;AACtB,UAAQ,kBAAkB;AAC1B,UAAQ,iBAAiB;AACzB,UAAQ,UAAU,MAAM;AACxB,UAAQ,sBAAsB,MAAM;AACpC,MAAI,QAAQ,SAAS;AACnB,QAAI;AACF,cAAQ,QAAQ,OAAO;AAAA,IACzB,SAAS,KAAK;AACZ,cAAQ,IAAI,KAAK,4BAA4B,GAAG;AAAA,IAClD;AACA,YAAQ,UAAU;AAAA,EACpB;AACA,UAAQ,UAAU,CAAC;AACnB,UAAQ,aAAa,MAAM;AAC3B,UAAQ,aAAa,MAAM;AAC3B,UAAQ,SAAS,MAAM;AACvB,UAAQ,QAAQ,CAAC;AACjB,UAAQ,cAAc,CAAC;AACzB;AAEA,SAAS,UAAU,SAAS;AAC1B,QAAM,EAAE,KAAK,SAAS,cAAc,GAAG,YAAY,IAAI;AACvD,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO,IAAI;AACxE,SAAO,MAAM,KAAK,EAAE,QAAQ,WAAW,QAAQ,GAAG,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa;AAClF,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,kCAAkC,EAAE,OAAO,SAAS,CAAC;AAAA,IACvE;AACA,YAAQ,cAAc;AAAA,MACpB,KAAK;AACH,eAAO,SAAS,YAAY;AAAA,MAC9B,KAAK;AACH,eAAO,SAAS,KAAK,EAAE,KAAK,aAAa;AAAA,MAC3C,KAAK;AAAA,MACL;AACE,eAAO,SAAS,KAAK;AAAA,IACzB;AAAA,EACF,CAAC,EAAE,QAAQ,MAAM,aAAa,KAAK,CAAC;AACtC;AACA,SAAS,aAAa,SAAS,SAAS;AACtC,QAAM,EAAE,KAAK,QAAQ,cAAc,QAAQ,eAAe,QAAQ,SAAS,IAAI;AAC/E,MAAI,MAAM;AACV,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,gBAAgB,YAAY,aAAa,aAAa;AACxD,YAAQ;AAAA,EACV;AACA,MAAI,UAAU,SAAS,IAAI,MAAM;AACjC,MAAI,CAAC,SAAS;AACZ,QAAI,gBAAgB;AAClB,UAAI,0BAA0B,UAAU,eAAe,KAAK,GAAG,GAAG;AAChE,gBAAQ,KAAK,KAAK,GAAG,IAAI,MAAM,QAAwB,oBAAI,KAAK,GAAG,QAAQ;AAAA,MAC7E;AAAA,IACF;AACA,UAAM,gBAAgB,YAAY,WAAW,MAAM,KAAK,QAAQ,KAAK;AACrE,UAAM,YAA4B,oBAAI,IAAI;AAC1C,QAAI,eAAe;AACjB,YAAM,WAAW,YAAY,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG;AACpD,eAAS,QAAQ,CAAC,WAAW;AAC3B,YAAI,CAAC,aAAa,IAAI,MAAM;AAC1B;AACF,qBAAa,IAAI,MAAM,EAAE,QAAQ,CAAC,SAAS,UAAU,IAAI,IAAI,CAAC;AAAA,MAChE,CAAC;AAAA,IACH;AACA,UAAM,iBAAiB,iBAAiB,UAAU;AAClD,UAAM,mBAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA,cAAc,iBAAiB,gBAAgB;AAAA,MAC/C,SAAS,gBAAgB,UAAU,EAAE,QAAQ,cAAc,IAAI;AAAA,MAC/D,GAAG;AAAA,IACL;AACA,cAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ;AACA,YAAQ,YAAY,YAAY;AAC9B,UAAI,WAAW,gBAAgB,SAAS;AACtC,cAAM,SAAS,MAAM,QAAQ,MAAM;AACnC,YAAI;AACF,iBAAO;AAAA,MACX;AACA,UAAI,CAAC,aAAa,OAAO,WAAW,MAAM,KAAK,QAAQ,QAAQ;AAC7D,eAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,gBAAM,SAAS,QAAQ,SAAS,OAAO,QAAQ,SAAS,CAAC;AACzD,iBAAO,YAAY,EAAE,QAAQ,GAAG,iBAAiB,CAAC;AAClD,kBAAQ,UAAU;AAClB,kBAAQ,SAAS;AAAA,QACnB,CAAC;AAAA,MACH;AACA,aAAO,UAAU,gBAAgB;AAAA,IACnC,GAAG,EAAE,MAAM,CAAC,UAAU;AACpB,eAAS,OAAO,MAAM;AACtB,UAAI,gBAAgB,WAAW,kBAAkB;AAC/C,gBAAQ,IAAI,KAAK,iEAAiE,GAAG;AACrF,eAAO,OAAO,qBAAqB,WAAW,mBAAmB,iBAAiB,QAAQ;AAAA,MAC5F;AACA,YAAM;AAAA,IACR,CAAC;AACD,aAAS,IAAI,QAAQ,OAAO;AAAA,EAC9B;AACA,SAAO,QAAQ;AACjB;AAEA,eAAe,uBAAuB,SAAS,SAAS,SAAS,SAAS;AACxE,MAAI,CAAC,UAAU,OAAO;AACpB,WAAO;AACT,aAAW,CAAC,QAAQ,GAAG,KAAK,aAAa,SAAS,OAAO,GAAG;AAC1D,QAAI;AACF,YAAM,UAAU,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACE;AAAA,UACA,aAAa,UAAU,UAAU;AAAA,UACjC,cAAc;AAAA,QAChB;AAAA,MACF;AACA,gBAAU,QAAQ,QAAQ,KAAK,MAAM,GAAG,KAAK,OAAO,IAAI;AAAA,IAC1D,SAAS,OAAO;AACd,cAAQ,IAAI,KAAK,gCAAgC,QAAQ,KAAK;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AACA,SAAS,UAAU,SAAS;AAC1B,SAAO,4BAA4B,KAAK,OAAO;AACjD;AACA,IAAM,SAAS;AACf,SAAS,aAAa,SAAS,SAAS;AACtC,QAAM,SAAS,CAAC;AAChB,UAAQ,QAAQ,QAAQ,CAAC,KAAK,WAAW,QAAQ;AAC/C,WAAO,KAAK,CAAC,KAAK,WAAW,KAAK,OAAO,CAAC,CAAC;AAC3C,WAAO;AAAA,EACT,CAAC;AACD,SAAO,OAAO,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,GAAG,CAAC;AACjD;AACA,SAAS,KAAK,KAAK;AACjB,QAAM,UAAU,IAAI,QAAQ,4BAA4B,MAAM;AAC9D,SAAO,IAAI,OAAO,iBAAiB,OAAO,eAAe,GAAG;AAC9D;AAEA,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,SAAS,mBAAmB,OAAO,SAAS;AAC1C,SAAO,WAAW,IAAI,CAAC,aAAa;AAClC,UAAM,QAAQ,MAAM,iBAAiB,QAAQ;AAC7C,QAAI,CAAC,SAAS,UAAU,QAAQ;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,aAAa,YAAY;AAC3B,cAAQ;AAAA,IACV;AACA,WAAO,uBAAuB,OAAO,MAAM,SAAS,IAAI,EAAE,KAAK,CAAC,aAAa;AAC3E,UAAI,CAAC,YAAY,UAAU;AACzB;AACF,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,MAAM,oBAAoB,QAAQ;AAAA,MACpC;AAAA,IACF,CAAC;AAAA,EACH,CAAC,EAAE,OAAO,OAAO;AACnB;AAEA,SAAS,kBAAkB,QAAQ,SAAS;AAC1C,MAAI,eAAe,MAAM,GAAG;AAC1B,UAAM,cAAc,OAAO,cAAc,OAAO;AAChD,QAAI,CAAC,UAAU,WAAW,GAAG;AAC3B,aAAO;AAAA,QACL,aAAa,SAAS;AAAA,UACpB,KAAK;AAAA,UACL,UAAU;AAAA,UACV,aAAa;AAAA,UACb,cAAc;AAAA,QAChB,CAAC,EAAE,KAAK,CAAC,QAAQ;AACf,cAAI,CAAC;AACH;AACF,iBAAO,SAAS;AAChB,iBAAO,QAAQ,cAAc;AAC7B,iBAAO,MAAM,OAAO;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,aAAa,YAAY;AAC3B,cAAQ;AAAA,IACV;AAAA,EACF,WAAW,iBAAiB,MAAM,KAAK,CAAC,UAAU,OAAO,KAAK,OAAO,GAAG;AACtE,UAAM,cAAc,OAAO,KAAK;AAChC,WAAO;AAAA,MACL,aAAa,SAAS;AAAA,QACpB,KAAK;AAAA,QACL,UAAU;AAAA,QACV,aAAa;AAAA,QACb,cAAc;AAAA,MAChB,CAAC,EAAE,KAAK,CAAC,QAAQ;AACf,YAAI,CAAC;AACH;AACF,eAAO,QAAQ,cAAc;AAC7B,eAAO,KAAK,UAAU,OAAO;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,CAAC;AACV;AAEA,SAAS,YAAY,QAAQ,SAAS;AACpC,QAAM,EAAE,eAAe,eAAe,IAAI;AAC1C,QAAM,OAAO,OAAO,aAAa,MAAM,KAAK,OAAO,aAAa,YAAY;AAC5E,MAAI,CAAC;AACH,WAAO,CAAC;AACV,QAAM,CAAC,QAAQ,EAAE,IAAI,KAAK,MAAM,GAAG;AACnC,MAAI,IAAI;AACN,UAAM,QAAQ,IAAI,EAAE;AACpB,UAAM,aAAa,QAAQ,YAAY;AAAA,MACrC,CAAC,KAAK,SAAS;AACb,eAAO,OAAO,KAAK,cAAc,OAAO,KAAK,EAAE;AAAA,MACjD;AAAA,MACA,eAAe,cAAc,OAAO,KAAK,EAAE;AAAA,IAC7C;AACA,QAAI,QAAQ;AACV,aAAO,aAAa,QAAQ,KAAK;AAAA,IACnC;AACA,QAAI,gBAAgB,cAAc,KAAK;AACrC,aAAO,CAAC;AACV,QAAI,YAAY;AACd,sBAAgB,YAAY,WAAW,UAAU,IAAI,CAAC;AACtD,aAAO,CAAC;AAAA,IACV,WAAW,QAAQ;AACjB,aAAO;AAAA,QACL,aAAa,SAAS;AAAA,UACpB,KAAK;AAAA,UACL,cAAc;AAAA,QAChB,CAAC,EAAE,KAAK,CAAC,YAAY;AACnB,0BAAgB,mBAAmB,aAAa,OAAO;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC;AACV;AAEA,SAAS,UAAU,QAAQ,SAAS;AAClC,QAAM,EAAE,MAAM,IAAI;AAClB,MAAI,cAAc,MAAM,GAAG;AACzB,QAAI,eAAe,MAAM,KAAK,sBAAsB,MAAM,GAAG;AAC3D,YAAM,KAAK,GAAG,kBAAkB,QAAQ,OAAO,CAAC;AAAA,IAClD;AACA,QAAI,oBAAoB,MAAM,GAAG;AAC/B,YAAM,KAAK,GAAG,YAAY,QAAQ,OAAO,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,MAAI,kBAAkB,MAAM,GAAG;AAC7B,UAAM,KAAK,GAAG,mBAAmB,OAAO,OAAO,OAAO,CAAC;AAAA,EACzD;AACA,SAAO,WAAW,QAAQ,CAAC,UAAU;AACnC,cAAU,OAAO,OAAO;AAAA,EAC1B,CAAC;AACH;AAEA,eAAe,aAAa,OAAO,SAAS;AAC1C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,aAAa,MAAM;AAC5D;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,SAAS;AACxB,UAAM,UAAU,sBAAsB,KAAK,SAAS,OAAO;AAC3D,oBAAgB,YAAY,cAAc,eAAe,GAAG,OAAO;AAAA,CACtE,CAAC;AAAA,EACA,OAAO;AACL,UAAM,cAAc,MAAM,KAAK,cAAc,WAAW,EAAE,OAAO,CAAC,eAAe;AAC/E,UAAI;AACF,eAAO,cAAc,cAAc,QAAQ,WAAW,SAAS,MAAM;AAAA,MACvE,SAAS,OAAO;AACd,gBAAQ,IAAI,KAAK,sCAAsC,WAAW,IAAI,IAAI,KAAK;AAC/E,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AACD,UAAM,UAAU,cAAc,eAAe,mBAAmB,EAAE;AAClE,UAAM,cAAc,QAAQ,cAAc,OAAO;AACjD,YAAQ,KAAK,YAAY,WAAW;AACpC,UAAM,iBAAiB,YAAY;AACnC,UAAM,QAAQ;AAAA,MACZ,YAAY,QAAQ,CAAC,eAAe;AAClC,eAAO,MAAM,KAAK,WAAW,QAAQ,EAAE,IAAI,OAAO,YAAY;AAC5D,cAAI,gBAAgB,OAAO,GAAG;AAC5B,kBAAM,UAAU,QAAQ;AACxB,gBAAI,UAAU;AACd,gBAAI;AACF,wBAAU,MAAM,aAAa,SAAS;AAAA,gBACpC,KAAK;AAAA,gBACL,aAAa;AAAA,gBACb,cAAc;AAAA,cAChB,CAAC;AAAA,YACH,SAAS,OAAO;AACd,sBAAQ,IAAI,KAAK,sCAAsC,OAAO,IAAI,KAAK;AAAA,YACzE;AACA,kBAAM,kBAAkB,QAAQ;AAAA,cAC9B;AAAA,cACA,CAAC,KAAK,WAAW,QAAQ,IAAI,QAAQ,KAAK,WAAW,KAAK,OAAO,CAAC;AAAA,YACpE;AACA,uBAAW,QAAQ,SAAS,eAAe,GAAG;AAC5C,kBAAI;AACF,+BAAe,WAAW,MAAM,eAAe,SAAS,MAAM;AAAA,cAChE,SAAS,OAAO;AACd,wBAAQ,IAAI,KAAK,+CAA+C,EAAE,MAAM,MAAM,CAAC;AAAA,cACjF;AAAA,YACF;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AACA,QAAI,eAAe,SAAS;AAC1B,kBAAY,KAAK,cAAc;AACjC,UAAM,WAAW,CAAC;AAClB,gBAAY,QAAQ,CAAC,UAAU;AAC7B,sBAAgB,MAAM,UAAU,QAAQ;AAAA,IAC1C,CAAC;AACD,aAAS,OAAO,CAAC,YAAY,kBAAkB,OAAO,KAAK,UAAU,QAAQ,MAAM,iBAAiB,KAAK,CAAC,KAAK,gBAAgB,QAAQ,MAAM,iBAAiB,aAAa,CAAC,GAAG,KAAK,CAAC,QAAQ,aAAa,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU;AACtO,YAAM,OAAO;AACb,YAAM,UAAU,aAAa,IAAI,KAAK,OAAO;AAC7C,UAAI,SAAS;AACX,wBAAgB,YAAY,cAAc,eAAe,GAAG,OAAO;AAAA,CAC1E,CAAC;AAAA,MACI,OAAO;AACL,cAAM;AAAA,UACJ;AAAA,YACE,KAAK;AAAA,YACL,KAAK,mBAAmB,KAAK,iBAAiB,OAAO;AAAA,YACrD;AAAA,UACF,EAAE,KAAK,CAAC,aAAa;AACnB,uBAAW,sBAAsB,UAAU,OAAO;AAClD,yBAAa,IAAI,KAAK,SAAS,QAAQ;AACvC,4BAAgB,YAAY,cAAc,eAAe,GAAG,QAAQ;AAAA,CAC/E,CAAC;AAAA,UACQ,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AACA,IAAM,cAAc;AACpB,IAAM,eAAe;AACrB,SAAS,SAAS,QAAQ;AACxB,MAAI,UAAU;AACZ,WAAO,CAAC;AACV,QAAM,SAAS,CAAC;AAChB,MAAI,UAAU,OAAO,QAAQ,aAAa,EAAE;AAC5C,SAAO,MAAM;AACX,UAAM,UAAU,aAAa,KAAK,OAAO;AACzC,QAAI,CAAC;AACH;AACF,WAAO,KAAK,QAAQ,CAAC,CAAC;AAAA,EACxB;AACA,YAAU,QAAQ,QAAQ,cAAc,EAAE;AAC1C,QAAM,YAAY;AAClB,QAAM,aAAa,IAAI;AAAA;AAAA,IAErB;AAAA,IACA;AAAA,EACF;AACA,SAAO,MAAM;AACX,QAAI,UAAU,UAAU,KAAK,OAAO;AACpC,QAAI,CAAC,SAAS;AACZ,gBAAU,WAAW,KAAK,OAAO;AACjC,UAAI,CAAC,SAAS;AACZ;AAAA,MACF,OAAO;AACL,kBAAU,YAAY,WAAW;AAAA,MACnC;AAAA,IACF,OAAO;AACL,iBAAW,YAAY,UAAU;AAAA,IACnC;AACA,WAAO,KAAK,QAAQ,CAAC,CAAC;AAAA,EACxB;AACA,SAAO;AACT;AACA,IAAM,qBAAqB;AAC3B,IAAM,cAAc;AACpB,SAAS,sBAAsB,KAAK,SAAS;AAC3C,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,kBAAkB,OAAO,MAAM,kBAAkB;AACvD,SAAO,kBAAkB,IAAI,QAAQ,aAAa,CAAC,UAAU;AAC3D,WAAO,MAAM;AACX,YAAM,CAAC,KAAK,EAAE,MAAM,IAAI,mBAAmB,KAAK,KAAK,KAAK,CAAC;AAC3D,UAAI,CAAC;AACH,eAAO;AACT,UAAI,WAAW;AACb,eAAO,QAAQ,GAAG;AAAA,IACtB;AAAA,EACF,CAAC,IAAI;AACP;AACA,SAAS,gBAAgB,OAAO,MAAM,CAAC,GAAG;AACxC,aAAW,QAAQ,MAAM,KAAK,KAAK,GAAG;AACpC,QAAI,iBAAiB,IAAI,GAAG;AAC1B,UAAI,KAAK,GAAG,gBAAgB,KAAK,QAAQ,CAAC;AAAA,IAC5C,WAAW,cAAc,MAAM;AAC7B,sBAAgB,KAAK,UAAU,GAAG;AAAA,IACpC,OAAO;AACL,UAAI,KAAK,IAAI;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,8BAA8B;AACpC,SAAS,wBAAwBC,MAAK;AACpC,SAAO,4BAA4B,KAAKA,KAAI,SAAS;AACvD;AACA,eAAe,sBAAsB,MAAM,SAAS;AAClD,QAAM,UAAU,MAAM,gBAAgB,MAAM,OAAO;AACnD,MAAI,cAAc,QAAQ,IAAI,KAAK,iBAAiB,QAAQ,IAAI,KAAK,CAAC,wBAAwB,QAAQ,IAAI;AACxG,WAAO,QAAQ;AACjB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,KAAK,YAAY;AACrB,QAAM,QAAQ,MAAM,UAAU,QAAQ,MAAM,SAAS,IAAI;AACzD,MAAI,mBAAmB,eAAe;AACpC,QAAI,aAAa;AACjB,cAAU,QAAQ,CAAC,SAAS,YAAY;AACtC,oBAAc,GAAG,QAAQ,KAAK,KAAK,CAAC;AAAA,IACtC,OAAO;AAAA;AAAA;AAAA,IAGP,CAAC;AACD,oBAAgB,YAAY,cAAc,eAAe,UAAU,CAAC;AAAA,EACtE;AACA,MAAI,QAAQ,YAAY;AACxB,QAAM,cAAc,KAAK;AACzB,MAAI,SAAS,SAAS,cAAc,KAAK,GAAG;AAC1C,QAAI,KAAK,gBAAgB;AACzB,UAAM,aAAa,OAAO,OAAO;AACjC,QAAI,QAAQ,gBAAgB;AAAA,EAC9B;AACA,MAAI,KAAK,YAAY;AACrB,YAAU,OAAO,OAAO;AACxB,QAAM,QAAQ,MAAM;AACpB,MAAIC,WAAU;AACd,QAAM,UAAU,YAAY;AAC1B,WAAO,MAAM;AACX,YAAM,OAAO,MAAM,IAAI;AACvB,UAAI,CAAC;AACH;AACF,UAAI;AACF,cAAM;AAAA,MACR,SAAS,OAAO;AACd,gBAAQ,IAAI,KAAK,sBAAsB,KAAK;AAAA,MAC9C;AACA,iBAAW,EAAEA,UAAS,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,aAAWA,UAAS,KAAK;AACzB,QAAM,QAAQ,IAAI,CAAC,GAAG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC;AAC7D,MAAI,QAAQ,YAAY;AACxB,QAAM,cAAc,KAAK;AACzB,QAAMD,OAAM,uBAAuB,OAAO,OAAO;AACjD,oBAAkBA,KAAI,aAAa,gBAAgBA,KAAI,SAAS,CAAC,CAAC;AAClE,qBAAmBA,KAAI,aAAa,iBAAiBA,KAAI,SAAS,CAAC,CAAC;AACpE,kBAAgB,eAAe,OAAO;AACtC,QAAM,2BAA2BA,IAAG;AACpC,SAAOA;AACT;AACA,SAAS,uBAAuB,OAAO,SAAS;AAC9C,QAAM,EAAE,OAAO,OAAO,IAAI;AAC1B,QAAMA,OAAM,UAAU,OAAO,QAAQ,MAAM,aAAa;AACxD,QAAM,gBAAgBA,KAAI,cAAc,gBAAgBA,KAAI,cAAc,eAAe;AACzF,gBAAc,eAAe,MAAM,KAAK,IAAI;AAC5C,gBAAc,eAAe,MAAM,KAAK,IAAI;AAC5C,gBAAc,eAAe,MAAM,SAAS,MAAM;AAClD,gBAAc,eAAe,MAAM,UAAU,MAAM;AACnD,gBAAc,OAAO,KAAK;AAC1B,EAAAA,KAAI,YAAY,aAAa;AAC7B,SAAOA;AACT;AAEA,eAAe,YAAY,MAAM,SAAS;AACxC,QAAM,UAAU,MAAM,gBAAgB,MAAM,OAAO;AACnD,QAAMA,OAAM,MAAM,sBAAsB,OAAO;AAC/C,QAAM,UAAU,aAAaA,MAAK,QAAQ,SAAS,wBAAwB,CAAC;AAC5E,MAAI,CAAC,QAAQ,cAAc;AACzB,YAAQ,kBAAkB,mBAAmB,QAAQ,aAAa;AAClE,YAAQ,iBAAiB,QAAQ,eAAe,gBAAgB,OAAO,MAAM;AAC7E,YAAQ,UAAU,MAAM;AAAA,EAC1B;AACA,QAAM,QAAQ,YAAY,SAASA,KAAI,aAAa;AACpD,SAAO,MAAM,cAAc,OAAO,OAAO;AAC3C;AAuBA,eAAe,aAAa,MAAM,SAAS;AACzC,QAAM,UAAU,MAAM,gBAAgB,MAAM,OAAO;AACnD,QAAM,EAAE,KAAK,SAAS,MAAM,IAAI,IAAI;AACpC,QAAM,SAAS,MAAM,YAAY,OAAO;AACxC,MAAI,KAAK,oBAAoB;AAC7B,MAAI,UAAU,OAAO,UAAU,MAAM,OAAO;AAC5C,MAAI,CAAC,aAAa,YAAY,EAAE,SAAS,IAAI,KAAK,OAAO,gBAAgB,cAAc;AACrF,UAAM,CAAC,QAAQ,IAAI,IAAI,QAAQ,MAAM,GAAG;AACxC,QAAI,eAAe;AACnB,QAAI,gBAAgB;AACpB,QAAI,SAAS,aAAa;AACxB,YAAM,WAAW,2BAA2B,IAAI;AAChD,UAAI,YAAY,GAAG;AACjB,uBAAe,KAAK,MAAM,WAAW,MAAM,CAAC,IAAI;AAChD,wBAAgB;AAAA,MAClB,OAAO;AACL,uBAAe,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF,WAAW,SAAS,cAAc;AAChC,qBAAe,KAAK,IAAI;AAAA,IAC1B;AACA,UAAM,eAAe,KAAK,UAAU,GAAG,YAAY;AACnD,UAAM,aAAa,KAAK,UAAU,YAAY;AAC9C,UAAM,cAAc,OAAO,KAAK,YAAY;AAC5C,UAAM,aAAa,IAAI,WAAW,YAAY,MAAM;AACpD,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,iBAAW,CAAC,IAAI,YAAY,WAAW,CAAC;AAAA,IAC1C;AACA,UAAM,aAAa,SAAS,cAAc,aAAa,YAAY,KAAK,aAAa,IAAI,cAAc,YAAY,GAAG;AACtH,UAAM,eAAe,OAAO,KAAK,OAAO,aAAa,GAAG,UAAU,CAAC;AACnE,cAAU,CAAC,QAAQ,KAAK,cAAc,UAAU,EAAE,KAAK,EAAE;AAAA,EAC3D;AACA,MAAI,QAAQ,oBAAoB;AAChC,SAAO;AACT;AAuCA,eAAe,SAAS,MAAM,SAAS;AACrC,SAAO;AAAA,IACL,MAAM,gBAAgB,MAAM,EAAE,GAAG,SAAS,MAAM,YAAY,CAAC;AAAA,EAC/D;AACF;;;AC/nDA,IAAM,aAAa;AAAA,EACjB;AAAA,EAAW;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EACpD;AAAA,EAAS;AAAA,EAAoB;AAAA,EAAa;AAAA,EAAe;AAAA,EACzD;AAAA,EAAU;AAAA,EAAiB;AAAA,EAAc;AAAA,EAAQ;AAAA,EACjD;AAAA,EAAc;AAAA,EAAe;AAC/B;AAGO,SAAS,sBAAsBE,KAA6B;AACjE,QAAM,OAAOA,IAAG,UAAU,SAAS,MAAOA,IAAG,UAAU,MAAM,GAAG,GAAI,IAAI,WAAMA,IAAG;AACjF,QAAM,KAAK,iBAAiBA,GAAE;AAC9B,QAAM,SAAiC,CAAC;AACxC,aAAW,KAAK,YAAY;AAC1B,UAAM,IAAI,GAAG,iBAAiB,CAAC;AAC/B,QAAI,EAAG,QAAO,CAAC,IAAI,EAAE,KAAK;AAAA,EAC5B;AACA,SAAO,EAAE,MAAM,OAAO;AACxB;AAGA,IAAM,kBAAkB;AAGxB,SAAS,YAAe,GAAe,IAAoC;AACzE,SAAO,QAAQ,KAAK,CAAC,GAAG,IAAI,QAAmB,CAAC,YAAY,WAAW,MAAM,QAAQ,MAAS,GAAG,EAAE,CAAC,CAAC,CAAC;AACxG;AAQA,eAAe,aAA4B;AACzC,MAAI;AACF,UAAM,QAAS,SAAgD;AAC/D,QAAI,CAAC,OAAO,MAAO;AACnB,UAAM,QAAQ,KAAK;AAAA,MACjB,MAAM;AAAA,MACN,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,IACzD,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;AAGA,SAAS,cAAc,MAAqB;AAC1C,MAAI,EAAE,gBAAgB,SAAU,QAAO;AACvC,MAAI,KAAK,OAAO,aAAc,QAAO;AACrC,MAAI,KAAK,aAAa,mBAAmB,EAAG,QAAO;AACnD,SAAO;AACT;AAMA,eAAsB,kBAAkBA,KAA0C;AAChF,MAAI;AACF,UAAM,WAAW;AACjB,WAAO,MAAM;AAAA,MACX,SAASA,KAAmB;AAAA,QAC1B,OAAO,KAAK,IAAI,OAAO,oBAAoB,GAAG,CAAC;AAAA,QAC/C,iBAAiB,iBAAiB,SAAS,IAAI,EAAE,mBAAmB;AAAA,QACpE,SAAS;AAAA,QACT,QAAQ;AAAA,MACV,CAAC;AAAA,MACD,kBAAkB;AAAA,IACpB;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,KAAK,qCAAqC,GAAG;AACrD,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,wBAAwB,MAA+C;AAC3F,MAAI;AACF,UAAM,WAAW;AACjB,UAAM,QAAQ,KAAK,IAAI,OAAO,oBAAoB,GAAG,CAAC;AAKtD,UAAM,YAAY,gBAAgB,IAAI;AACtC,UAAM,SAAS,UAAU,sBAAsB;AAC/C,UAAM,OAAO,MAAM;AAAA,MACjB,SAAS,WAAW;AAAA,QAClB;AAAA,QACA,iBAAiB,iBAAiB,SAAS,IAAI,EAAE,mBAAmB;AAAA,QACpE,SAAS;AAAA,QACT,QAAQ;AAAA,MACV,CAAC;AAAA,MACD,kBAAkB;AAAA,IACpB;AACA,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,SAAS,MAAM,KAAK,SAAS,iBAAiB,qBAAqB,CAAC,EAAE;AAAA,MAAI,CAAC,MAC9E,EAAc,sBAAsB;AAAA,IACvC;AACA,WAAO,MAAM,WAAW,MAAM,MAAM,OAAO,MAAM,OAAO,KAAK,OAAO,MAAM;AAAA,EAC5E,SAAS,KAAK;AACZ,YAAQ,KAAK,iCAAiC,GAAG;AACjD,WAAO;AAAA,EACT;AACF;AAGA,SAAS,gBAAgB,MAA+B;AACtD,QAAM,KAAK,KAAK,IAAI,KAAK,IAAI;AAC7B,QAAM,KAAK,KAAK,IAAI,KAAK,IAAI;AAC7B,MAAI,OAAO,SAAS,iBAAiB,IAAI,EAAE;AAC3C,MAAI,QAAQ,KAAK,QAAQ,aAAa,EAAG,QAAO;AAChD,QAAM,SAAS,CAAC,MACd,EAAE,QAAQ,KAAK,KAAK,EAAE,OAAO,KAAK,KAAK,EAAE,SAAS,KAAK,IAAI,KAAK,KAAK,EAAE,UAAU,KAAK,IAAI,KAAK;AACjG,SAAO,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,iBAAiB;AAC1E,QAAI,OAAO,KAAK,sBAAsB,CAAC,EAAG,QAAO;AACjD,WAAO,KAAK;AAAA,EACd;AACA,SAAO,SAAS;AAClB;AAWA,SAAS,oBAA4B;AACnC,QAAM,KAAW,OAAe;AAChC,MAAI,CAAC,IAAI,gBAAiB,QAAO;AACjC,aAAW,KAAK,CAAC,yBAAyB,yBAAyB,YAAY,GAAG;AAChF,QAAI,GAAG,gBAAgB,CAAC,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAEA,SAASC,eAAc,MAA6B;AAClD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,IAAI,IAAI,WAAW;AACzB,MAAE,SAAS,MAAM,QAAQ,OAAO,EAAE,MAAM,CAAC;AACzC,MAAE,UAAU,MAAM,OAAO,EAAE,KAAK;AAChC,MAAE,cAAc,IAAI;AAAA,EACtB,CAAC;AACH;AAGO,SAAS,cAAc,MAA6B;AACzD,SAAOA,eAAc,IAAI;AAC3B;AAGO,SAAS,eAAe,MAA6C;AAC1E,UAAQ,QAAQ,IAAI,WAAW,QAAQ,IAAI,UAAU;AACvD;AAUA,eAAsB,uBAAuB,MAAkB,MAAmD;AAChH,QAAM,KAAK,UAAU;AAGrB,MAAI,CAAC,IAAI,mBAAmB,CAAE,OAAe,cAAe,QAAO;AAEnE,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,GAAG,gBAAgB,EAAE,OAAO,EAAE,WAAW,GAAG,GAAG,OAAO,OAAO,kBAAkB,KAAK,CAAQ;AAAA,EAC7G,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,MAAM,cAAc,QAAQ,MAAM,IAAI;AAAA,EAC/C,SAAS,KAAK;AACZ,YAAQ,KAAK,mCAAmC,GAAG;AACnD,WAAO;AAAA,EACT,UAAE;AACA,WAAO,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,EAC5C;AACF;AAEA,eAAe,cAAc,QAAqB,MAAkB,MAAmD;AACrH,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,YAAY;AAClB,QAAM,QAAQ;AACd,EAAC,MAAc,cAAc;AAC7B,QAAM,MAAM,KAAK,EAAE,MAAM,MAAM,MAAS;AAExC,QAAM,QAAQ,OAAO,eAAe,EAAE,CAAC;AACvC,QAAM,IAAI,OAAO,cAAc,KAAK,CAAC;AACrC,QAAM,KAAM,EAAE,SAAoB,MAAM,cAAc,OAAO;AAC7D,QAAM,KAAM,EAAE,UAAqB,MAAM,eAAe,OAAO;AAE/D,QAAM,KAAK,KAAK,OAAO;AACvB,QAAM,KAAK,KAAK,OAAO;AACvB,QAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC;AAC9C,QAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC;AAE9C,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,MAAM;AACV,QAAM,OAAO,MAAM;AACjB,QAAI;AAAE,UAAI,UAAU,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,IAAI,EAAE;AAAA,IAAG,QAAQ;AAAA,IAAsB;AAC1G,UAAM,sBAAsB,IAAI;AAAA,EAClC;AACA,OAAK;AAEL,QAAM,MAAO,OAA4E,cAAc,EAAE;AACzG,QAAM,OAAO,kBAAkB;AAC/B,QAAM,MAAM,IAAI,cAAc,KAAK,OAAO,EAAE,UAAU,KAAK,IAAI,MAAS;AACxE,QAAM,SAAqB,CAAC;AAC5B,MAAI,kBAAkB,CAAC,MAAM;AAAE,QAAI,EAAE,QAAQ,EAAE,KAAK,KAAM,QAAO,KAAK,EAAE,IAAI;AAAA,EAAG;AAE/E,QAAM,OAAO,MAAM;AAAE,QAAI,IAAI,UAAU,WAAY,KAAI,KAAK;AAAA,EAAG;AAC/D,QAAM,WAAW,IAAI;AAErB,QAAM,QAAQ,OAAO,WAAW,MAAM,KAAK;AAC3C,SAAO,iBAAiB,SAAS,IAAI;AAErC,QAAM,OAAO,IAAI,QAAc,CAAC,YAAY;AAAE,QAAI,SAAS,MAAM,QAAQ;AAAA,EAAG,CAAC;AAC7E,MAAI,MAAM;AACV,QAAM;AAEN,SAAO,aAAa,KAAK;AACzB,uBAAqB,GAAG;AACxB,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,SAAOA,eAAc,IAAI,KAAK,QAAQ,EAAE,MAAM,QAAQ,aAAa,CAAC,CAAC;AACvE;AAGA,SAAS,WACP,SACA,MACA,IACA,IACA,OACA,QACiB;AACjB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,SAAS,MAAM;AACjB,YAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC;AACjD,YAAM,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC;AACjD,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,QAAQ;AACf,aAAO,SAAS;AAChB,YAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAI,UAAU,MAAM,KAAK,IAAI,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,IAAI,IAAI,GAAG,GAAG,IAAI,EAAE;AACrF,UAAI,YAAY;AAChB,iBAAW,KAAK,QAAQ;AACtB,YAAI,UAAU,EAAE,OAAO,KAAK,KAAK,QAAQ,EAAE,MAAM,KAAK,KAAK,OAAO,EAAE,QAAQ,OAAO,EAAE,SAAS,KAAK;AAAA,MACrG;AACA,cAAQ,OAAO,UAAU,WAAW,CAAC;AAAA,IACvC;AACA,QAAI,UAAU;AACd,QAAI,MAAM;AAAA,EACZ,CAAC;AACH;;;AC5QO,IAAM,yBAAyB;AAAA,EAClC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACX;AAEO,SAAS,eAAe,IAAI;AAC/B,MAAI,CAAC,MAAM,KAAK;AACZ,WAAO;AACX,QAAM,IAAI,KAAK,MAAM,KAAK,GAAI;AAC9B,MAAI,IAAI;AACJ,WAAO,GAAG,CAAC;AACf,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,QAAM,OAAO,IAAI;AACjB,MAAI,IAAI;AACJ,WAAO,OAAO,GAAG,CAAC,KAAK,IAAI,MAAM,GAAG,CAAC;AACzC,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,SAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AAC1B;AAKO,SAAS,kBAAkB,QAAQ,SAAS,QAAQ,MAAM,KAAK,IAAI,GAAG;AACzE,QAAM,QAAQ,oBAAI,IAAI;AACtB,QAAM,QAAQ,oBAAI,IAAI;AACtB,MAAI,SAAS;AACb,MAAI,QAAQ;AACZ,aAAW,KAAK,QAAQ;AACpB,eAAW,KAAK,EAAE,SAAS,CAAC;AACxB,YAAM,IAAI,CAAC;AACf,UAAM,IAAI,EAAE,OAAO,MAAM,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC;AAC9C,QAAI,EAAE,UAAU;AACZ;AACJ,UAAM,IAAI,KAAK,MAAM,EAAE,EAAE;AACzB,QAAI,CAAC,OAAO,MAAM,CAAC;AACf,cAAQ,KAAK,IAAI,OAAO,CAAC;AAAA,EACjC;AACA,SAAO;AAAA,IACH;AAAA,IACA,QAAQ,OAAO;AAAA,IACf;AAAA,IACA,OAAO,MAAM;AAAA,IACb,YAAY,OAAO,UAAU,UAAU,WAAW,KAAK,IAAI,GAAG,MAAM,KAAK,IAAI;AAAA,IAC7E,QAAQ,CAAC,GAAG,MAAM,QAAQ,CAAC,EACtB,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE,EACxC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA,EACzE;AACJ;;;AC/CO,IAAM,mBAAmB;AAAA,EAC5B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AACd;AASO,SAAS,UAAU,GAAG;AACzB,QAAM,cAAc,CAAC,CAAC,EAAE;AACxB,QAAM,KAAK,EAAE,MAAM;AACnB,QAAM,SAAS,CAAC,UAAU;AACtB,UAAM,MAAM,EAAE,OAAO,OAAO,iBAAiB,KAAK,EAAE;AACpD,QAAI,IAAI;AACJ,UAAI,KAAK;AACT,UAAI,OAAO,GAAG,gBAAgB,YAAY,GAAG,cAAc,GAAG;AAC1D,cAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,aAAa,GAAG,gBAAgB,CAAC,CAAC;AACzE,YAAI,SAAS;AAAA,UACT,MAAM,GAAG,MAAM,IAAI,GAAG,WAAW;AAAA,UACjC,OAAO,SAAS,GAAG;AAAA,QACvB;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AACA,MAAI,EAAE,WAAW;AACb,WAAO,eAAe,KAAK,OAAO,UAAU,IAAI;AACpD,MAAI;AACA,WAAO,OAAO,OAAO;AACzB,MAAI,EAAE,WAAW;AACb,WAAO,EAAE,OAAO,WAAW,OAAO,iBAAiB,QAAQ;AAC/D,MAAI;AACA,WAAO,EAAE,OAAO,QAAQ,OAAO,iBAAiB,KAAK;AACzD,SAAO;AACX;AAEO,SAAS,eAAe,UAAU;AACrC,SAAO,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW;AAC1D;;;AC9CO,SAAS,kBAAkB;AAC9B,SAAO,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG;AAClC;AAEO,SAAS,QAAQ,OAAO;AAC3B,SAAO,MAAM,SAAS,IAAI,MAAM,MAAM,MAAM,KAAK,KAAK,OAAO;AACjE;AASO,SAAS,aAAa,OAAO,WAAW;AAC3C,QAAM,OAAO,MAAM,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;AACjD,QAAM,QAAQ,CAAC,GAAG,MAAM,SAAS,EAAE,MAAM,CAAC,cAAc;AACxD,SAAO,EAAE,OAAO,OAAO,MAAM,SAAS,EAAE;AAC5C;AAEO,IAAM,iBAAiB;AACvB,SAAS,QAAQ,OAAO;AAC3B,SAAO,MAAM,MAAM,SAAS;AAChC;AAKO,SAAS,KAAK,OAAO;AACxB,MAAI,CAAC,MAAM,MAAM;AACb,WAAO;AACX,QAAM,QAAQ,MAAM,MAAM,MAAM,GAAG,EAAE;AACrC,SAAO,EAAE,OAAO,OAAO,MAAM,SAAS,EAAE;AAC5C;AACO,SAAS,QAAQ,OAAO,OAAO;AAClC,QAAM,OAAO,MAAM,QAAQ;AAC3B,SAAO,QAAQ,KAAK,OAAO,MAAM,MAAM;AAC3C;AAEO,SAAS,KAAK,OAAO,OAAO;AAC/B,SAAO,QAAQ,OAAO,KAAK,IAAI,EAAE,GAAG,OAAO,OAAO,MAAM,QAAQ,MAAM,IAAI;AAC9E;AAEO,SAAS,WAAW,OAAO;AAC9B,SAAO,MAAM,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,MAAM,MAAM,MAAM,MAAM,KAAK;AAC/E;;;AC1CO,SAAS,eAAe;AAC3B,SAAO,EAAE,OAAO,QAAQ,SAAS,MAAM,SAAS,CAAC,EAAE;AACvD;AAEO,SAAS,eAAe,KAAK;AAChC,MAAI;AACA,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,WAAO,EAAE,aAAa,WAAW,EAAE,aAAa;AAAA,EACpD,QACM;AACF,WAAO;AAAA,EACX;AACJ;AAKO,SAAS,kBAAkB,QAAQ,SAAS;AAC/C,MAAI,CAAC,eAAe,QAAQ,GAAG;AAC3B,WAAO;AACX,SAAO;AAAA,IACH,OAAO;AAAA,IACP,SAAS;AAAA,MACL,IAAI,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,MAC/C,IAAI,QAAQ,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,MACzC,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,WAAW,QAAQ;AAAA,IACvB;AAAA,IACA,SAAS,OAAO;AAAA,EACpB;AACJ;AACO,SAAS,UAAU,QAAQ;AAC9B,SAAO,OAAO,UAAU,eAAe,OAAO,YAAY;AAC9D;AASO,SAAS,OAAO,QAAQ,SAAS,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG;AACpE,MAAI,CAAC,UAAU,MAAM;AACjB,WAAO,EAAE,QAAQ,YAAY,KAAK;AACtC,QAAM,MAAM,OAAO,QAAQ;AAC3B,SAAO;AAAA,IACH,QAAQ;AAAA,MACJ,OAAO,UAAU,YAAY;AAAA,MAC7B,SAAS;AAAA,MACT,SAAS,CAAC,GAAG,OAAO,SAAS,EAAE,KAAK,UAAU,UAAU,YAAY,UAAU,IAAI,IAAI,CAAC;AAAA,IAC3F;AAAA,IACA,YAAY,UAAU,MAAM;AAAA,EAChC;AACJ;AAEO,SAAS,SAAS,QAAQ;AAC7B,SAAO,UAAU,MAAM,IAAI,EAAE,GAAG,QAAQ,OAAO,QAAQ,SAAS,KAAK,IAAI;AAC7E;;;ACtDO,SAAS,wBAAwB,SAAS;AAC7C,SAAO;AAAA,IACH,IAAI,GAAG,QAAQ,EAAE;AAAA,IACjB,UAAU,QAAQ;AAAA,IAClB,QAAQ,EAAE,GAAG,QAAQ,QAAQ,MAAM,OAAO;AAAA,IAC1C,MAAM,QAAQ;AAAA,IACd,aAAa,QAAQ,aAAa,SAAS,QAAQ,cAAc;AAAA,IACjE,WAAW,QAAQ;AAAA,EACvB;AACJ;AAEO,SAAS,mBAAmB,SAAS,SAAS,OAAO,CAAC,GAAG;AAG5D,QAAM,UAAU,KAAK,iBAAiB,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS;AAClF,SAAO,CAAC,wBAAwB,OAAO,GAAG,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAC/G;AAkBO,SAAS,eAAe,MAAM;AACjC,MAAI,CAAC,KAAK,kBAAkB,KAAK,kBAAkB;AAC/C,WAAO;AACX,SAAO,aAAa,KAAK,mBAAmB,CAAC;AACjD;;;AC5CO,SAAS,eAAe,OAAO;AAClC,QAAM,QAAQ,CAAC;AACf,MAAI,MAAM,QAAQ;AACd,UAAM,KAAK,MAAM,MAAM,OAAO,GAAG,GAAG;AACxC,MAAI,MAAM,QAAQ;AACd,UAAM,KAAK,KAAK,MAAM,OAAO,QAAQ,IAAI;AAC7C,SAAO,MAAM,SAAS,MAAM,KAAK,GAAG,IAAI,MAAM,SAAS,SAAS,gBAAgB;AACpF;AAUO,SAAS,eAAe,OAAO,WAAW,CAAC,GAAG;AACjD,QAAM,MAAM,CAAC;AACb,QAAM,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,CAAC,EAAE,KAAK,MAAM;AAC1E,MAAI,KAAK;AAAA,IACL,IAAI,MAAM;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAC,MAAM,OAAO,eAAe,KAAK,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAAA,EAC3E,CAAC;AACD,aAAW,KAAK,UAAU;AACtB,QAAI,KAAK;AAAA,MACL,IAAI,EAAE;AAAA,MACN,MAAM;AAAA,MACN,OAAO,GAAG,EAAE,UAAU;AAAA,MACtB,OAAO,EAAE,YAAY,EAAE,aAAa;AAAA,IACxC,CAAC;AAAA,EACL;AACA,QAAM,QAAQ,eAAe,MAAM,MAAM;AACzC,QAAM,UAAU,CAAC,MAAM,YAAY,QAAQ,KAAK,KAAK,YAAY,QAAQ,CAAC;AAC1E,MAAI,MAAM,YAAY,QAAQ,WAAW,GAAG;AACxC,UAAM,QAAQ,MAAM,UAAU,UAAU;AACxC,QAAI,KAAK;AAAA,MACL,IAAI,MAAM,UAAU,aAAa;AAAA,MACjC,MAAM;AAAA,MACN,OAAO,qBAAqB,KAAK;AAAA,MACjC,QAAQ;AAAA,MACR,OAAO;AAAA,IACX,CAAC;AAAA,EACL;AACA,MAAI,MAAM,IAAI;AACV,QAAI,KAAK;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO,MAAM,GAAG,SAAS,iBAAiB,MAAM,GAAG,MAAM,YAAY;AAAA,MACrE,QAAQ,MAAM,GAAG,UAAU,WAAW,YAAY,MAAM,GAAG,UAAU,WAAW,4BAA4B;AAAA,IAChH,CAAC;AAED,QAAI,MAAM,GAAG,YAAY;AACrB,UAAI,KAAK,EAAE,IAAI,QAAQ,MAAM,WAAW,OAAO,gBAAgB,QAAQ,MAAM,GAAG,WAAW,CAAC;AAAA,IAChG;AAAA,EACJ;AACA,MAAI,QAAQ,WAAW,GAAG;AACtB,QAAI,KAAK,EAAE,IAAI,QAAQ,MAAM,UAAU,OAAO,6BAA6B,QAAQ,gCAAgC,CAAC;AAAA,EACxH;AACA,MAAI,UAAU,YAAY;AACtB,QAAI,KAAK,EAAE,IAAI,QAAQ,MAAM,YAAY,OAAO,YAAY,QAAQ,wBAAwB,CAAC;AAAA,EACjG;AACA,SAAO;AACX;AACA,IAAM,cAAc,CAAC,SAAS,QAAQ,eAAe,aAAa,UAAU;AAE5E,SAAS,eAAe,QAAQ;AAC5B,MAAI,WAAW;AACX,WAAO;AACX,MAAI,WAAW;AACX,WAAO;AACX,SAAO;AACX;AAOO,SAAS,aAAa,OAAO,WAAW,CAAC,GAAG;AAC/C,QAAM,QAAQ;AAAA,IACV,KAAK,MAAM,SAAS,UAAU,MAAM,MAAM,EAAE;AAAA,IAC5C;AAAA,IACA,YAAY,eAAe,MAAM,MAAM,CAAC;AAAA,IACxC,WAAW,MAAM,OAAO,QAAG;AAAA,EAC/B;AACA,MAAI,MAAM,QAAQ;AACd,UAAM,KAAK,eAAe,MAAM,OAAO,QAAQ,IAAI;AACvD,MAAI,MAAM,IAAI;AACV,UAAM,KAAK,UAAU,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,iBAAc,MAAM,GAAG,UAAU,KAAK,EAAE,EAAE;AAC3G,QAAM,KAAK,IAAI,cAAc,IAAI,MAAM,IAAI;AAC3C,MAAI,SAAS,QAAQ;AACjB,UAAM,KAAK,IAAI,mBAAmB,EAAE;AACpC,eAAW,KAAK;AACZ,YAAM,KAAK,KAAK,EAAE,UAAU,KAAK,EAAE,YAAY,aAAa,EAAE,WAAM,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,EAAE;AAAA,EAClG;AACA,SAAO,MAAM,KAAK,IAAI;AAC1B;;;ACtGA,IAAM,SAAS;AAKf,SAAS,eAAe,MAAM;AAC1B,QAAM,SAAS,CAAC;AAEhB,aAAW,KAAK,KAAK,SAAS,iBAAiB;AAC3C,WAAO,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,CAAC;AAChD,QAAM,SAAS,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC;AAC7D,aAAW,KAAK,KAAK,SAAS,YAAY,GAAG;AACzC,QAAI,CAAC,OAAO,EAAE,KAAK;AACf,aAAO,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AACA,SAAO;AACX;AAQO,SAAS,cAAc,MAAM;AAChC,MAAI,CAAC;AACD,WAAO,CAAC;AACZ,QAAM,WAAW,eAAe,IAAI;AACpC,QAAM,aAAa,CAAC,MAAM,SAAS,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC;AACnE,QAAM,MAAM,CAAC;AACb,QAAM,OAAO,oBAAI,IAAI;AACrB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAClC,QAAI,KAAK,CAAC,MAAM;AACZ;AACJ,QAAI,WAAW,CAAC;AACZ;AAGJ,UAAM,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI;AACnC,QAAI,QAAQ,CAAC,gBAAgB,KAAK,IAAI;AAClC;AACJ,UAAM,QAAQ,OAAO,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC;AAC3C,QAAI,CAAC;AACD;AACJ,UAAM,MAAM,MAAM,CAAC;AAGnB,UAAM,SAAS,IAAI,QAAQ,WAAW,EAAE;AACxC,QAAI,CAAC;AACD;AACJ,UAAM,MAAM,OAAO,YAAY;AAG/B,QAAI,KAAK,IAAI,GAAG;AACZ;AACJ,SAAK,IAAI,GAAG;AACZ,QAAI,KAAK,EAAE,QAAQ,OAAO,GAAG,QAAQ,OAAO,SAAS,EAAE,CAAC;AAAA,EAC5D;AACA,SAAO;AACX;AA6BO,SAAS,gBAAgB,MAAM,UAAU;AAC5C,MAAI,CAAC,SAAS;AACV,WAAO,CAAC,EAAE,MAAM,MAAM,SAAS,MAAM,CAAC;AAC1C,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC7D,QAAM,MAAM,CAAC;AACb,MAAI,KAAK;AACT,aAAW,KAAK,QAAQ;AACpB,QAAI,EAAE,QAAQ;AACV,UAAI,KAAK,EAAE,MAAM,KAAK,MAAM,IAAI,EAAE,KAAK,GAAG,SAAS,MAAM,CAAC;AAC9D,QAAI,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,CAAC;AACzE,SAAK,EAAE,QAAQ,EAAE;AAAA,EACrB;AACA,MAAI,KAAK,KAAK;AACV,QAAI,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GAAG,SAAS,MAAM,CAAC;AACrD,SAAO;AACX;AAEO,SAAS,mBAAmB,MAAM,OAAO,YAAY;AAExD,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK;AAClC,QAAM,KAAK,OAAO,YAAY,GAAG;AACjC,MAAI,KAAK;AACL,WAAO,CAAC;AACZ,QAAM,QAAQ,OAAO,MAAM,KAAK,CAAC;AAEjC,MAAI,KAAK,KAAK,KAAK;AACf,WAAO,CAAC;AACZ,QAAM,IAAI,MAAM,YAAY;AAC5B,SAAO,WACF,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,YAAY,EAAE,SAAS,CAAC,CAAC,EACtF,MAAM,GAAG,CAAC;AACnB;;;ACpHO,IAAM,mBAAmB;AAAA,EAC5B,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AACZ;AAEO,SAAS,kBAAkB,MAAM;AACpC,QAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAClE,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,MAAI,CAAC;AACD,WAAO;AAEX,SAAO,cAAc,KAAK,IAAI;AAClC;AAQO,SAAS,SAAS,OAAO;AAC5B,QAAM,QAAQC,gBAAe,MAAM,MAAM;AAEzC,MAAI,UAAU;AACV,WAAO,EAAE,OAAO,MAAM;AAC1B,MAAI,MAAM;AACN,WAAO,EAAE,OAAO,MAAM,QAAQ,UAAU,OAAO,iBAAiB,OAAO;AAG3E,MAAI,MAAM,MAAM,aAAa,kBAAkB,MAAM,KAAK,IAAI,GAAG;AAC7D,WAAO,EAAE,OAAO,MAAM,QAAQ,YAAY,OAAO,iBAAiB,SAAS;AAAA,EAC/E;AACA,MAAI,UAAU;AACV,WAAO,EAAE,OAAO,MAAM,QAAQ,UAAU,OAAO,iBAAiB,OAAO;AAC3E,SAAO,EAAE,OAAO,MAAM;AAC1B;AAKA,SAASC,gBAAe,QAAQ;AAC5B,MAAI,WAAW;AACX,WAAO;AACX,MAAI,WAAW;AACX,WAAO;AACX,SAAO;AACX;;;ACjDO,IAAM,mBAAmB,CAAC,aAAM,aAAM,aAAM,aAAM,gBAAM,WAAI;AAO5D,SAAS,mBAAmB,WAAW,UAAU;AACpD,QAAM,UAAU,oBAAI,IAAI;AACxB,aAAW,KAAK,WAAW;AACvB,UAAM,OAAO,QAAQ,IAAI,EAAE,KAAK,KAAK,CAAC;AACtC,SAAK,KAAK,CAAC;AACX,YAAQ,IAAI,EAAE,OAAO,IAAI;AAAA,EAC7B;AACA,QAAM,OAAO,CAAC,UAAU;AACpB,UAAM,KAAK,iBAAiB,QAAQ,KAAK;AACzC,WAAO,KAAK,IAAI,iBAAiB,SAAS;AAAA,EAC9C;AACA,SAAO,CAAC,GAAG,QAAQ,QAAQ,CAAC,EACvB,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO;AAAA,IACzB;AAAA,IACA,OAAO,KAAK;AAAA,IACZ,MAAM,WAAW,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,IAAI;AAAA,IAC3D,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM;AAAA,EACjD,EAAE,EACG,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE,KAAK,IAAI,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAC5G;AAQO,SAAS,eAAe,WAAW,MAAM;AAC5C,QAAM,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,cAAc,KAAK,aAAa,EAAE,UAAU,KAAK,SAAS,EAAE,WAAW,KAAK,MAAM;AACtH,MAAI,KAAK;AACL,WAAO,UAAU,OAAO,CAAC,MAAM,EAAE,EAAE,cAAc,KAAK,aAAa,EAAE,UAAU,KAAK,SAAS,EAAE,WAAW,KAAK,OAAO;AAAA,EAC1H;AACA,SAAO,CAAC,GAAG,WAAW,IAAI;AAC9B;;;ACpCO,IAAM,oBAAoB;AA6C1B,SAAS,WAAW,MAAM;AAC7B,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACrD,MAAI,CAAC,MAAM;AACP,WAAO;AACX,MAAI,MAAM,WAAW;AACjB,WAAO,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY;AAC5C,UAAQ,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,MAAM,MAAM,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,YAAY;AACpF;;;ACvDO,SAAS,YAAY;AACxB,SAAO,EAAE,OAAO,CAAC,EAAE;AACvB;AAQO,SAAS,UAAU,OAAO,MAAM;AACnC,QAAM,OAAO,EAAE,SAAS,MAAM,GAAG,KAAK;AACtC,QAAM,KAAK,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AACxD,MAAI,KAAK;AACL,WAAO,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,IAAI,EAAE;AAC3C,QAAM,QAAQ,CAAC,GAAG,MAAM,KAAK;AAC7B,QAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,MAAM,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE,SAAO,EAAE,MAAM;AACnB;AACO,SAAS,eAAe,OAAO,IAAI;AACtC,SAAO,EAAE,OAAO,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;AAC3D;AACO,SAAS,cAAc,OAAO,IAAI;AACrC,SAAO,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC,EAAE,QAAQ,IAAI,CAAE,EAAE;AAC9F;AAEO,SAAS,WAAW,OAAO,IAAI,IAAI;AACtC,QAAM,OAAO,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACrD,MAAI,OAAO;AACP,WAAO;AACX,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM,SAAS,GAAG,EAAE,CAAC;AAC/D,MAAI,WAAW;AACX,WAAO;AACX,QAAM,QAAQ,CAAC,GAAG,MAAM,KAAK;AAC7B,QAAM,CAAC,KAAK,IAAI,MAAM,OAAO,MAAM,CAAC;AACpC,QAAM,OAAO,QAAQ,GAAG,KAAK;AAC7B,SAAO,EAAE,MAAM;AACnB;AAEO,SAAS,YAAY,OAAO,IAAI,OAAO;AAC1C,QAAM,KAAK,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACnD,MAAI,KAAK;AACL,WAAO;AACX,SAAO,WAAW,OAAO,IAAI,KAAK,KAAK;AAC3C;AAEO,SAAS,cAAc,OAAO;AACjC,SAAO,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO;AAC9C;AACO,SAAS,UAAU,OAAO;AAC7B,SAAO,EAAE,OAAO,MAAM,MAAM,QAAQ,UAAU,cAAc,KAAK,EAAE,OAAO;AAC9E;AACO,SAAS,YAAY;AACxB,SAAO,EAAE,OAAO,CAAC,EAAE;AACvB;AAQO,SAAS,YAAY,OAAO;AAC/B,SAAO,cAAc,KAAK,EAAE,IAAI,CAAC,OAAO;AAAA,IACpC,MAAM,EAAE;AAAA,IACR,IAAI,EAAE,OAAO,EAAE;AAAA,IACf,KAAK,EAAE;AAAA,IACP,OAAO,EAAE;AAAA,EACb,EAAE;AACN;AAEO,SAAS,YAAY,OAAO;AAC/B,QAAM,EAAE,OAAO,SAAS,IAAI,UAAU,KAAK;AAC3C,MAAI,CAAC;AACD,WAAO;AACX,MAAI,aAAa;AACb,WAAO,GAAG,KAAK,WAAW,UAAU,IAAI,KAAK,GAAG;AACpD,SAAO,GAAG,QAAQ,OAAO,KAAK;AAClC;AASO,SAAS,aAAa,KAAK;AAC9B,MAAI,CAAC,IAAI;AACL,WAAO;AACX,SAAO,IAAI,UAAU,cAAc;AACvC;AACO,SAAS,aAAa,SAAS;AAClC,MAAI,YAAY;AACZ,WAAO;AACX,MAAI,YAAY;AACZ,WAAO;AACX,SAAO;AACX;AAEO,SAAS,aAAa,IAAI;AAC7B,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,GAAI,CAAC;AAC/C,QAAM,KAAK,KAAK,MAAM,QAAQ,EAAE;AAChC,QAAM,KAAK,QAAQ;AACnB,SAAO,GAAG,EAAE,IAAI,OAAO,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAC/C;;;ACrGO,IAAM,iBAAiB,CAAC,SAAS,QAAQ,eAAe,aAAa,UAAU;AAE/E,IAAM,eAAe;AAAA,EACxB,OAAO;AAAA,EACP,MAAM;AAAA,EACN,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AACd;AAMA,IAAM,gBAAgB;AAAA,EAClB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AACV;AAMO,SAAS,gBAAgB,OAAO;AACnC,MAAI,OAAO,UAAU,UAAU;AAC3B,QAAI,eAAe,SAAS,KAAK;AAC7B,aAAO;AACX,QAAI,SAAS;AACT,aAAO,cAAc,KAAK;AAAA,EAClC;AACA,SAAO;AACX;AAmBO,IAAM,qBAAqB,CAAC,YAAY,QAAQ,UAAU,KAAK;AAE/D,IAAM,kBAAkB;AAAA,EAC3B,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACT;AASO,IAAM,eAAe,CAAC,YAAY,WAAW,OAAO,OAAO;AAE3D,IAAM,qBAAqB;AAAA,EAC9B,UAAU;AAAA,EACV,SAAS;AAAA,EACT,KAAK;AAAA,EACL,OAAO;AACX;AAEO,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAE5B,SAAS,kBAAkB,OAAO;AACrC,MAAI,OAAO,UAAU,YAAY,mBAAmB,SAAS,KAAK,GAAG;AACjE,WAAO;AAAA,EACX;AACA,SAAO;AACX;;;ACzFO,IAAM,sBAAN,MAAoD;AAAA,EACjD,IAAI,YAAoB,KAAa;AAC3C,WAAO,SAAS,UAAU,IAAI,GAAG;AAAA,EACnC;AAAA,EAEQ,QAAQ,YAAoB,KAAwB;AAC1D,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,KAAK,IAAI,YAAY,GAAG,CAAC;AAC1D,aAAO,MAAO,KAAK,MAAM,GAAG,IAAkB,CAAC;AAAA,IACjD,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEQ,SAAS,YAAoB,KAAa,UAAqB;AACrE,iBAAa,QAAQ,KAAK,IAAI,YAAY,GAAG,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EAC1E;AAAA,EAEA,MAAM,KAAK,YAAoB,KAAiC;AAC9D,WAAO,KAAK,QAAQ,YAAY,GAAG;AAAA,EACrC;AAAA;AAAA,EAGA,MAAM,QAAQ,YAAwC;AACpD,UAAM,SAAS,SAAS,UAAU;AAClC,UAAM,MAAiB,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,IAAI,aAAa,IAAI,CAAC;AAC5B,UAAI,CAAC,KAAK,CAAC,EAAE,WAAW,MAAM,EAAG;AACjC,UAAI;AACF,YAAI,KAAK,GAAI,KAAK,MAAM,aAAa,QAAQ,CAAC,KAAK,IAAI,CAAe;AAAA,MACxE,QAAQ;AAAA,MAA+B;AAAA,IACzC;AACA,WAAO,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,UAAM,MAAM,KAAK,QAAQ,QAAQ,YAAY,QAAQ,GAAG;AACxD,QAAI,KAAK,OAAO;AAChB,SAAK,SAAS,QAAQ,YAAY,QAAQ,KAAK,GAAG;AAClD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,aAAqB,MAAiC;AACjE,QAAI,KAAK,OAAO,IAAW,OAAM,IAAI,MAAM,uCAAuC;AAClF,WAAO;AAAA,MACL,KAAK,MAAM,cAAc,IAAI;AAAA,MAC7B,MAAM,KAAK;AAAA,MACX,MAAM,KAAK,QAAQ;AAAA,MACnB,MAAM,eAAe,KAAK,IAAI;AAAA,MAC9B,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAwB;AAC9B,UAAM,OAAiB,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,IAAI,aAAa,IAAI,CAAC;AAC5B,UAAI,KAAK,EAAE,WAAW,QAAQ,KAAK,MAAM,gBAAgB,CAAC,EAAE,WAAW,aAAa,EAAG,MAAK,KAAK,CAAC;AAAA,IACpG;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,KAAwB;AACxC,QAAI;AACF,YAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,GAAG,KAAK,IAAI;AAC1D,aAAO,MAAM,QAAQ,KAAK,IAAK,QAAsB,CAAC;AAAA,IACxD,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA,EAGQ,OAAO,UAAkB;AAC/B,WAAO,cAAc,QAAQ;AAAA,EAC/B;AAAA,EAEA,MAAM,aAAa,UAA4C;AAC7D,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,KAAK,OAAO,QAAQ,CAAC;AACtD,YAAM,SAAS,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AACxC,aAAO,MAAM,QAAQ,MAAM,IAAK,SAA6B,CAAC;AAAA,IAChE,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,WACJ,UACA,SACwB;AACxB,UAAM,SAAwB;AAAA,MAC5B,IAAI,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,MACxE;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ,aAAa,SAAS,QAAQ,cAAc;AAAA,MACjE,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,UAAM,MAAM,MAAM,KAAK,aAAa,QAAQ;AAC5C,QAAI,KAAK,MAAM;AACf,iBAAa,QAAQ,KAAK,OAAO,QAAQ,GAAG,KAAK,UAAU,GAAG,CAAC;AAC/D,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,cAAc,UAAuC;AACzD,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,aAAa,QAAQ,EAAE;AACxD,YAAM,SAAS,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AACxC,aAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAAA,IAC3C,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,OAAuH;AAC1I,UAAMC,WAAU,MAAM,KAAK,cAAc,MAAM,QAAQ;AAEvD,UAAM,OAAO,eAAeA,UAAS;AAAA,MACnC,WAAW,MAAM;AAAA,MAAW,OAAO,MAAM;AAAA,MAAO,QAAQ,MAAM;AAAA,MAAQ,UAAU,MAAM;AAAA,IACxF,CAAC;AACD,iBAAa,QAAQ,aAAa,MAAM,QAAQ,IAAI,KAAK,UAAU,IAAI,CAAC;AACxE,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,WAAW,YAA6E;AAC5F,UAAM,SAAS,SAAS,UAAU;AAClC,UAAM,OAAO,oBAAI,IAA0D;AAC3E,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,IAAI,aAAa,IAAI,CAAC;AAC5B,UAAI,CAAC,KAAK,CAAC,EAAE,WAAW,MAAM,EAAG;AACjC,iBAAW,KAAK,KAAK,UAAU,CAAC,GAAG;AACjC,YAAI,EAAE,QAAQ,MAAM,CAAC,KAAK,IAAI,EAAE,OAAO,EAAE,EAAG,MAAK,IAAI,EAAE,OAAO,IAAI,EAAE,MAAM;AAAA,MAC5E;AAAA,IACF;AACA,WAAO,CAAC,GAAG,KAAK,OAAO,CAAC;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,oBAAoC;AACxC,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAM,wBAAuC;AAAA,EAE7C;AAAA,EAEA,MAAM,OAAO,IAAY,OAAwC;AAE/D,eAAW,KAAK,KAAK,YAAY,GAAG;AAClC,YAAM,OAAO,KAAK,UAAU,CAAC;AAC7B,YAAM,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7C,UAAI,OAAO,GAAG;AACZ,aAAK,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAI,GAAG,MAAM;AACtC,qBAAa,QAAQ,GAAG,KAAK,UAAU,IAAI,CAAC;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,eAAW,KAAK,KAAK,YAAY,GAAG;AAClC,YAAM,OAAO,KAAK,UAAU,CAAC;AAC7B,YAAM,OAAO,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3C,UAAI,KAAK,WAAW,KAAK,QAAQ;AAC/B,qBAAa,QAAQ,GAAG,KAAK,UAAU,IAAI,CAAC;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAkC;AACtC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,aAAa,aAAqB,QAAkD;AACxF,WAAO;AAAA,EACT;AACF;;;ACjMO,IAAM,cAAN,MAA4C;AAAA,EACjD,YACU,MACA,MACA,UACA,cACA,aACR;AALQ;AACA;AACA;AACA;AACA;AAER,SAAK,OAAO,KAAK,QAAQ,OAAO,EAAE;AAAA,EACpC;AAAA,EAEQ,UAAuB;AAC7B,UAAM,IAA4B,EAAE,gBAAgB,oBAAoB,gBAAgB,KAAK,KAAK,GAAG;AACrG,QAAI,KAAK,SAAU,GAAE,cAAc,IAAI,KAAK;AAC5C,QAAI,KAAK,aAAc,QAAO,OAAO,GAAG,KAAK,YAAY;AACzD,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,KAAKC,OAAiC;AAC5C,WAAO,KAAK,cAAc,EAAE,aAAa,KAAK,aAAa,GAAGA,MAAK,IAAI,EAAE,GAAGA,MAAK;AAAA,EACnF;AAAA,EAEA,MAAM,KAAK,YAAoB,KAAiC;AAC9D,UAAM,IAAI,IAAI,gBAAgB,EAAE,YAAY,IAAI,CAAC;AACjD,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAAC,IAAI,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/F,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,gBAAgB,IAAI,MAAM,EAAE;AACzD,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,QAAQ,YAAwC;AACpD,UAAM,IAAI,IAAI,gBAAgB,EAAE,WAAW,CAAC;AAC5C,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAAC,IAAI,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/F,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,mBAAmB,IAAI,MAAM,EAAE;AAC5D,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA,EAGA,MAAc,WAAW,YAAoB,MAA+B;AAC1E,QAAI;AACF,YAAM,KAAK,MAAM,MAAM,GAAG,KAAK,IAAI,aAAa,KAAK,KAAK;AAAA,QACxD,QAAQ;AAAA,QACR,SAAS,KAAK,QAAQ;AAAA,QACtB,MAAM,KAAK,UAAU,EAAE,YAAY,KAAK,CAAC;AAAA,MAC3C,CAAC,CAAC;AACF,UAAI,GAAG,GAAI,SAAQ,MAAM,GAAG,KAAK,GAAG;AAAA,IACtC,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,SAAoC;AAG7C,QAAI,QAAQ,YAAY,WAAW,OAAO,GAAG;AAC3C,gBAAU,EAAE,GAAG,SAAS,YAAY,MAAM,KAAK,WAAW,QAAQ,YAAY,QAAQ,UAAU,EAAE;AAAA,IACpG;AACA,QAAI,QAAQ,WAAW,WAAW,OAAO,GAAG;AAC1C,gBAAU,EAAE,GAAG,SAAS,WAAW,MAAM,KAAK,WAAW,QAAQ,YAAY,QAAQ,SAAS,EAAE;AAAA,IAClG;AACA,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,KAAK,KAAK;AAAA,MAC5D,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ;AAAA,MACtB,MAAM,KAAK,UAAU,OAAO;AAAA,IAC9B,CAAC,CAAC;AACF,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,gBAAgB,IAAI,MAAM,EAAE;AACzD,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,OAAO,YAAoB,MAAiC;AAChE,UAAM,OAAO,MAAM,cAAc,IAAI;AACrC,WAAO;AAAA,MACL,KAAK,MAAM,KAAK,WAAW,YAAY,IAAI;AAAA,MAC3C,MAAM,KAAK;AAAA,MACX,MAAM,KAAK,QAAQ;AAAA,MACnB,MAAM,eAAe,KAAK,IAAI;AAAA,MAC9B,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aAAa,UAA4C;AAC7D,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,QAAQ,CAAC,aAAa,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AACnI,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,wBAAwB,IAAI,MAAM,EAAE;AACjE,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,WACJ,UACA,SAC8E;AAC9E,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,QAAQ,CAAC,aAAa,KAAK,KAAK;AAAA,MACrG,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ;AAAA,MACtB,MAAM,KAAK,UAAU,OAAO;AAAA,IAC9B,CAAC,CAAC;AACF,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,sBAAsB,IAAI,MAAM,EAAE;AAC/D,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,cAAc,UAAuC;AAGzD,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,QAAQ,CAAC,cAAc,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAEpI,QAAI,IAAI,WAAW,IAAK,QAAO,CAAC;AAChC,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,EAAE;AAClE,YAAS,MAAM,IAAI,KAAK,GAAiC;AAAA,EAC3D;AAAA,EAEA,MAAM,eAAe,OAAuH;AAC1I,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,MAAM,QAAQ,CAAC,aAAa,mBAAmB,MAAM,SAAS,CAAC;AAAA,MAC9G,KAAK,KAAK;AAAA,QACR,QAAQ;AAAA,QACR,SAAS,KAAK,QAAQ;AAAA,QACtB,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,OAAO,QAAQ,MAAM,QAAQ,UAAU,MAAM,SAAS,CAAC;AAAA,MAC7F,CAAC;AAAA,IACH;AACA,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,EAAE;AACnE,YAAS,MAAM,IAAI,KAAK,GAAiC;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,WAAW,YAA6E;AAC5F,UAAM,IAAI,IAAI,gBAAgB,EAAE,WAAW,CAAC;AAC5C,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,cAAc,CAAC,IAAI,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC7F,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,sBAAsB,IAAI,MAAM,EAAE;AAC/D,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,kBAAkB,YAAoB,WAAmC;AAC7E,UAAM,IAAI,IAAI,gBAAgB,EAAE,YAAY,UAAU,CAAC;AACvD,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,qBAAqB,CAAC,IAAI,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AACpG,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,EAAE;AACtE,YAAS,MAAM,IAAI,KAAK,GAAgC;AAAA,EAC1D;AAAA,EAEA,MAAM,sBAAsB,YAAoB,WAAmB,IAA4B;AAC7F,UAAM,MAAM,GAAG,KAAK,IAAI,0BAA0B,KAAK,KAAK;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ;AAAA,MACtB,MAAM,KAAK,UAAU,EAAE,YAAY,WAAW,GAAG,CAAC;AAAA,IACpD,CAAC,CAAC;AAAA,EACJ;AAAA,EAEA,MAAM,OAAO,IAAY,OAAwC;AAC/D,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,EAAE,CAAC,IAAI,KAAK,KAAK;AAAA,MACtF,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ;AAAA,MACtB,MAAM,KAAK,UAAU,KAAK;AAAA,IAC5B,CAAC,CAAC;AACF,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,EAAE;AAAA,EAC7D;AAAA;AAAA,EAGA,MAAM,SAAkC;AACtC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,WAAW,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AACrF,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,EAAE;AAE3D,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,WAAW,CAAC,MAAM,QAAQ,KAAK,QAAQ,GAAG;AACvF,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,aAAa,YAAoB,OAAiD;AACtF,UAAM,IAAI,IAAI,gBAAgB,EAAE,WAAW,CAAC;AAC5C,QAAI,MAAO,GAAE,IAAI,SAAS,KAAK;AAC/B,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAAC,IAAI,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/F,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,wBAAwB,IAAI,MAAM,EAAE;AACjE,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,OAAM,IAAI,MAAM,yCAAyC;AACnF,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,gBAAgB,mBAAmB,EAAE,CAAC,IAAI,KAAK,KAAK;AAAA,MACtF,QAAQ;AAAA,MACR,SAAS,KAAK,QAAQ;AAAA,IACxB,CAAC,CAAC;AACF,QAAI,CAAC,IAAI,MAAM,IAAI,WAAW,IAAK,OAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,EAAE;AAAA,EACnF;AACF;;;AChIO,IAAM,cAAc,OAAwC,WAAoB;AAEvF,IAAM,WAAW;AAEjB,IAAM,qBAAqB;AAE3B,IAAM,oBAAoB;AAI1B,IAAM,UAAuE;AAAA,EAC3E,EAAE,IAAI,UAAU,MAAM,WAAW,OAAO,WAAW,MAAM,yBAAyB;AAAA,EAClF,EAAE,IAAI,UAAU,MAAM,WAAW,OAAO,WAAW,MAAM,yBAAyB;AAAA,EAClF,EAAE,IAAI,QAAQ,MAAM,WAAW,OAAO,WAAW,MAAM,wBAAwB;AAAA,EAC/E,EAAE,IAAI,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM,wBAAwB;AAAA,EAChF,EAAE,IAAI,QAAQ,MAAM,WAAW,OAAO,WAAW,MAAM,wBAAwB;AACjF;AACA,IAAM,aAAa,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AAM1C,IAAM,OAAiE;AAAA;AAAA;AAAA,EAGrE;AAAA,IAAE,KAAK;AAAA,IAAU,KAAK;AAAA,IAAQ,OAAO;AAAA,IACnC,MAAM;AAAA,EAA8G;AAAA,EACtH;AAAA,IAAE,KAAK;AAAA,IAAW,KAAK;AAAA,IAAQ,OAAO;AAAA,IACpC,MAAM;AAAA,EAAwE;AAAA,EAChF;AAAA,IAAE,KAAK;AAAA,IAAU,KAAK;AAAA,IAAY,OAAO;AAAA,IACvC,MAAM;AAAA,EAAgH;AAAA,EACxH;AAAA,IAAE,KAAK;AAAA,IAA+B,KAAK;AAAA,IAAY,OAAO;AAAA,IAC5D,MAAM;AAAA,EAA6I;AAAA,EACrJ;AAAA,IAAE,KAAK;AAAA,IAAgC,KAAK;AAAA,IAAY,OAAO;AAAA,IAC7D,MAAM;AAAA,EAAoE;AAC9E;AAGA,IAAM,QAA6D;AAAA,EACjE,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA,MAAM,EAAE,OAAO,2BAA2B,MAAM,8HAA8H;AAAA,EAC9K,UAAU,EAAE,OAAO,uBAAuB,MAAM,oIAAoI;AAAA,EACpL,UAAU,EAAE,OAAO,yBAAyB,MAAM,iIAAiI;AACrL;AAMA,IAAM,eAAoD;AAAA,EACxD,EAAE,IAAI,QAAQ,OAAO,OAAO;AAAA,EAC5B,EAAE,IAAI,YAAY,OAAO,WAAW;AAAA,EACpC,EAAE,IAAI,YAAY,OAAO,WAAW;AAAA,EACpC,EAAE,IAAI,QAAQ,OAAO,OAAO;AAC9B;AAeA,IAAM,aAAyB,CAAC,QAAQ,SAAS,UAAU,OAAO;AAElE,IAAM,gBAAgB;AAEtB,IAAM,YAAY;AAElB,IAAM,eAAe;AACrB,IAAM,kBAAkB,KAAK,OAAO;AACpC,IAAM,kBAAkB,KAAK,OAAO;AAEpC,IAAMC,OAAM,MACT,OAAe,aAAa,OAAO,WAAW,IAAI,OAAO,KAAK,IAAI,KAAK,OAAO,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE;AACjH,SAAS,KAAK,GAAW;AAAE,MAAI,IAAI;AAAG,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAK,IAAI,KAAK,EAAE,WAAW,CAAC,IAAK;AAAG,SAAO;AAAG;AAQvH,SAAS,gBAAyB;AAChC,MAAI;AACF,QAAI,OAAO,WAAW,mBAAmB,EAAE,QAAS,QAAO;AAC3D,QAAI,OAAO,WAAW,eAAe,EAAE,QAAS,QAAO;AAAA,EACzD,QAAQ;AAAA,EAER;AACA,MAAI,OAAO,cAAc,gBAAgB,UAAU,kBAAkB,KAAK,EAAG,QAAO;AACpF,SAAO,OAAO,WAAW,eAAe,kBAAkB;AAC5D;AAGA,SAAS,gBAAyB;AAChC,MAAI;AACF,WAAO,OAAO,WAAW,mBAAmB,EAAE;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,iBAA0B;AACjC,SAAO,OAAQ,UAAU,cAA2C,oBAAoB;AAC1F;AAGA,SAAS,cAAc,SAAiB,MAA2B;AACjE,QAAM,IAAI,sCAAsC,KAAK,OAAO;AAC5D,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,CAAC,EAAE,MAAM,KAAK,UAAU,EAAE,IAAI;AACpC,MAAI;AACF,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,mBAAmB,OAAO;AAC5D,UAAM,QAAQ,IAAI,WAAW,IAAI,MAAM;AACvC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,OAAM,CAAC,IAAI,IAAI,WAAW,CAAC;AAChE,WAAO,IAAI,KAAK,CAAC,KAAK,GAAG,MAAM,EAAE,MAAM,QAAQ,YAAY,CAAC;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,WAAN,MAAe;AAAA,EA0KpB,YAAY,KAAkB;AAnJ9B;AAAA,SAAQ,cAAc;AAEtB;AAAA,SAAQ,gBAAgB;AAKxB;AAAA;AAAA;AAAA;AAAA,SAAQ,iBAAiB;AAQzB;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,SAA0C;AAElD;AAAA,SAAQ,UAAqF;AAE7F;AAAA,SAAQ,mBAAmB;AAY3B,SAAQ,WAAsB,CAAC;AAE/B;AAAA,SAAQ,SAAS;AAEjB;AAAA,SAAQ,WAAW,oBAAI,IAAY;AAEnC;AAAA,SAAQ,WAAW,oBAAI,IAA4B;AAEnD;AAAA,SAAQ,OAAO,oBAAI,IAAyB;AAE5C,SAAQ,OAAa;AACrB,SAAQ,UAAU;AAGlB,SAAQ,eAAe,EAAE,GAAG,KAAK,GAAG,IAAI;AACxC,SAAQ,UAAgC;AACxC,SAAQ,YAA6C;AAErD;AAAA,SAAQ,iBAAgC;AAIxC;AAAA,SAAQ,WAAqB;AAC7B,SAAQ,OAAO;AACf,SAAQ,QAA0B;AAClC,SAAQ,MAAW;AAEnB;AAAA,SAAQ,QAAe;AAEvB;AAAA,SAAQ,cAAyB,CAAC;AAElC;AAAA,SAAQ,YAAY;AAEpB;AAAA,SAAQ,aAAyB;AAEjC;AAAA,SAAQ,eAAe;AACvB,SAAQ,YAAuB;AAE/B;AAAA,SAAQ,gBAAgB,oBAAI,IAAY;AAMxC;AAAA,SAAQ,SAAS;AAEjB;AAAA,SAAQ,YAAY;AAEpB;AAAA,SAAQ,aAAa;AAErB;AAAA,SAAQ,YAAY;AAEpB;AAAA,SAAQ,YAAY,oBAAI,IAAY;AAEpC;AAAA,SAAQ,WAAW;AAEnB;AAAA,SAAQ,WAAW;AAQnB;AAAA,SAAQ,iBAAkC,CAAC;AAC3C,SAAQ,iBAAiC;AAEzC;AAAA,SAAQ,iBAAiB;AAEzB;AAAA,SAAQ,iBAAiB;AAEzB;AAAA,SAAQ,cAAc;AAItB;AAAA,SAAQ,UAA+D,EAAE,cAAc,CAAC,EAAE;AAE1F;AAAA,SAAQ,MAAsB;AAE9B;AAAA,SAAQ,iBAAqD;AAE7D;AAAA,SAAQ,gBAAgB;AAGxB;AAAA,SAAQ,eAAe;AAGvB,SAAQ,WAAW;AAEnB;AAAA,SAAQ,aAAa,oBAAI,IAA4B;AAErD;AAAA,SAAQ,UAAyB;AAEjC;AAAA,SAAQ,UAAU,oBAAI,IAAY;AAElC;AAAA,SAAQ,aAAa;AAErB;AAAA,SAAQ,UAAyB,aAAa;AAG9C;AAAA,SAAQ,QAAa;AAIrB,SAAQ,WAAW;AACnB,SAAQ,YAAY;AACpB,SAAQ,WAAW;AAEnB;AAAA,SAAQ,YAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,IAAI;AACjD,SAAQ,YAAuE;AAC/E,SAAQ,cAAyE;AAEjF,SAAQ,MAAM;AAuGd,SAAQ,gBAAgB,MAAM;AAC5B,UAAI,SAAS,oBAAoB,UAAW,MAAK,KAAK,SAAS;AAAA,IACjE;AAiXA;AAAA,SAAQ,kBAAkB,oBAAI,IAAyB;AAEvD;AAAA,SAAQ,UAA2C,CAAC;AAKpD;AAAA;AAAA;AAAA;AAAA,SAAQ,UAAU,oBAAI,IAAyB;AAY/C;AAAA,SAAQ,WAAsB,UAAU;AAExC;AAAA,SAAQ,UAAsG,CAAC;AAC/G,SAAQ,aAAa;AACrB,SAAQ,cAAc;AACtB,SAAQ,YAAY;AACpB,SAAQ,UAAU;AAClB,SAAQ,YAAY;AACpB,SAAQ,aAAa;AAuUrB,SAAQ,cAAc;AA8ctB;AAAA,SAAQ,gBAA0H,CAAC;AAwVnI;AAAA,SAAQ,mBAAmB,CAAC,MAAoB;AAC9C,UAAI,EAAE,gBAAgB,WAAW,EAAE,WAAW,EAAG;AACjD,YAAM,SAAS,EAAE;AACjB,YAAM,IAAI,OAAO,sBAAsB;AACvC,WAAK,UAAU,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,EAAE,MAAM,IAAI,EAAE,KAAK,OAAO,MAAM;AAGnF,UAAI,WAAW;AACf,UAAI;AACF,YAAI,OAAO,OAAO,sBAAsB,YAAY;AAAE,iBAAO,kBAAkB,EAAE,SAAS;AAAG,qBAAW;AAAA,QAAM;AAAA,MAChH,QAAQ;AAAE,mBAAW;AAAA,MAAwC;AAC7D,UAAI,CAAC,UAAU;AACb,eAAO,iBAAiB,eAAe,KAAK,gBAAgB;AAC5D,eAAO,iBAAiB,aAAa,KAAK,cAAc;AACxD,eAAO,iBAAiB,iBAAiB,KAAK,cAAc;AAAA,MAC9D;AAAA,IACF;AAEA,SAAQ,mBAAmB,CAAC,MAAoB;AAC9C,YAAM,IAAI,KAAK;AACf,UAAI,CAAC,EAAG;AACR,YAAM,KAAK,EAAE,UAAU,EAAE,IAAI,KAAK,EAAE,UAAU,EAAE;AAChD,UAAI,CAAC,EAAE,SAAS,KAAK,MAAM,IAAI,EAAE,IAAI,mBAAoB;AACzD,UAAI,CAAC,EAAE,OAAO;AACZ,UAAE,QAAQ;AACV,aAAK,WAAW,UAAU,IAAI,UAAU;AACxC,aAAK,YAAY;AAAA,MACnB;AACA,QAAE,eAAe;AACjB,WAAK,SAAS,KAAK,YAAY,EAAE,KAAK,IAAI,EAAE,KAAK,EAAE;AACnD,WAAK,iBAAiB;AAAA,IACxB;AAEA,SAAQ,iBAAiB,MAAM;AAC7B,aAAO,oBAAoB,eAAe,KAAK,gBAAgB;AAC/D,aAAO,oBAAoB,aAAa,KAAK,cAAc;AAC3D,aAAO,oBAAoB,iBAAiB,KAAK,cAAc;AAC/D,YAAM,IAAI,KAAK;AACf,WAAK,UAAU;AACf,UAAI,CAAC,GAAG,MAAO;AACf,WAAK,WAAW,UAAU,OAAO,UAAU;AAC3C,WAAK,UAAU;AACf,WAAK,eAAe;AAEpB,WAAK,mBAAmB;AACxB,aAAO,WAAW,MAAM;AAAE,aAAK,mBAAmB;AAAA,MAAO,GAAG,CAAC;AAAA,IAC/D;AA0HA;AAAA;AAAA;AAAA;AAAA,SAAQ,SAAS,CAAC,MAAoB;AACpC,UAAI,KAAK,SAAS,UAAW;AAC7B,YAAM,SAAS,KAAK,KAAK,EAAE,SAAS,EAAE,OAAO;AAC7C,UAAI,CAAC,QAAQ;AAAE,aAAK,GAAG,MAAM,UAAU;AAAQ;AAAA,MAAQ;AACvD,YAAM,IAAI,OAAO,sBAAsB;AACvC,aAAO,OAAO,KAAK,GAAG,OAAO;AAAA,QAC3B,SAAS;AAAA,QAAS,MAAM,EAAE,OAAO;AAAA,QAAM,KAAK,EAAE,MAAM;AAAA,QACpD,OAAO,EAAE,QAAQ;AAAA,QAAM,QAAQ,EAAE,SAAS;AAAA,MAC5C,CAAC;AACD,MAAC,KAAK,GAAG,WAA2B,cAClC,OAAO,QAAQ,YAAY,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK;AAAA,IAClE;AAEA,SAAQ,UAAU,CAAC,MAAkB;AACnC,UAAI,KAAK,SAAS,UAAW;AAC7B,YAAM,SAAS,KAAK,KAAK,EAAE,SAAS,EAAE,OAAO;AAC7C,UAAI,CAAC,OAAQ;AACb,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,YAAM,IAAI,OAAO,sBAAsB;AACvC,WAAK,eAAe;AAAA,QAClB,GAAG,EAAE,QAAQ,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,QACrD,GAAG,EAAE,SAAS,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,IAAI;AAAA,MACxD;AACA,WAAK,QAAQ,KAAK;AAClB,WAAK,aAAa,EAAE,MAAM,WAAW,SAAS,OAAO,GAAG,EAAE,SAAS,EAAE,OAAO;AAAA,IAC9E;AAEA,SAAQ,QAAQ,CAAC,MAAqB;AACpC,UAAI,EAAE,QAAQ,UAAU;AAAE,aAAK,WAAW;AAAG,aAAK,QAAQ,KAAK;AAAG,aAAK,cAAc;AAAA,MAAG;AAAA,IAC1F;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,gBAAgB,CAAC,MAAqB;AAC5C,UAAI,CAAC,EAAE,UAAU,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,QAAS;AACxD,UAAI,EAAE,SAAS,WAAW,EAAE,OAAO,IAAI,YAAY,MAAM,IAAK;AAC9D,QAAE,eAAe;AACjB,WAAK,kBAAkB,CAAC,KAAK,cAAc;AAAA,IAC7C;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,kBAAkB,CAAC,MAAkB;AAC3C,UAAI,EAAE,aAAa,EAAE,SAAS,KAAK,IAAI,EAAG;AAC1C,WAAK,WAAW;AAAA,IAClB;AAGA;AAAA,SAAQ,YAAY,CAAC,MAAqB;AACxC,UAAI,EAAE,QAAQ,SAAU,MAAK,WAAW;AAAA,IAC1C;AAIA;AAAA,SAAQ,eAAe,CAAC,MAAoB;AAC1C,UAAI,KAAK,SAAS,YAAY,KAAK,SAAS,SAAU;AAEtD,UAAI,EAAE,gBAAgB,WAAW,EAAE,gBAAgB,SAAS,EAAE,WAAW,EAAG;AAE5E,YAAM,IAAI,EAAE;AACZ,UAAI,MAAM,EAAE,OAAO,gBAAgB,EAAE,UAAU,aAAa,GAAI;AAChE,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,WAAK,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ;AAC9C,eAAS,iBAAiB,eAAe,KAAK,cAAc,IAAI;AAChE,eAAS,iBAAiB,aAAa,KAAK,YAAY,IAAI;AAC5D,eAAS,iBAAiB,iBAAiB,KAAK,gBAAgB,IAAI;AACpE,WAAK,cAAc,EAAE,SAAS,EAAE,OAAO;AAAA,IACzC;AAEA,SAAQ,eAAe,CAAC,MAAoB;AAC1C,UAAI,CAAC,KAAK,UAAW;AACrB,QAAE,eAAe;AACjB,WAAK,cAAc,EAAE,SAAS,EAAE,OAAO;AAAA,IACzC;AAEA,SAAQ,aAAa,CAAC,MAAoB;AACxC,UAAI,CAAC,KAAK,UAAW;AACrB,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,YAAM,QAAQ,KAAK;AACnB,YAAM,YAAY,KAAK,SAAS;AAChC,WAAK,WAAW;AAChB,YAAM,KAAiB;AAAA,QACrB,GAAG,KAAK,IAAI,MAAM,GAAG,EAAE,OAAO;AAAA,QAAG,GAAG,KAAK,IAAI,MAAM,GAAG,EAAE,OAAO;AAAA,QAC/D,GAAG,KAAK,IAAI,EAAE,UAAU,MAAM,CAAC;AAAA,QAAG,GAAG,KAAK,IAAI,EAAE,UAAU,MAAM,CAAC;AAAA,MACnE;AACA,UAAI,GAAG,IAAI,KAAK,GAAG,IAAI,GAAG;AAAE,aAAK,OAAO,MAAM,UAAU;AAAQ;AAAA,MAAQ;AACxE,WAAK,QAAQ,KAAK;AAClB,UAAI,UAAW,MAAK,KAAK,gBAAgB,EAAE;AAAA,UACtC,MAAK,aAAa,EAAE;AAAA,IAC3B;AAGA;AAAA,SAAQ,iBAAiB,MAAM;AAC7B,WAAK,WAAW;AAChB,WAAK,OAAO,MAAM,UAAU;AAAA,IAC9B;AA8NA;AAAA,SAAQ,cAAc,CAAC,MAAkB;AACvC,UAAI,KAAK,SAAS,OAAQ;AAC1B,YAAM,IAAI,EAAE;AACZ,UAAI,MAAM,EAAE,OAAO,gBAAgB,EAAE,UAAU,aAAa,GAAI;AAChE,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,YAAM,OAAO,EAAE,UAAU,OAAO;AAChC,YAAM,OAAO,EAAE,UAAU,OAAO;AAChC,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,WAAW;AAC7D,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,YAAY;AAG9D,YAAM,SAAS,EAAE,GAAG,MAAM,OAAO,IAAI,GAAG,GAAG,MAAM,OAAO,IAAI,EAAE;AAC9D,WAAK,QAAQ,KAAK;AAClB,WAAK,aAAa,EAAE,MAAM,QAAQ,QAAQ,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO;AAAA,IAC/F;AA+QA;AAAA,SAAQ,WAAW,MAAM;AACvB,iBAAW,KAAK,KAAK,UAAU;AAC7B,cAAM,MAAM,KAAK,KAAK,IAAI,EAAE,EAAE;AAC9B,YAAI,CAAC,IAAK;AAEV,YAAI,EAAE,SAAS,QAAQ;AAErB,gBAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,WAAW;AAC7D,gBAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,YAAY;AAC9D,gBAAM,KAAK,EAAE,OAAO,IAAI,OAAO,OAAO;AACtC,gBAAM,KAAK,EAAE,OAAO,IAAI,OAAO,OAAO;AACtC,gBAAM,WAAW,KAAK,OAAO,KAAK,OAAO,aAAa,MAAM,KAAK,OAAO,KAAK,OAAO,cAAc;AAClG,iBAAO,OAAO,IAAI,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,SAAS,WAAW,SAAS,OAAO,CAAC;AACjG,cAAI,UAAU,OAAO,UAAU;AAC/B;AAAA,QACF;AAEA,YAAI,MAAM,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK;AACrC,YAAI,CAAC,OAAO,CAAC,IAAI,aAAa;AAG5B,cAAI,IAA0B;AAC9B,cAAI;AAAE,gBAAI,cAAc,EAAE,MAAM;AAAA,UAAG,QAAQ;AAAE,gBAAI;AAAA,UAAM;AACvD,gBAAM,GAAG,WAAW;AACpB,eAAK,SAAS,IAAI,EAAE,IAAI,GAAG;AAAA,QAC7B;AAEA,YAAI,EAAE,SAAS,UAAU;AAIvB,gBAAM,MAAM,KAAK,WAAW,GAAG,GAAG;AAClC,cAAI,KAAK;AACP,kBAAM,WAAW,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,cAAc,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO;AAGvG,kBAAM,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI;AAC7D,kBAAM,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI;AAC7D,mBAAO,OAAO,IAAI,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,SAAS,WAAW,SAAS,OAAO,CAAC;AACjG,gBAAI,UAAU,OAAO,YAAY,EAAE,OAAO,UAAU,EAAE,QAAQ,GAAG,MAAM,EAAE,OAAO,QAAQ,QAAQ;AAAA,UAClG,OAAO;AACL,gBAAI,MAAM,UAAU;AACpB,gBAAI,UAAU,IAAI,UAAU;AAAA,UAC9B;AACA;AAAA,QACF;AAEA,YAAI,KAAK;AACP,gBAAM,OAAO,IAAI,sBAAsB;AACvC,gBAAM,KAAK,KAAK,OAAO,EAAE,OAAO,IAAI,KAAK;AACzC,gBAAM,KAAK,KAAK,MAAM,EAAE,OAAO,IAAI,KAAK;AACxC,gBAAM,WAAW,KAAK,SAAS,KAAK,KAAK,MAAM,OAAO,eACpD,KAAK,QAAQ,KAAK,KAAK,OAAO,OAAO,cAAc,KAAK,QAAQ;AAClE,iBAAO,OAAO,IAAI,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,SAAS,WAAW,SAAS,OAAO,CAAC;AACjG,cAAI,UAAU,OAAO,UAAU;AAAA,QACjC,OAAO;AACL,cAAI,MAAM,UAAU;AACpB,cAAI,UAAU,IAAI,UAAU;AAAA,QAC9B;AAAA,MACF;AAGA,UAAI,KAAK,gBAAgB;AACvB,cAAM,IAAI,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,cAAc;AAChE,cAAM,MAAM,KAAK,KAAK,WAAW,GAAG,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,IAAI;AACnE,YAAI,KAAK;AACP,iBAAO,OAAO,KAAK,UAAU,OAAO;AAAA,YAClC,SAAS;AAAA,YAAS,MAAM,IAAI,IAAI;AAAA,YAAM,KAAK,IAAI,IAAI;AAAA,YAAM,OAAO,IAAI,IAAI;AAAA,YAAM,QAAQ,IAAI,IAAI;AAAA,UAChG,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AA0FA,SAAQ,cAAc,MAAM,KAAK,gBAAgB;AAsGjD;AAAA,SAAQ,UAAsB;AA6N9B;AAAA,SAAQ,oBAAoB,CAAC,MAAoB;AAC/C,UAAI,KAAK,aAAa,WAAW,EAAE,WAAW,KAAK,KAAK,SAAS,EAAG;AACpE,UAAK,EAAE,QAAwB,QAAQ,OAAO,EAAG;AACjD,WAAK,YAAY,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,KAAK,UAAU,GAAG,IAAI,KAAK,UAAU,EAAE;AAC5F,WAAK,KAAK,UAAU,IAAI,UAAU;AAClC,aAAO,iBAAiB,eAAe,KAAK,iBAAiB;AAC7D,aAAO,iBAAiB,aAAa,KAAK,eAAe;AAAA,IAC3D;AACA,SAAQ,oBAAoB,CAAC,MAAoB;AAC/C,UAAI,CAAC,KAAK,UAAW;AACrB,QAAE,eAAe;AACjB,WAAK,UAAU,IAAI,KAAK,UAAU,MAAM,EAAE,UAAU,KAAK,UAAU;AACnE,WAAK,UAAU,IAAI,KAAK,UAAU,MAAM,EAAE,UAAU,KAAK,UAAU;AACnE,WAAK,gBAAgB;AAAA,IACvB;AACA,SAAQ,kBAAkB,MAAM;AAC9B,UAAI,CAAC,KAAK,UAAW;AACrB,WAAK,YAAY;AACjB,WAAK,KAAK,UAAU,OAAO,UAAU;AACrC,aAAO,oBAAoB,eAAe,KAAK,iBAAiB;AAChE,aAAO,oBAAoB,aAAa,KAAK,eAAe;AAC5D,WAAK,UAAU;AAAA,IACjB;AAEA,SAAQ,eAAe,CAAC,MAAoB;AAC1C,UAAI,KAAK,aAAa,QAAS;AAC/B,QAAE,eAAe;AAAG,QAAE,gBAAgB;AACtC,WAAK,cAAc,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,KAAK,UAAU,GAAG,IAAI,KAAK,UAAU,EAAE;AAC9F,aAAO,iBAAiB,eAAe,KAAK,YAAY;AACxD,aAAO,iBAAiB,aAAa,KAAK,UAAU;AAAA,IACtD;AACA,SAAQ,eAAe,CAAC,MAAoB;AAC1C,UAAI,CAAC,KAAK,YAAa;AACvB,QAAE,eAAe;AACjB,WAAK,UAAU,IAAI,KAAK,YAAY,MAAM,EAAE,UAAU,KAAK,YAAY;AACvE,WAAK,UAAU,IAAI,KAAK,YAAY,MAAM,EAAE,UAAU,KAAK,YAAY;AACvE,WAAK,gBAAgB;AAAA,IACvB;AACA,SAAQ,aAAa,MAAM;AACzB,UAAI,CAAC,KAAK,YAAa;AACvB,WAAK,cAAc;AACnB,aAAO,oBAAoB,eAAe,KAAK,YAAY;AAC3D,aAAO,oBAAoB,aAAa,KAAK,UAAU;AACvD,WAAK,UAAU;AAAA,IACjB;AAkkBA;AAAA,SAAQ,YAAY,oBAAI,IAAoB;AAgO5C,SAAQ,cAA0C;AASlD;AAAA,SAAQ,WAAW,oBAAI,IAA6B;AAEpD;AAAA,SAAQ,YAAY,oBAAI,IAAoB;AAE5C;AAAA,SAAQ,aAAa,oBAAI,IAAY;AAErC;AAAA,SAAQ,YAAY,oBAAI,IAAY;AACpC,SAAQ,SAAS,oBAAI,IAAoB;AAwOzC;AAAA,SAAQ,QAAgB,CAAC;AA6HzB;AAAA,SAAQ,YAAY,oBAAI,IAAwB;AAgChD;AAAA,SAAQ,SAAS,oBAAI,IAA4D;AAljI/E,SAAK,MAAM;AAEX,SAAK,QAAQ,IAAI,UACb,IAAI,YAAY,IAAI,SAAS,IAAI,MAAM,IAAI,UAAU,IAAI,SAAS,IAAI,WAAW,IACjF,IAAI,oBAAoB;AAAA,EAC9B;AAAA,EAEA,IAAY,MAAM;AAAE,WAAO,SAAS,WAAW,SAAS;AAAA,EAAQ;AAAA;AAAA,EAGhE,IAAY,SAAS;AAAE,WAAO,KAAK,IAAI,SAAS;AAAA,EAAM;AAAA,EAEtD,MAAM,QAAQ;AACZ,SAAK,UAAU;AACf,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,aAAS,iBAAiB,WAAW,KAAK,aAAa;AACvD,aAAS,iBAAiB,SAAS,KAAK,iBAAiB,IAAI;AAC7D,aAAS,iBAAiB,WAAW,KAAK,SAAS;AACnD,QAAI,KAAK,IAAI,SAAU,MAAK,OAAO;AACnC,SAAK,gBAAgB;AACrB,SAAK,UAAU,KAAK;AACpB,SAAK,WAAW,MAAM,KAAK,MAAM,KAAK,KAAK,IAAI,YAAY,KAAK,GAAG;AACnE,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,cAAc;AACnB,SAAK,iBAAiB;AAEtB,QAAI,KAAK,OAAQ,MAAK,qBAAqB;AAC3C,SAAK,KAAK,kBAAkB;AAC5B,SAAK,KAAK,QAAQ;AAClB,SAAK,KAAK,aAAa;AACvB,SAAK,iBAAiB;AACtB,SAAK,cAAc;AAGnB,SAAK,KAAK,gBAAgB;AAC1B,SAAK,QAAQ;AACb,SAAK,gBAAgB;AAGrB,QAAI,CAAC,KAAK,YAAY,KAAK,QAAQ,CAAC,KAAK,SAAS,EAAG,MAAK,UAAU;AACpE,QAAI,KAAK,IAAI,SAAU,MAAK,QAAQ,KAAK,IAAI,SAAS,SAAS,SAAS,SAAS;AAAA,EACnF;AAAA;AAAA,EAGA,SAAS,MAA0B;AACjC,SAAK,OAAO;AACZ,SAAK,gBAAgB;AACrB,SAAK,QAAQ,SAAS,SAAS,SAAS,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB;AACxB,UAAM,WAAW,MAAM;AACrB,UAAI,KAAK,QAAQ,KAAK,QAAS;AAC/B,WAAK,UAAU,KAAK;AACpB,WAAK,KAAK,eAAe;AAAA,IAC3B;AACA,qBAAiB,YAAY,QAAQ;AAErC,eAAW,OAAO,CAAC,aAAa,cAAc,GAAY;AACxD,YAAM,WAAW,QAAQ,GAAG;AAC5B,cAAQ,GAAG,IAAI,YAA4B,MAAiB;AAC1D,cAAM,SAAU,SAA0C,MAAM,MAAM,IAAI;AAC1E,sBAAc,IAAI,MAAM,sBAAsB,CAAC;AAC/C,eAAO;AAAA,MACT;AAAA,IACF;AACA,qBAAiB,wBAAwB,QAAQ;AAAA,EACnD;AAAA,EAEA,MAAc,iBAAiB;AAC7B,QAAI;AACF,WAAK,WAAW,MAAM,KAAK,MAAM,KAAK,KAAK,IAAI,YAAY,KAAK,GAAG;AACnE,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB,QAAQ;AAAA,IAAkD;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,gBAAgB;AACtB,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW,YAAY,MAAM,KAAK,KAAK,SAAS,GAAG,YAAY;AACpE,aAAS,iBAAiB,oBAAoB,KAAK,aAAa;AAAA,EAClE;AAAA,EAMA,MAAc,WAAW;AACvB,QAAI,KAAK,YAAY,SAAS,oBAAoB,SAAU;AAE5D,UAAM,SAAS,KAAK,QAAQ;AAC5B,QAAI,WAAW,OAAO,YAAY,cAAc,OAAO,YAAY,SAAU;AAC7E,SAAK,WAAW;AAChB,QAAI;AACF,YAAM,MAAM,KAAK;AACjB,YAAM,UAAU,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;AACxC,YAAM,CAAC,MAAM,KAAK,GAAG,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,QAChD,KAAK,MAAM,KAAK,KAAK,IAAI,YAAY,GAAG,EAAE,MAAM,MAAM,IAAI;AAAA,QAC1D,KAAK,aAAa,KAAK,UAAU,QAAQ,KAAK,MAAM,QAAQ,KAAK,IAAI,UAAU,EAAE,MAAM,MAAM,IAAI,IAAI;AAAA,QACrG,GAAG,QAAQ,IAAI,CAAC,OAAO,KAAK,MAAM,aAAa,EAAE,EAAE,MAAM,MAAM,IAAI,CAAC;AAAA,MACtE,CAAC;AAED,UAAI,QAAQ,KAAK,IAAK;AACtB,UAAI,UAAU;AACd,UAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,KAAK,QAAQ,GAAG;AACjF,aAAK,WAAW;AAChB,kBAAU;AAAA,MACZ;AACA,UAAI,MAAM,QAAQ,GAAG,KAAK,KAAK,UAAU,GAAG,MAAM,KAAK,UAAU,KAAK,WAAW,GAAG;AAClF,aAAK,cAAc;AACnB,kBAAU;AAAA,MACZ;AACA,cAAQ,QAAQ,CAAC,IAAI,MAAM;AACzB,cAAM,OAAO,QAAQ,CAAC;AACtB,YAAI,CAAC,MAAM,QAAQ,IAAI,EAAG;AAE1B,cAAM,SAAS,KAAK,SAAS,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,KAAK,WAAW,IAAI,EAAE,EAAE,KAAK,KAAK,UAAU,IAAI,EAAE,EAAE,CAAC;AAC/G,cAAM,OAAO,CAAC,GAAG,MAAM,GAAG,KAAK;AAC/B,YAAI,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,KAAK,SAAS,IAAI,EAAE,CAAC,EAAG;AACpE,aAAK,SAAS,IAAI,IAAI,IAAI;AAC1B,kBAAU;AAAA,MACZ,CAAC;AACD,UAAI,SAAS;AACX,aAAK,WAAW;AAChB,aAAK,WAAW;AAChB,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,UAAE;AACA,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,KAAK,kBAAkB;AAAA,EAC9B;AAAA;AAAA,EAIQ,WAAW;AACjB,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,KAAK,KAAK;AACf,aAAS,KAAK,YAAY,KAAK,IAAI;AACnC,SAAK,SAAS,KAAK,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAErD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,cAAc;AACpB,SAAK,OAAO,YAAY,KAAK;AAE7B,SAAK,UAAU,GAAG,OAAO,SAAS;AAClC,SAAK,KAAK,GAAG,OAAO,IAAI;AACxB,SAAK,GAAG,YAAY,GAAG,QAAQ,KAAK,CAAC;AACrC,SAAK,SAAS,GAAG,OAAO,QAAQ;AAChC,SAAK,YAAY,GAAG,OAAO,YAAY;AACvC,SAAK,QAAQ,OAAO,KAAK,IAAI,KAAK,QAAQ,KAAK,SAAS;AACxD,SAAK,OAAO,YAAY,KAAK,OAAO;AAEpC,SAAK,WAAW,GAAG,OAAO,UAAU;AACpC,SAAK,OAAO,YAAY,KAAK,QAAQ;AAErC,SAAK,OAAO,KAAK,UAAU;AAC3B,SAAK,aAAa,KAAK,gBAAgB;AACvC,SAAK,YAAY,GAAG,UAAU,YAAY;AAC1C,SAAK,UAAU,OAAO;AACtB,SAAK,UAAU,QAAQ;AACvB,SAAK,UAAU,aAAa,cAAc,mBAAmB;AAC7D,SAAK,UAAU,UAAU,MAAM,KAAK,kBAAkB,KAAK;AAC3D,SAAK,SAAS,KAAK,YAAY;AAC/B,SAAK,UAAU,GAAG,OAAO,OAAO;AAChC,SAAK,QAAQ,aAAa,QAAQ,QAAQ;AAC1C,SAAK,QAAQ,aAAa,aAAa,QAAQ;AAC/C,SAAK,QAAQ,UAAU,MAAM,KAAK,QAAQ,UAAU,OAAO,MAAM;AAIjE,SAAK,SAAS,GAAG,OAAO,MAAM;AAC9B,SAAK,WAAW,GAAG,OAAO,WAAW;AACrC,SAAK,WAAW,GAAG,OAAO,WAAW;AACrC,SAAK,OAAO,OAAO,KAAK,UAAU,KAAK,QAAQ;AAE/C,SAAK,OAAO,OAAO,KAAK,MAAM,KAAK,YAAY,KAAK,WAAW,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AAGrG,SAAK,OAAO,iBAAiB,SAAS,CAAC,MAAM;AAC3C,YAAM,IAAI,EAAE;AACZ,UAAI,GAAG,WAAW,EAAE,QAAQ,YAAY,EAAG;AAC3C,WAAK,WAAW;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YAAyB;AAC/B,UAAM,OAAO,GAAG,OAAO,MAAM;AAG7B,UAAM,OAAO,GAAG,OAAO,OAAO;AAC9B,UAAM,QAAQ,GAAG,OAAO,OAAO;AAC/B,UAAM,YAAY;AAClB,IAAC,MAAM,cAAc,QAAQ,EAAkB,cAAc,KAAK,IAAI,SAAS;AAC/E,SAAK,iBAAiB,eAAe,KAAK,iBAAiB;AAE3D,UAAM,MAAM,GAAG,OAAO,MAAM;AAI5B,UAAM,UAAU,GAAG,OAAO,WAAW;AACrC,UAAM,SAAS,GAAG,QAAQ;AAC1B,WAAO,QAAQ,OAAO;AACtB,WAAO,QAAQ;AACf,WAAO,aAAa,cAAc,gBAAgB;AAClD,WAAO,YAAY;AACnB,SAAK,UAAU,GAAG,OAAO,MAAM;AAC/B,UAAM,UAA6D;AAAA,MACjE,EAAE,MAAM,QAAQ,MAAM,aAAa,OAAO,OAAO;AAAA,MACjD,EAAE,MAAM,UAAU,MAAM,eAAe,OAAO,SAAS;AAAA,MACvD,EAAE,MAAM,SAAS,MAAM,cAAc,OAAO,QAAQ;AAAA,MACpD,EAAE,MAAM,SAAS,MAAM,SAAS,OAAO,QAAQ;AAAA,IACjD;AACA,SAAK,QAAQ,YAAY,iEACvB,QAAQ,IAAI,CAAC,MAAM,qBAAqB,EAAE,IAAI,KAAK,EAAE,IAAI,SAAS,EAAE,KAAK,kBAAkB,EAAE,KAAK,EAAE,IACpG;AACF,SAAK,QAAQ,iBAA8B,YAAY,EAAE,QAAQ,CAAC,MAAM;AACtE,QAAE,UAAU,MAAM;AAAE,aAAK,QAAQ,EAAE,QAAQ,GAAe;AAAG,aAAK,WAAW;AAAA,MAAG;AAAA,IAClF,CAAC;AACD,WAAO,UAAU,MAAM,KAAK,WAAW,KAAK,OAAO;AACnD,YAAQ,OAAO,QAAQ,KAAK,OAAO;AAEnC,SAAK,WAAW,GAAG,QAAQ;AAC3B,SAAK,SAAS,QAAQ,OAAO;AAC7B,SAAK,SAAS,UAAU,MAAM,KAAK,YAAY;AAG/C,UAAM,UAAU,GAAG,OAAO,WAAW;AACrC,UAAM,SAAS,GAAG,QAAQ;AAC1B,WAAO,QAAQ,OAAO;AACtB,WAAO,QAAQ;AACf,WAAO,aAAa,cAAc,UAAU;AAC5C,WAAO,YAAY;AACnB,WAAO,UAAU,MAAM,KAAK,WAAW,KAAK,YAAY;AAIxD,SAAK,eAAe,GAAG,OAAO,MAAM;AACpC,SAAK,aAAa,YAChB,mEAEA,QAAQ,IAAI,CAAC,MACX,wCAAwC,EAAE,EAAE,uBAAuB,EAAE,IAAI,YAC/D,EAAE,EAAE,iBAAiB,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,IAClE,0jBAI+H,iBAAiB,yTAIvG,WAAW,WAAW,CAAC,OAAO,KAAK,mBAAmB,CAAC,kCACrE,KAAK,IAAI,UAAU,WAAW,SAAS;AACpE,SAAK,aAAa,iBAA8B,eAAe,EAAE,QAAQ,CAAC,MAAM;AAC9E,QAAE,UAAU,MAAM,KAAK,UAAU,EAAE,QAAQ,MAAO;AAAA,IACpD,CAAC;AACD,SAAK,aAAa,iBAA8B,YAAY,EAAE,QAAQ,CAAC,MAAM;AAC3E,QAAE,UAAU,MAAM;AAChB,cAAM,MAAM,EAAE,QAAQ;AACtB,YAAI,QAAQ,QAAQ;AAAE,eAAK,WAAW;AAAG,eAAK,UAAU;AAAG;AAAA,QAAQ;AACnE,YAAI,QAAQ,YAAY;AAAE,eAAK,WAAW;AAAG,eAAK,sBAAsB;AAAG;AAAA,QAAQ;AACnF,aAAK,cAAc,GAAsE;AAAA,MAC3F;AAAA,IACF,CAAC;AACD,YAAQ,OAAO,QAAQ,KAAK,YAAY;AAExC,UAAM,SAAS,GAAG,QAAQ;AAC1B,WAAO,QAAQ,OAAO;AACtB,WAAO,QAAQ;AACf,WAAO,aAAa,cAAc,UAAU;AAC5C,WAAO,YAAY;AACnB,WAAO,UAAU,MAAM,KAAK,aAAa,IAAI;AAE7C,UAAM,WAAW,GAAG,QAAQ;AAC5B,aAAS,QAAQ,OAAO;AACxB,aAAS,QAAQ;AACjB,aAAS,aAAa,cAAc,OAAO;AAC3C,aAAS,YAAY;AACrB,aAAS,UAAU,MAAM,KAAK,UAAU;AACxC,QAAI,OAAO,SAAS,KAAK,UAAU,SAAS,QAAQ,QAAQ;AAK5D,SAAK,SAAS,GAAG,OAAO,OAAO;AAG/B,QAAI,CAAC,KAAK,IAAI,OAAQ,MAAK,OAAO,MAAM,UAAU;AAClD,SAAK,OAAO,OAAO,KAAK,QAAQ,GAAG;AAGnC,SAAK,SAAS,GAAG,OAAO,QAAQ;AAChC,SAAK,OAAO,UAAU,MAAM,KAAK,aAAa,KAAK;AAGnD,SAAK,UAAU,CAAC,GAAG,cAAc,IAAI,KAAK,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;AACpG,UAAM,OAAO,GAAG,OAAO,MAAM;AAC7B,eAAW,KAAK,KAAK,SAAS;AAC5B,YAAM,MAAM,EAAE,OAAO,UAAU,CAAC,KAAK;AACrC,YAAM,IAAI,GAAG,UAAU,MAAM,YAAY,OAAO,EAAE,KAAK;AACvD,QAAE,QAAQ,MAAM,EAAE;AAClB,UAAI,KAAK;AACP,UAAE,aAAa,iBAAiB,MAAM;AACtC,UAAE,QAAQ;AAAA,MACZ;AACA,QAAE,UAAU,MAAM,KAAK,OAAO,EAAE,EAAE;AAClC,WAAK,YAAY,CAAC;AAAA,IACpB;AAGA,UAAM,QAAQ,GAAG,OAAO,OAAO;AAC/B,UAAM,aAAa,KAAK,QAAQ,UAAK,WAAW,SAAS;AACzD,eAAW,QAAQ;AACnB,eAAW,UAAU,MAAM,KAAK,QAAQ,KAAK,SAAS,YAAY,QAAQ,SAAS;AACnF,UAAM,UAAU,KAAK,QAAQ,WAAW,QAAQ,MAAM;AACtD,YAAQ,QAAQ;AAChB,YAAQ,UAAU,MAAM,KAAK,QAAQ,KAAK,SAAS,SAAS,QAAQ,MAAM;AAC1E,UAAM,YAAY,KAAK,QAAQ,aAAa,UAAU,QAAQ;AAC9D,cAAU,QAAQ;AAClB,cAAU,UAAU,MAAM,KAAK,QAAQ,KAAK,SAAS,WAAW,QAAQ,QAAQ;AAChF,UAAM,YAAY,KAAK,QAAQ,aAAa,UAAU,QAAQ;AAC9D,cAAU,QAAQ,cAAc,IAC5B,gDACA;AACJ,cAAU,UAAU,MAAM,KAAK,QAAQ,KAAK,SAAS,WAAW,QAAQ,QAAQ;AAShF,QAAI,eAAe,GAAG;AACpB,YAAM,OAAO,YAAY,SAAS,WAAW,SAAS;AAAA,IACxD,WAAW,cAAc,GAAG;AAC1B,YAAM,WAAW,KAAK,QAAQ,YAAY,SAAS,OAAO;AAC1D,eAAS,QAAQ;AACjB,eAAS,UAAU,MAAM,KAAK,UAAU;AACxC,YAAM,OAAO,YAAY,SAAS,WAAW,QAAQ;AAAA,IACvD,OAAO;AACL,YAAM,OAAO,YAAY,SAAS,SAAS;AAAA,IAC7C;AAGA,UAAM,WAAW,GAAG,OAAO,UAAU;AACrC,aAAS,OAAO,SAAS,eAAe,UAAU,CAAC;AACnD,SAAK,UAAU,GAAG,QAAQ,SAAS,GAAG;AACtC,aAAS,YAAY,KAAK,OAAO;AACjC,UAAM,SAAS,GAAG,SAAS,QAAQ;AACnC,WAAO,OAAO;AACd,WAAO,cAAc;AACrB,WAAO,QAAQ,KAAK;AACpB,WAAO,UAAU,MAAM;AAAE,WAAK,SAAS,OAAO;AAAO,WAAK,WAAW;AAAA,IAAG;AACxE,aAAS,YAAY,MAAM;AAC3B,UAAM,UAAU,GAAG,OAAO,aAAa;AACvC,SAAK,YAAY,GAAG,UAAU,WAAW;AACzC,SAAK,UAAU,aAAa,cAAc,kBAAkB;AAC5D,SAAK,UAAU;AAAA,MAAO,SAAS,gBAAgB,IAAI,CAAC,KAAK,YAAY;AAAA,MACnE,GAAI,OAAO,KAAK,YAAY,EAAoC,IAAI,CAAC,MAAM,SAAS,aAAa,CAAC,GAAG,GAAG,KAAK,iBAAiB,CAAC,CAAC;AAAA,IAAC;AACnI,SAAK,UAAU,WAAW,MAAM;AAAE,WAAK,eAAe,KAAK,UAAW;AAAO,WAAK,UAAU;AAAG,WAAK,WAAW;AAAA,IAAG;AAClH,SAAK,UAAU,GAAG,UAAU,SAAS;AACrC,SAAK,QAAQ,aAAa,cAAc,OAAO;AAC/C,SAAK,QAAQ,OAAO,SAAS,gBAAgB,UAAU,KAAK,GAAG,SAAS,gBAAgB,UAAU,KAAK,GAAG,SAAS,cAAc,QAAQ,KAAK,CAAC;AAC/I,SAAK,QAAQ,WAAW,MAAM;AAAE,WAAK,YAAY,KAAK,QAAS;AAAoB,WAAK,UAAU;AAAG,WAAK,WAAW;AAAA,IAAG;AACxH,YAAQ,OAAO,KAAK,WAAW,KAAK,OAAO;AAC3C,SAAK,SAAS,GAAG,OAAO,MAAM;AAG9B,UAAM,WAAW,GAAG,OAAO,gBAAgB;AAC3C,SAAK,SAAS;AAGd,UAAM,eAAe,GAAG,OAAO,oBAAoB;AACnD,SAAK,eAAe,GAAG,OAAO,WAAW;AACzC,SAAK,YAAY,GAAG,OAAO,WAAW;AACtC,SAAK,UAAU,MAAM,UAAU;AAC/B,iBAAa,OAAO,KAAK,cAAc,OAAO,UAAU,SAAS,KAAK,WAAW,KAAK,QAAQ,KAAK,kBAAkB,CAAC;AAKtH,UAAM,eAAe,GAAG,OAAO,oBAAoB;AACnD,SAAK,aAAa;AAIlB,UAAM,WAAW,GAAG,OAAO,gBAAgB;AAC3C,SAAK,SAAS;AAId,UAAM,eAAe,KAAK,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM;AACnD,YAAM,OAAO,GAAG,OAAO,kBAAkB;AACzC,YAAM,OAAO,GAAG,OAAO,WAAW;AAClC,WAAK,YAAY,IAAI;AACrB,WAAK,gBAAgB,IAAI,EAAE,IAAI,IAAI;AACnC,UAAI;AACF,cAAM,MAAM,EAAE,OAAO;AAAA,UACnB,YAAY,KAAK,IAAI;AAAA,UACrB,SAAS,KAAK,IAAI;AAAA,UAClB,MAAM,KAAK,IAAI;AAAA,UACf,UAAU,KAAK;AAAA,UACf,KAAK,KAAK;AAAA,UACV,SAAS;AAAA,UACT,OAAO,CAAC,UAAU,KAAK,YAAY,KAAK;AAAA,UACxC,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE;AAAA,UAC5B,OAAO,MAAM,KAAK,UAAU;AAAA,QAC9B,CAAC;AACD,YAAI,OAAO,QAAQ,UAAU;AAG3B,gBAAM,OAAO,GAAG,OAAO,UAAU;AACjC,eAAK,YAAY;AACjB,eAAK,OAAO,GAAG,MAAM,KAAK,KAAK,UAAU,CAAC;AAAA,QAC5C,WAAW,IAAK,MAAK,YAAY,GAAG;AAAA,MACtC,SAAS,GAAG;AAEV,aAAK,YAAY,GAAG,OAAO,SAAS,8BAA8B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE,CAAC;AAAA,MACjH;AACA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,SAAS,GAAG,OAAO,QAAQ;AACjC,WAAO,iBAAiB,eAAe,KAAK,YAAY;AAIxD,SAAK,YAAY,GAAG,OAAO,SAAS;AACpC,SAAK,UAAU,MAAM,UAAU;AAE/B,SAAK,OAAO,MAAM,KAAK,QAAQ,KAAK,WAAW,MAAM,UAAU,cAAc,cAAc,UAAU,GAAG,aAAa,MAAM;AAC3H,eAAW,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,YAAY,YAAY,GAAG,CAAC,YAAY,YAAY,GAAG,CAAC,QAAQ,QAAQ,CAAC,GAA8B;AACpJ,WAAK,QAAQ,IAAI,IAAI,IAAI;AAAA,IAC3B;AACA,gBAAY,QAAQ,CAAC,GAAG,MAAM,KAAK,QAAQ,KAAK,KAAK,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAG,IAAI,CAAC,CAAC;AAC/E,SAAK,eAAe;AACpB,SAAK,mBAAmB;AACxB,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAuCQ,iBAAiB;AACvB,SAAK,OAAO,YACV;AAcF,UAAM,QAAQ,KAAK,OAAO,cAAc,eAAe;AACvD,UAAM,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAC1D,UAAM,UAAU,MAAM;AAAE,WAAK,YAAY;AAAI,WAAK,gBAAgB;AAAA,IAAG;AACrE,UAAM,YAAY,CAAC,MAAM;AACvB,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AAAE,UAAE,eAAe;AAAG,aAAK,KAAK,cAAc;AAAA,MAAG;AAAA,IACzF;AAEA,IAAC,KAAK,OAAO,cAAc,gBAAgB,EAAkB,UAAU,CAAC,MAAM;AAC5E,QAAE,gBAAgB;AAClB,WAAK,KAAK,mBAAmB;AAAA,IAC/B;AACA,IAAC,KAAK,OAAO,cAAc,iBAAiB,EAAkB,UAAU,CAAC,MAAM;AAC7E,QAAE,gBAAgB;AAClB,WAAK,KAAK,cAAc;AAAA,IAC1B;AACA,IAAC,KAAK,OAAO,cAAc,gBAAgB,EAAkB,UAAU,CAAC,MAAM;AAC5E,QAAE,gBAAgB;AAClB,WAAK,YAAY;AAAA,IACnB;AAEA,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGQ,kBAAkB;AACxB,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAM,MAAM,KAAK,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,MAAM;AACzD,UAAM,UAAU,KAAK,QAAQ,iBAA8B,YAAY;AACvE,UAAM,MAAM,UAAU,GAAG;AACzB,QAAI,CAAC,IAAK;AACV,QAAI,cAAc,KAAK,aAAa,aAAU,KAAK,aAAa,IAAI,OAAO,KAAK,UAAU,KAAK;AAAA,EACjG;AAAA,EAEQ,kBAAkB;AACxB,UAAM,MAAM,KAAK,QAAQ,cAAc,gBAAgB;AACvD,QAAI,IAAK,KAAI,cAAc,KAAK;AAAA,EAClC;AAAA,EAEQ,iBAAiB;AACvB,UAAM,MAAM,KAAK,QAAQ,cAAc,aAAa;AACpD,QAAI,CAAC,IAAK;AACV,QAAI,cAAc;AAClB,QAAI,CAAC,KAAK,SAAS,MAAM,QAAQ;AAAE,UAAI,MAAM,UAAU;AAAQ;AAAA,IAAQ;AACvE,QAAI,MAAM,UAAU;AAEpB,UAAM,OAAO,GAAG,OAAO,WAAW;AAClC,SAAK;AAAA,MACH,GAAG,QAAQ,cAAc,YAAY,KAAK,QAAQ,CAAC;AAAA,MACnD,GAAG,QAAQ,aAAa;AAAA,IAC1B;AACA,UAAM,QAAQ,GAAG,UAAU,UAAU,OAAO;AAC5C,UAAM,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,WAAW,UAAU;AAAG,WAAK,eAAe;AAAA,IAAG;AAClG,SAAK,YAAY,KAAK;AACtB,QAAI,YAAY,IAAI;AAEpB,SAAK,SAAS,MAAM,QAAQ,CAAC,MAAM,MAAM;AACvC,YAAM,OAAO,GAAG,OAAO,eAAe,KAAK,UAAU,KAAK,OAAO;AAEjE,YAAM,QAAQ,GAAG,OAAO;AACxB,YAAM,OAAO;AACb,YAAM,UAAU,KAAK;AACrB,YAAM,QAAQ;AACd,YAAM,WAAW,CAAC,MAAM;AACtB,UAAE,gBAAgB;AAClB,aAAK,WAAW,cAAc,KAAK,UAAU,KAAK,EAAE;AACpD,aAAK,eAAe;AAAA,MACtB;AAEA,YAAM,QAAQ,GAAG,QAAQ,cAAc,KAAK,KAAK;AACjD,YAAM,QAAQ,KAAK,SAAS,KAAK,MAAM,WAAM,KAAK,GAAG,KAAK;AAE1D,YAAM,KAAK,GAAG,UAAU,cAAc,QAAG;AACzC,SAAG,WAAW,MAAM;AACpB,SAAG,UAAU,CAAC,MAAM;AAAE,UAAE,gBAAgB;AAAG,aAAK,WAAW,YAAY,KAAK,UAAU,KAAK,IAAI,EAAE;AAAG,aAAK,eAAe;AAAA,MAAG;AAE3H,YAAM,OAAO,GAAG,UAAU,cAAc,QAAG;AAC3C,WAAK,WAAW,MAAM,KAAK,SAAS,MAAM,SAAS;AACnD,WAAK,UAAU,CAAC,MAAM;AAAE,UAAE,gBAAgB;AAAG,aAAK,WAAW,YAAY,KAAK,UAAU,KAAK,IAAI,CAAC;AAAG,aAAK,eAAe;AAAA,MAAG;AAE5H,YAAM,IAAI,GAAG,UAAU,UAAU,QAAG;AACpC,QAAE,QAAQ;AACV,QAAE,UAAU,CAAC,MAAM;AAAE,UAAE,gBAAgB;AAAG,aAAK,WAAW,eAAe,KAAK,UAAU,KAAK,EAAE;AAAG,aAAK,eAAe;AAAA,MAAG;AAEzH,WAAK,OAAO,OAAO,KAAK,SAAS,MAAM;AAAE,cAAM,MAAM,GAAG,OAAO,YAAY;AAAuB,YAAI,MAAM,KAAK;AAAQ,YAAI,MAAM;AAAI,eAAO;AAAA,MAAK,GAAG,IAAI,GAAG,QAAQ,aAAa,KAAK,IAAI,GAAG,OAAO,IAAI,MAAM,CAAC;AAChN,UAAI,YAAY,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB;AACtB,UAAM,MAAM,KAAK,QAAQ,cAAc,gBAAgB;AACvD,QAAI,CAAC,IAAK;AACV,QAAI,cAAc;AAClB,QAAI,CAAC,KAAK,QAAQ,QAAQ;AACxB,UAAI,YAAY;AAAA,QAAG;AAAA,QAAO;AAAA,QACxB,KAAK,IAAI,SACL,+FACA;AAAA,MAAoF,CAAC;AAC3F;AAAA,IACF;AACA,eAAW,KAAK,KAAK,SAAS;AAC5B,YAAM,MAAM,GAAG,OAAO,cAAc,EAAE,OAAO,UAAU,GAAG;AAC1D,YAAM,OAAO,GAAG,OAAO,WAAW;AAClC,WAAK;AAAA,QACH,GAAG,KAAK,YAAY,EAAE,OAAO,QAAS,EAAE,UAAU,OAAQ;AAAA,QAC1D,GAAG,QAAQ,aAAa,OAAO,EAAE,EAAE,CAAC;AAAA,MACtC;AACA,UAAI,EAAE,MAAO,MAAK,YAAY,GAAG,QAAQ,YAAY,GAAG,EAAE,KAAK,WAAW,EAAE,UAAU,IAAI,KAAK,GAAG,EAAE,CAAC;AACrG,YAAM,OAAO,GAAG,OAAO,WAAW;AAClC,iBAAW,OAAO,gBAAgB,EAAE,MAAM,cAAc,EAAE,IAAI,CAAC,GAAG;AAChE,YAAI,IAAI,QAAS,MAAK,YAAY,GAAG,QAAQ,WAAW,IAAI,IAAI,CAAC;AAAA,YAC5D,MAAK,YAAY,SAAS,eAAe,IAAI,IAAI,CAAC;AAAA,MACzD;AACA,UAAI,OAAO,MAAM,IAAI;AACrB,UAAI,YAAY,GAAG;AAAA,IACrB;AACA,QAAI,YAAY,IAAI;AAAA,EACtB;AAAA;AAAA,EAGA,MAAc,qBAAqB;AACjC,UAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,OAAO,EAAE;AAC/C,QAAI,CAAC,MAAM;AAAE,WAAK,YAAY;AAAyB,WAAK,gBAAgB;AAAG;AAAA,IAAQ;AACvF,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,mBAAmB;AAClD,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,OAAO,IAAI,MAAM,CAAC;AAC/C,YAAM,EAAE,UAAU,IAAK,MAAM,IAAI,KAAK;AACtC,UAAI,CAAC,WAAW;AAAE,aAAK,YAAY;AAAyB,aAAK,gBAAgB;AAAG;AAAA,MAAQ;AAC5F,WAAK,WAAW,UAAU,KAAK,UAAU;AAAA,QACvC,IAAI,UAAU,iBAAiB,UAAU,YAAY,OAAO,UAAU,EAAE;AAAA,QACxE,MAAM;AAAA;AAAA,QAEN,OAAO,GAAG,UAAU,YAAY,UAAU,OAAO,SAAS,GAAG,UAAU,OAAO,iBAAO,OAAO,UAAU,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC,WAAM,EAAE;AAAA,QAChI,KAAK,UAAU;AAAA,QACf,KAAK,UAAU,iBAAiB,UAAU;AAAA,MAC5C,CAAC;AACD,WAAK,YAAY;AACjB,WAAK,gBAAgB;AACrB,WAAK,eAAe;AAAA,IACtB,SAAS,GAAG;AACV,WAAK,YAAY,aAAa,QAAQ,iCAAiC,EAAE,OAAO,KAAK;AACrF,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB;AAC5B,UAAM,QAAQ,KAAK,OAAO,cAAc,eAAe;AACvD,UAAM,OAAO,MAAM,MAAM,KAAK;AAC9B,UAAM,WAAW,YAAY,KAAK,QAAQ;AAE1C,QAAI,CAAC,QAAQ,CAAC,SAAS,OAAQ;AAC/B,QAAI,KAAK,YAAa;AAEtB,UAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,OAAO,EAAE;AAC/C,QAAI,CAAC,MAAM;AAAE,WAAK,YAAY;AAAiD,WAAK,gBAAgB;AAAG;AAAA,IAAQ;AAE/G,SAAK,cAAc;AACnB,SAAK,YAAY;AACjB,SAAK,gBAAgB;AACrB,UAAM,aAAa;AAAA,MACjB,IAAI,WAAW,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,MACtC,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC3B,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,OAAO,SAAS;AAAA,IAClB;AACA,SAAK,QAAQ,KAAK,UAAU;AAC5B,SAAK,cAAc;AAEnB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,cAAc;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM,QAAQ;AAAA,UACd,QAAQ,EAAE,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK;AAAA,UACzD;AAAA,UACA,aAAa,cAAc,KAAK,QAAQ,EACrC,OAAO,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,KAAK,EAChD,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAQ,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE;AAAA,UAC/D,OAAO,KAAK,UAAU,SAAS;AAAA,QACjC,CAAC;AAAA,MACH,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,uBAAuB,IAAI,MAAM,EAAE;AAEhE,YAAM,QAAQ;AACd,WAAK,WAAW,UAAU;AAC1B,WAAK,eAAe,EAAE;AACtB,WAAK,eAAe;AACpB,WAAK,YAAY,EAAE,MAAM,kBAAkB,OAAO,4BAA4B,SAAS,SAAS,KAAK,SAAS,MAAM,eAAe,EAAE,GAAG,CAAC;AAAA,IAC3I,SAAS,GAAG;AACV,WAAK,YAAY,aAAa,QAAQ,EAAE,UAAU;AAClD,WAAK,gBAAgB;AACrB,WAAK,YAAY,EAAE,MAAM,SAAS,OAAO,SAAS,OAAO,mCAAmC,CAAC;AAAA,IAC/F,UAAE;AACA,WAAK,cAAc;AACnB,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,eAAe,GAAW;AAAE,SAAK,YAAY;AAAA,EAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhD,cAAc;AACpB,UAAM,UAAU,aAAa;AAAA,MAC3B,SAAS,OAAQ,WAAmB,sBAAsB,eAAe,OAAQ,WAAmB,4BAA4B;AAAA,MAChI,iBAAiB,OAAO,oBAAoB,YAAY,kBAAkB;AAAA,IAC5E,CAAC;AACD,QAAI,YAAY,aAAa;AAC3B,WAAK,YAAY,aAAa,OAAO,KAAK;AAC1C,WAAK,gBAAgB;AACrB;AAAA,IACF;AACA,QAAI,KAAK,QAAS,QAAO,KAAK,cAAc;AAE5C,UAAM,OAAQ,WAAmB,qBAAsB,WAAmB;AAC1E,UAAM,QAAQ,KAAK,OAAO,cAAc,eAAe;AACvD,QAAI;AAGF,WAAK,cAAc;AACnB,YAAM,MAAM,IAAI,KAAK;AACrB,UAAI,aAAa;AACjB,UAAI,iBAAiB;AACrB,UAAI,OAAO,SAAS,gBAAgB,QAAQ;AAE5C,WAAK,YAAY,MAAM,QAAQ,GAAG,MAAM,MAAM,KAAK,CAAC,MAAM;AAC1D,UAAI,WAAW,CAAC,OAAY;AAC1B,YAAI,OAAO;AACX,iBAAS,IAAI,GAAG,aAAa,IAAI,GAAG,QAAQ,QAAQ,IAAK,SAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE;AAClF,cAAM,QAAQ,GAAG,KAAK,SAAS,GAAG,IAAI;AAAA,MACxC;AACA,UAAI,UAAU,CAAC,OAAY;AACzB,aAAK,YAAY,IAAI,UAAU,gBAAgB,uCAAuC;AACtF,aAAK,gBAAgB;AACrB,aAAK,cAAc;AAAA,MACrB;AACA,UAAI,QAAQ,MAAM;AAAE,YAAI,KAAK,QAAS,MAAK,cAAc;AAAA,MAAG;AAC5D,UAAI,MAAM;AACV,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,UAAU;AACf,WAAK,aAAa,KAAK,IAAI;AAC3B,YAAM,OAAO,KAAK,OAAO,cAAc,gBAAgB;AACvD,WAAK,MAAM,UAAU;AACrB,WAAK,aAAa,YAAY,MAAM;AAClC,cAAM,IAAI,KAAK,OAAO,cAAc,oBAAoB;AACxD,YAAI,EAAG,GAAE,cAAc,aAAa,KAAK,IAAI,IAAI,KAAK,UAAU;AAAA,MAClE,GAAG,GAAG;AACN,WAAK,OAAO,cAAc,gBAAgB,EAAG,UAAU,IAAI,IAAI;AAC/D,WAAK,eAAe;AAAA,IACtB,SAAS,GAAG;AACV,WAAK,YAAY,aAAa,QAAQ,EAAE,UAAU;AAClD,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,gBAAgB;AACtB,SAAK,UAAU;AACf,QAAI,KAAK,WAAY,eAAc,KAAK,UAAU;AAClD,SAAK,aAAa;AAGlB,SAAK,UAAU;AACf,UAAM,OAAO,KAAK,QAAQ,cAAc,gBAAgB;AACxD,QAAI,KAAM,MAAK,MAAM,UAAU;AAC/B,SAAK,QAAQ,cAAc,gBAAgB,GAAG,UAAU,OAAO,IAAI;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,uBAAuB;AAC7B,UAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,OAAO,EAAE;AAC/C,QAAI,CAAC,QAAQ,KAAK,gBAAiB;AACnC,QAAI,OAAO,gBAAgB,YAAa;AACxC,QAAI;AACF,YAAM,SAAS,IAAI,YAAY,GAAG,IAAI,SAAS;AAE/C,aAAO,iBAAiB,aAAa,CAAC,OAAO;AAC3C,YAAI;AACJ,YAAI;AAAE,mBAAS,KAAK,MAAO,GAAoB,IAAI;AAAA,QAAG,QAAQ;AAAE;AAAA,QAAQ;AACxE,YAAI,QAAQ,cAAc,QAAS,MAAK,aAAa,OAAO,IAAI;AAAA,MAClE,CAAC;AACD,aAAO,UAAU,MAAM;AAAA,MAAC;AACxB,WAAK,kBAAkB;AAGvB,WAAK,gBAAgB,YAAY,MAAM,KAAK,KAAK,YAAY,GAAG,GAAI;AAAA,IACtE,QAAQ;AAEN,WAAK,gBAAgB,YAAY,MAAM,KAAK,KAAK,YAAY,GAAG,GAAI;AAAA,IACtE;AAAA,EACF;AAAA,EAKA,MAAc,cAAc;AAC1B,UAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,OAAO,EAAE;AAC/C,QAAI,CAAC,KAAM;AACX,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,oBAAoB,mBAAmB,KAAK,WAAW,CAAC,EAAE;AACzF,UAAI,CAAC,IAAI,GAAI;AACb,YAAM,EAAE,QAAQ,IAAK,MAAM,IAAI,KAAK;AACpC,iBAAW,KAAK,WAAW,CAAC,EAAG,MAAK,aAAa,CAAC;AAAA,IACpD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,aAAa,OAAY;AAC/B,QAAI,CAAC,OAAO,MAAM,CAAC,MAAM,KAAM;AAG/B,QAAI,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,EAAG;AACjD,SAAK,cAAc,MAAM;AACzB,SAAK,QAAQ,KAAK,EAAE,IAAI,MAAM,IAAI,IAAI,MAAM,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC;AAE3G,QAAI,KAAK,QAAQ,UAAU,KAAK,WAAW;AACzC,WAAK;AACL,WAAK,gBAAgB;AACrB,WAAK,cAAc,kCAA6B,MAAM,IAAI;AAAA,IAC5D;AACA,SAAK,YAAY,EAAE,MAAM,eAAe,OAAO,oBAAoB,CAAC;AACpE,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGQ,cAAc,OAAe,MAAc;AACjD,QAAI;AACF,YAAM,IAAK,WAAmB;AAC9B,UAAI,CAAC,KAAK,EAAE,eAAe,UAAW;AACtC,UAAI,EAAE,OAAO,EAAE,MAAM,OAAO,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,kBAAkB,CAAC;AAAA,IAC3E,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,qBAAqB;AAC3B,SAAK,WAAW,YACd;AAWF,SAAK,SAAS,KAAK,WAAW,cAAc,iBAAiB;AAC7D,SAAK,eAAe,KAAK,WAAW,cAAc,cAAc;AAEhE,IAAC,KAAK,WAAW,cAAc,yBAAyB,EAAkB,UAAU,MAAM,KAAK,cAAc;AAI7G,SAAK,OAAO,iBAAiB,UAAU,MAAM;AAC3C,YAAMC,MAAK,KAAK;AAChB,WAAK,iBAAiBA,IAAG,eAAeA,IAAG,YAAYA,IAAG,eAAe;AACzE,WAAK,qBAAqB;AAAA,IAC5B,CAAC;AAGD,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA,EAKA,YAAY,OAA2B;AACrC,UAAM,QAAuB;AAAA,MAC3B,IAAI,MAAM,MAAM,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,MACpF,IAAI,MAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,MACvC,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM,SAAS;AAAA,MACtB,OAAO,MAAM;AAAA,IACf;AACA,SAAK,eAAe,KAAK,KAAK;AAE9B,QAAI,KAAK,eAAe,SAAS,IAAK,MAAK,iBAAiB,KAAK,eAAe,MAAM,IAAI;AAE1F,SAAK,iBAAiB,MAAM,UAAU,UAAU,UAAU;AAC1D,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,kBAAkB,QAAwB;AACxC,SAAK,iBAAiB;AACtB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,gBAAgB;AACd,SAAK,iBAAiB,CAAC;AACvB,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AACtB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAAe;AAC3B,QAAI,KAAK,aAAc;AACvB,QAAI;AACJ,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,cAAc,KAAK,KAAK,KAAK;AACrD,eAAS,OAAO,MAAM,KAAK,KAAK,IAAI,YAAY,KAAK,iBAAiB,MAAS,IAAI;AAAA,IACrF,QAAQ;AACN,UAAI,KAAK,mBAAmB,QAAQ;AAClC,aAAK,iBAAiB;AACtB,aAAK,eAAe;AAAA,MACtB;AACA;AAAA,IACF;AACA,QAAI,WAAW,MAAM;AAEnB,WAAK,iBAAiB;AACtB,WAAK,eAAe;AACpB,WAAK,iBAAiB;AACtB,WAAK,eAAe;AACpB;AAAA,IACF;AACA,SAAK,iBAAiB;AACtB,UAAM,QAAQ,IAAI,IAAI,KAAK,eAAe,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC1D,UAAM,QAAQ,OAAO,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,OAAO,YAAY,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;AACpF,QAAI,MAAM,QAAQ;AAChB,WAAK,iBAAiB,CAAC,GAAG,KAAK,gBAAgB,GAAG,KAAK,EACpD,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC,EACvC,MAAM,IAAI;AACb,YAAM,SAAS,MAAM,OAAO,CAAC,GAAG,MAAO,EAAE,KAAK,IAAI,EAAE,KAAK,GAAI,KAAK,aAAa;AAC/E,WAAK,gBAAgB;AAErB,YAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,GAAI,EAAE,YAAY;AACxE,UAAI,MAAM,KAAK,CAAC,MAAM,EAAE,UAAU,WAAW,EAAE,MAAM,aAAa,EAAG,MAAK,iBAAiB;AAAA,IAC7F;AACA,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA,EAGQ,mBAAmB;AACzB,UAAM,OAAO,KAAK,QAAQ,cAAc,CAAC,KAAK,gBAAgB,CAAC,CAAC,KAAK,MAAM;AAC3E,QAAI,QAAQ,CAAC,KAAK,cAAc;AAC9B,WAAK,eAAe,YAAY,MAAM,KAAK,KAAK,aAAa,GAAG,IAAM;AAAA,IACxE,WAAW,CAAC,QAAQ,KAAK,cAAc;AACrC,oBAAc,KAAK,YAAY;AAC/B,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAGQ,uBAAuB;AAC7B,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,SAAS,KAAK,WAAW,cAAc,mBAAmB;AAGhE,QAAI,CAAC,OAAQ;AACb,UAAM,IAAI,kBAAkB,KAAK,gBAAgB,KAAK,cAAc;AAEpE,WAAO,cAAc,mBAAmB,EAAG,cAAc,uBAAuB,EAAE,MAAM;AACxF,WAAO,YAAY,iBAAiB,EAAE,MAAM;AAC5C,UAAM,OAAO,OAAO,cAAc,iBAAiB;AACnD,QAAI,MAAM;AACR,WAAK,cAAc,KAAK,mBAAmB,SAAS,SAAS,KAAK,mBAAmB,YAAY,YAAY;AAC7G,WAAK,YAAY,YAAY,KAAK,cAAc;AAAA,IAClD;AAEA,UAAM,UAAU,KAAK,WAAW,cAAc,oBAAoB;AAClE,QAAI,CAAC,EAAE,QAAQ;AACb,cAAQ,YAAY;AACpB,cAAQ,MAAM,UAAU;AAAA,IAC1B,OAAO;AACL,cAAQ,MAAM,UAAU;AACxB,YAAM,OAA2B;AAAA,QAC/B,CAAC,UAAU,uBAAuB,EAAE,MAAM,CAAC;AAAA,QAC3C,CAAC,UAAU,OAAO,EAAE,MAAM,CAAC;AAAA,QAC3B,CAAC,YAAY,eAAe,EAAE,UAAU,CAAC;AAAA,QACzC,CAAC,iBAAiB,OAAO,EAAE,KAAK,CAAC;AAAA,QACjC,CAAC,UAAU,OAAO,EAAE,MAAM,CAAC;AAAA,QAC3B,CAAC,SAAS,EAAE,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,QAAK,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,KAAK,QAAG;AAAA,MAC1E;AACA,cAAQ,YACN,sEAAsE,KAAK,WAAW,kFAExD,EAAE,MAAM,gBAAa,eAAe,EAAE,UAAU,CAAC,SAAM,EAAE,KAAK,wCACjE,KAAK,cAAc,WAAM,QAAG,4CAC3B,KAAK,cAAc,KAAK,uBAAuB,MAC3E,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,6BAA6B,WAAW,CAAC,CAAC,aAAa,WAAW,CAAC,CAAC,YAAY,EAAE,KAAK,EAAE,IAC9G;AAGF,cAAQ,cAAc,cAAc,EAAG,cACrC,KAAK,eAAe,KAAK,eAAe,SAAS,CAAC,GAAG,SAAS;AAChE,MAAC,QAAQ,cAAc,0BAA0B,EAAkB,UAAU,MAAM;AACjF,aAAK,cAAc,CAAC,KAAK;AACzB,aAAK,qBAAqB;AAAA,MAC5B;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,WAAW,cAAc,kBAAkB;AAC9D,UAAM,cAAc;AACpB,QAAI,EAAE,QAAQ;AACZ,YAAM;AAAA,QACJ,GAAG,QAAQ,eAAe,UAAK,eAAe,EAAE,UAAU,CAAC,EAAE;AAAA,QAC7D,GAAG,QAAQ,eAAe,UAAK,EAAE,MAAM,SAAS;AAAA,QAChD,GAAG,QAAQ,eAAe,UAAK,EAAE,KAAK,QAAQ;AAAA,MAChD;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,WAAW,cAAc,kBAAkB;AAC9D,UAAM,cAAc;AACpB,QAAI,EAAE,QAAQ;AACZ,YAAM,OAAO,CAAC,MAAc,OAAe,UAAkB;AAC3D,cAAM,IAAI,GAAG,UAAU,cAAc,KAAK,mBAAmB,OAAO,QAAQ,KAAK,GAAG,KAAK,IAAI,KAAK,EAAE;AACpG,UAAE,QAAQ,OAAO;AACjB,UAAE,UAAU,MAAM;AAChB,eAAK,iBAAiB,KAAK,mBAAmB,OAAO,KAAK;AAC1D,eAAK,eAAe;AAAA,QACtB;AACA,eAAO;AAAA,MACT;AACA,YAAM,YAAY,KAAK,IAAI,OAAO,EAAE,MAAM,CAAC;AAC3C,iBAAW,EAAE,MAAM,MAAM,KAAK,EAAE,OAAQ,OAAM,YAAY,KAAK,MAAM,MAAM,KAAK,CAAC;AAAA,IACnF;AAAA,EACF;AAAA;AAAA,EAGQ,iBAAiB;AACvB,QAAI,CAAC,KAAK,WAAY;AACtB,SAAK,qBAAqB;AAC1B,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,SAAS,KAAK,iBAChB,KAAK,eAAe,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,cAAc,IAChE,KAAK;AAET,QAAI,CAAC,OAAO,QAAQ;AAClB,WAAK,OAAO,YACV,6BACC,KAAK,eAAe,SACjB,mBAAmB,WAAW,KAAK,cAAc,CAAC,cAClD,KAAK,mBAAmB,SACxB,iFACA,0NAGJ;AACF;AAAA,IACF;AAEA,SAAK,OAAO,YAAY,OAAO,IAAI,CAAC,MAAM;AACxC,YAAM,OAAO,IAAI,KAAK,EAAE,EAAE,EAAE,mBAAmB,QAAW,EAAE,QAAQ,MAAM,CAAC;AAC3E,aAAO,0BAA0B,EAAE,SAAS,MAAM,4BACtB,WAAW,IAAI,CAAC,iCAChB,WAAW,EAAE,IAAI,CAAC,kCACjB,WAAW,EAAE,KAAK,CAAC,MAC7C,EAAE,SAAS,4BAA4B,WAAW,EAAE,MAAM,CAAC,YAAY,MACxE;AAAA,IACJ,CAAC,EAAE,KAAK,EAAE;AAEV,QAAI,KAAK,eAAgB,MAAK,OAAO,YAAY,KAAK,OAAO;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAiB;AACvB,UAAM,QAAQ,KAAK,IAAI,SAAS;AAChC,SAAK,OAAO,YACV,y4BAoBsB,WAAW,KAAK,CAAC,6BAA0B,WAAW,WAAW,CAAC,UAAU,KAAK,mBAAmB,CAAC;AAE7H,IAAC,KAAK,OAAO,cAAc,yBAAyB,EAAkB,UAAU,CAAC,MAAM;AACrF,QAAE,gBAAgB;AAClB,WAAK,eAAe,CAAC,KAAK,QAAQ;AAAA,IACpC;AAEA,SAAK,OAAO,iBAA8B,WAAW,EAAE,QAAQ,CAAC,MAAM;AACpE,QAAE,UAAU,MAAM,KAAK,SAAS,EAAE,QAAQ,UAAU,QAAQ,QAAQ,MAAM;AAAA,IAC5E,CAAC;AACD,IAAC,KAAK,OAAO,cAAc,wBAAwB,EAA0B,UAAU,MAAM;AAC3F,WAAK,OAAO,UAAU;AACtB,WAAK,QAAQ,SAAS;AAAA,IACxB;AACA,IAAC,KAAK,OAAO,cAAc,WAAW,EAA0B,UAAU,MAAM;AAC9E,WAAK,KAAK,eAAe;AACzB,UAAI,KAAK,UAAU,MAAO,MAAK,KAAK,gBAAgB;AAAA,IACtD;AAAA,EACF;AAAA;AAAA,EAGA,IAAY,kBAA6B;AACvC,WAAO,KAAK,UAAU,QAAQ,KAAK,cAAc,KAAK;AAAA,EACxD;AAAA;AAAA,EAGQ,SAAS,OAAc;AAC7B,SAAK,QAAQ;AACb,SAAK,UAAU;AAEf,QAAI,UAAU,SAAS,CAAC,KAAK,YAAY,OAAQ,MAAK,KAAK,gBAAgB;AAC3E,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAc,kBAAkB;AAC9B,QAAI;AACF,WAAK,cAAc,MAAM,KAAK,MAAM,QAAQ,KAAK,IAAI,UAAU;AAC/D,WAAK,YAAY;AACjB,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB,QAAQ;AAAA,IAA8B;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAA6D;AACnE,UAAM,OAAO,KAAK;AAClB,UAAM,UAAU,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK;AAChD,WAAO;AAAA,MACL,EAAE,KAAK,QAAQ,OAAO,QAAQ,GAAG,KAAK,OAAO,CAAC,MAAM,gBAAgB,EAAE,MAAM,MAAM,UAAU,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,MAIrG,EAAE,KAAK,aAAa,OAAO,aAAa,GAAG,KAAK,OAAO,CAAC,MAAM,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO;AAAA,MAC3G,EAAE,KAAK,YAAY,OAAO,YAAY,GAAG,KAAK,OAAO,CAAC,MAAM,gBAAgB,EAAE,MAAM,MAAM,UAAU,EAAE,OAAO;AAAA,MAC7G;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,GAAG,KAAK,OAAO,CAAC,MAAM,gBAAgB,EAAE,MAAM,MAAM,cAAc,KAAK,MAAM,EAAE,SAAS,IAAI,OAAO,EAAE;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa;AACnB,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAM,QAAQ,KAAK,UAAU;AAC7B,UAAM,UAAU,KAAK,OAAO,cAAc,eAAe;AACzD,QAAI,SAAS;AACX,cAAQ,YAAY,MACjB,IAAI,CAAC,MACJ,yBAAyB,KAAK,eAAe,EAAE,MAAM,QAAQ,EAAE,gBAAgB,EAAE,GAAG,2BAC3D,EAAE,CAAC,gCAAgC,EAAE,KAAK,kBAAkB,EACtF,KAAK,EAAE;AACV,cAAQ,iBAA8B,UAAU,EAAE,QAAQ,CAAC,MAAM;AAC/D,UAAE,UAAU,MAAM;AAChB,gBAAM,MAAM,EAAE,QAAQ;AAEtB,eAAK,aAAa,KAAK,eAAe,MAAM,KAAK;AACjD,eAAK,OAAO,UAAU;AAAA,QACxB;AAAA,MACF,CAAC;AAAA,IACH;AAKA,UAAM,WAAW,KAAK,aAAa,KAAK,UAAU;AAClD,UAAM,SAAgC;AAAA,MACpC,MAAM,OAAO,KAAK,SAAS,MAAM;AAAA,MACjC,KAAK,WAAW,OAAO,KAAK,YAAY,MAAM,IAAI;AAAA,IACpD;AACA,UAAM,SAAgC,EAAE,MAAM,aAAa,KAAK,MAAM;AACtE,SAAK,OAAO,iBAA8B,WAAW,EAAE,QAAQ,CAAC,MAAM;AACpE,YAAM,QAAS,EAAE,QAAQ,UAAU,QAAQ,QAAQ;AACnD,QAAE,UAAU,OAAO,MAAM,UAAU,KAAK,KAAK;AAC7C,QAAE,aAAa,gBAAgB,OAAO,UAAU,KAAK,KAAK,CAAC;AAC3D,QAAE,aAAa,cAAc,GAAG,OAAO,KAAK,CAAC,WAAM,OAAO,KAAK,CAAC,WAAW;AAC3E,MAAC,EAAE,cAAc,WAAW,EAAkB,cAAc,OAAO,KAAK;AAAA,IAC1E,CAAC;AACD,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,UAAM,OAAO,KAAK,OAAO,cAAc,cAAc;AACrD,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,CAAC,GAAG,KAAK,eAAe,EACpC,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC,EACrD,MAAM,GAAG,CAAC;AACb,SAAK,YAAY,OAAO,SACpB,OAAO,IAAI,CAAC,MAAM;AAChB,YAAM,QAAQ,aAAa,gBAAgB,EAAE,MAAM,CAAC;AACpD,YAAM,OAAO,kBAAkB,EAAE,QAAQ;AAEzC,aAAO,4DAA4D,WAAW,EAAE,EAAE,CAAC,2BACxD,WAAW,EAAE,UAAU,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,gCACjE,WAAW,EAAE,QAAQ,QAAQ,EAAE,CAAC,sBAAmB,WAAW,KAAK,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,OAAO,EAAE,SAAS,CAAC,6CACzG,gBAAgB,EAAE,MAAM,CAAC,KAAK,KAAK,uCACnC,IAAI,KAAK,gBAAgB,IAAI,CAAC,oFAEd,WAAW,CAAC,IAAI,WAAW,SAAS;AAAA,IAIxF,CAAC,EAAE,KAAK,EAAE,IACV;AACJ,SAAK,iBAA8B,UAAU,EAAE,QAAQ,CAAC,MAAM;AAC5D,YAAM,KAAK,EAAE,QAAQ;AACrB,YAAM,OAAO,MAAM;AACjB,aAAK,aAAa;AAClB,aAAK,eAAe;AACpB,aAAK,OAAO,UAAU;AACtB,aAAK,SAAS,IAAI,EAAE;AACpB,cAAM,IAAI,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACxC,YAAI,EAAG,MAAK,KAAK,aAAa,CAAC;AAC/B,aAAK,WAAW;AAChB,aAAK,MAAM,EAAE;AAAA,MACf;AACA,QAAE,UAAU;AACZ,QAAE,YAAY,CAAC,MAAM;AAAE,YAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AAAE,YAAE,eAAe;AAAG,eAAK;AAAA,QAAG;AAAA,MAAE;AAC/F,QAAE,iBAAoC,YAAY,EAAE,QAAQ,CAAC,QAAQ;AACnE,YAAI,UAAU,CAAC,MAAM;AACnB,YAAE,gBAAgB;AAClB,gBAAM,IAAI,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACxC,cAAI,CAAC,EAAG;AACR,cAAI,IAAI,QAAQ,QAAQ,OAAQ,MAAK;AAAA,mBAC5B,IAAI,QAAQ,QAAQ,UAAW,MAAK,KAAK,eAAe,CAAC;AAAA,mBACzD,IAAI,QAAQ,QAAQ,UAAU;AAErC,gBAAI,IAAI,QAAQ,MAAO,MAAK,KAAK,cAAc,CAAC;AAAA,iBAC3C;AACH,kBAAI,QAAQ,QAAQ;AACpB,kBAAI,cAAc;AAClB,yBAAW,MAAM;AAAE,oBAAI,IAAI,aAAa;AAAE,yBAAO,IAAI,QAAQ;AAAO,sBAAI,cAAc;AAAA,gBAAU;AAAA,cAAE,GAAG,GAAI;AAAA,YAC3G;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAMA,MAAc,oBAAoB;AAChC,QAAI;AAIF,YAAM,OAAO,MAAM,KAAK,MAAM,kBAAkB,KAAK,IAAI,YAAY,KAAK,IAAI,KAAK,EAAE;AACrF,WAAK,gBAAgB,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;AAAA,IACrD,QAAQ;AACN,WAAK,gBAAgB,CAAC;AAAA,IACxB;AACA,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAAsB;AAC5B,UAAM,MAAM,KAAK,QAAQ,cAAc,eAAe;AACtD,QAAI,CAAC,IAAK;AACV,UAAM,SAAS,KAAK,cAAc,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM;AACzD,QAAI,CAAC,OAAO,QAAQ;AAAE,UAAI,YAAY;AAAI,UAAI,MAAM,UAAU;AAAQ;AAAA,IAAQ;AAC9E,QAAI,MAAM,UAAU;AACpB,QAAI,YACF,uDAAuD,OAAO,MAAM,eAAe,OAAO,WAAW,IAAI,KAAK,GAAG,mBACjH,OAAO,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MACtB,qCAAqC,WAAW,EAAE,QAAQ,CAAC,wBACrC,WAAW,EAAE,IAAI,CAAC,6BAClB,WAAW,OAAO,EAAE,SAAS,CAAC,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAClF;AAEF,QAAI,iBAA8B,OAAO,EAAE,QAAQ,CAAC,MAAM;AACxD,QAAE,UAAU,MAAM;AAChB,cAAM,KAAK,EAAE,QAAQ;AACrB,aAAK,QAAQ;AACb,YAAI,CAAC,KAAK,YAAY,OAAQ,MAAK,KAAK,gBAAgB;AACxD,aAAK,aAAa;AAClB,aAAK,OAAO,UAAU;AACtB,aAAK,SAAS,IAAI,EAAE;AACpB,aAAK,WAAW;AAChB,aAAK,MAAM,EAAE;AAAA,MACf;AAAA,IACF,CAAC;AACD,IAAC,IAAI,cAAc,UAAU,EAAkB,UAAU,YAAY;AACnE,UAAI;AACF,cAAM,KAAK,MAAM,sBAAsB,KAAK,IAAI,YAAY,KAAK,IAAI,KAAK,EAAE;AAAA,MAC9E,QAAQ;AAAA,MAA6D;AACrE,WAAK,KAAK,kBAAkB;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAIQ,eAAe,MAAe;AACpC,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGA,MAAc,UAAU;AACtB,QAAI;AACF,WAAK,MAAO,MAAM,KAAK,MAAM,SAAS,KAAM;AAAA,IAC9C,QAAQ;AACN,WAAK,MAAM;AAAA,IACb;AACA,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGQ,eAAuB;AAC7B,UAAM,MAAM,KAAK;AACjB,UAAM,OAAO,KAAK,QAAQ,QAAQ,KAAK,IAAI;AAC3C,WAAO,KAAK,eAAe,GAAG,IAAI,SAAM,IAAI,aAAa,IAAI,KAAK;AAAA,EACpE;AAAA;AAAA,EAGQ,iBAAyB;AAC/B,UAAM,MAAM,KAAK;AACjB,UAAM,OAAO;AACb,QAAI,CAAC,KAAK,cAAc;AACtB,aAAO,OAAO,0BAA0B,KAAK,QACzC,4FACA,4IACuD;AAAA,IAC7D;AACA,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,SAAS,IAAI;AACnB,WAAO,OACL,0BAA0B,WAAW,IAAI,QAAQ,QAAQ,KAAK,IAAI,UAAU,CAAC,cACvE,WAAW,IAAI,aAAa,IAAI,CAAC,0CACR,OAC3B,oBAAoB,WAAW,KAAK,IAAI,CAAC,UACzC,+BAA+B,wCACD,OAAO,SACrC,OAAO,IAAI,CAAC,MACV,sBAAsB,EAAE,gBAAgB,QAAQ,EAAE,6BAA6B,WAAW,EAAE,IAAI,CAAC,aAChG,EAAE,WAAW,mDAAmD,MAAM,QAAQ,EAAE,KAAK,EAAE,IAC1F,6EAA6E;AAAA,EACrF;AAAA,EAEQ,qBAAqB;AAC3B,UAAM,MAAM,KAAK,QAAQ,cAAc,eAAe;AACtD,QAAI,CAAC,IAAK;AACV,QAAI,cAAc,KAAK;AACvB,QAAI,MAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EAC5C;AAAA,EAEQ,gBAAgB;AACtB,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAM,OAAO,KAAK,OAAO,cAAc,YAAY;AACnD,UAAM,MAAM,KAAK,OAAO,cAAc,aAAa;AACnD,QAAI,CAAC,QAAQ,CAAC,IAAK;AACnB,IAAC,KAAK,cAAc,YAAY,EAAkB,cAAc,KAAK,aAAa;AAClF,SAAK,UAAU,OAAO,SAAS,CAAC,KAAK,KAAK,YAAY;AACtD,SAAK,aAAa,iBAAiB,OAAO,KAAK,QAAQ,CAAC;AAExD,QAAI,CAAC,KAAK,UAAU;AAAE,UAAI,UAAU,OAAO,MAAM;AAAG,UAAI,YAAY;AAAI;AAAA,IAAQ;AAChF,QAAI,UAAU,IAAI,MAAM;AAExB,UAAM,OAAO,KAAK,QAAQ;AAC1B,QAAI,YACF,KAAK,eAAe,IACpB,yGAE2B,KAAK,SAC5B,KAAK,IAAI,CAAC,GAAG,MACX,qDAAqD,WAAW,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,4CAC/C,CAAC,yDAAoD,EAAE,KAAK,EAAE,IACrG,0DAA0D,mHAEpD,WAAW,KAAK,QAAQ,CAAC,yWAMzB,WAAW,KAAK,QAAQ,SAAS,OAAO,EAAE,CAAC,mIAE3C,WAAW,KAAK,QAAQ,SAAS,SAAS,EAAE,CAAC;AAMzD,SAAK,mBAAmB;AAExB,IAAC,IAAI,cAAc,wBAAwB,EAAkB,UAAU,MAAM,KAAK,eAAe,KAAK;AAEtG,QAAI,iBAA8B,eAAe,EAAE,QAAQ,CAAC,MAAM;AAChE,QAAE,UAAU,MAAM;AAChB,cAAM,IAAI,OAAO,EAAE,QAAQ,KAAK;AAChC,aAAK,QAAQ,eAAe,KAAK,QAAQ,aAAa,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC;AAC9E,aAAK,YAAY;AACjB,aAAK,cAAc;AAAA,MACrB;AAAA,IACF,CAAC;AAED,UAAM,MAAM,IAAI,cAAc,aAAa;AAC3C,QAAI,KAAK;AACP,UAAI,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AACxD,UAAI,UAAU,MAAM;AAAE,aAAK,WAAW,IAAI;AAAA,MAAO;AACjD,UAAI,YAAY,CAAC,MAAM;AAAE,YAAI,EAAE,QAAQ,QAAS,CAAC,IAAI,cAAc,uBAAuB,EAAkB,MAAM;AAAA,MAAG;AAAA,IACvH;AACA,IAAC,IAAI,cAAc,uBAAuB,EAAkB,UAAU,MAAM;AAC1E,YAAM,aAAa,gBAAgB,KAAK,QAAQ;AAChD,UAAI,CAAC,YAAY;AACf,aAAK,YAAY;AACjB,aAAK,mBAAmB;AACxB;AAAA,MACF;AACA,UAAI,KAAK,QAAQ,aAAa,SAAS,UAAU,GAAG;AAClD,aAAK,YAAY;AACjB,aAAK,mBAAmB;AACxB;AAAA,MACF;AACA,WAAK,QAAQ,eAAe,CAAC,GAAG,KAAK,QAAQ,cAAc,UAAU;AACrE,WAAK,WAAW;AAChB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,cAAc;AACnB,MAAC,IAAI,cAAc,aAAa,GAA+B,MAAM;AAAA,IACvE;AAGA,eAAW,OAAO,CAAC,cAAc,cAAc,GAAG;AAChD,UAAI,cAAc,GAAG,GAAG,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAAA,IAC9E;AACA,IAAC,IAAI,cAAc,uBAAuB,EAAkB,UAAU,MAAM;AAC1E,YAAMC,OAAM,gBAAiB,IAAI,cAAc,YAAY,EAAuB,KAAK;AACvF,YAAM,QAAS,IAAI,cAAc,cAAc,EAAuB,MAAM,KAAK;AACjF,UAAI,CAACA,QAAO,CAAC,OAAO;AAClB,aAAK,iBAAiB,KAAK,QAAQ,UAC/B,UAAU,KAAK,QAAQ,QAAQ,KAAK,OAAO,KAAK,QAAQ,QAAQ,GAAG,KACnE,oBAAoB;AACxB,aAAK,YAAY,CAACA,OAAM,mDAAmD;AAC3E,aAAK,mBAAmB;AACxB;AAAA,MACF;AACA,WAAK,YAAY;AACjB,WAAK,WAAW,EAAE,KAAAA,MAAK,MAAM,CAAC;AAC9B,WAAK,iBAAiB,UAAU,KAAK,OAAOA,IAAG,EAAE;AAAA,IACnD;AACA,IAAC,IAAI,cAAc,uBAAuB,EAAkB,UAAU,MAAM;AAC1E,WAAK,KAAK,YAAY,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAGQ,cAAc;AACpB,UAAM,cAAc,KAAK,IAAI,gBAAgB,CAAC,GAAG,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AACjG,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,iBAAiB,KAAK,IAAI,UAAU,EAAE;AAEvE,YAAM,IAAI,MAAM,KAAK,MAAM,GAAG,IAAI;AAClC,YAAM,SAAS,MAAM,QAAQ,GAAG,YAAY,IACvC,EAAE,aAA2B,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IAC9E;AACJ,YAAM,UAAU,GAAG,WAAW,OAAO,EAAE,QAAQ,QAAQ,YAAY,OAAO,EAAE,QAAQ,UAAU,WAC1F,EAAE,KAAK,EAAE,QAAQ,KAAe,OAAO,EAAE,QAAQ,MAAgB,IACjE;AACJ,WAAK,UAAU,EAAE,cAAc,UAAU,YAAY,QAAQ;AAAA,IAC/D,QAAQ;AACN,WAAK,UAAU,EAAE,cAAc,WAAW;AAAA,IAC5C;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI;AACF,mBAAa,QAAQ,iBAAiB,KAAK,IAAI,UAAU,IAAI,KAAK,UAAU,KAAK,OAAO,CAAC;AAAA,IAC3F,QAAQ;AAAA,IAA4B;AAAA,EACtC;AAAA;AAAA,EAGQ,oBAAiC;AACvC,UAAM,OAAO,GAAG,OAAO,cAAc;AACrC,SAAK,OAAO,GAAG,OAAO,UAAU,iBAAiB,CAAC;AAClD,UAAM,MAAM,GAAG,OAAO,MAAM;AAC5B,UAAM,QAA4B;AAAA,MAChC,CAAC,UAAU,QAAQ;AAAA,MACnB,CAAC,SAAS,OAAO;AAAA,MACjB,CAAC,YAAY,UAAU;AAAA,MACvB,CAAC,UAAU,QAAQ;AAAA,IACrB;AACA,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO;AAChC,YAAM,IAAI,GAAG,QAAQ,MAAM;AAC3B,QAAE,QAAQ,GAAG,IAAI;AACjB,QAAE,aAAa,cAAc,IAAI;AACjC,QAAE,YAAY;AACd,UAAI,YAAY,CAAC;AAAA,IACnB;AACA,SAAK,YAAY,GAAG;AACpB,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,cAA2B;AACjC,UAAM,MAAM,GAAG,UAAU,QAAQ;AACjC,QAAI,QAAQ;AACZ,QAAI,aAAa,cAAc,gBAAgB;AAC/C,QAAI,UAAU,MAAM,KAAK,gBAAgB;AACzC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,kBAA+B;AACrC,UAAM,UAAU,GAAG,OAAO,aAAa;AAEvC,UAAM,QAAQ,GAAG,OAAO,WAAW;AACnC,UAAM,OAAO,CAAC,MAAc,MAAcC,QAAe,UAAkB;AACzE,YAAM,IAAI,GAAG,UAAU,UAAU;AACjC,QAAE,QAAQ,MAAM;AAChB,QAAE,QAAQ;AACV,QAAE,aAAa,cAAc,KAAK;AAClC,QAAE,YAAY,GAAG,IAAI,yBAAyBA,MAAK;AACnD,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,WAAW,WAAW,eAAe,6BAA6B;AACvF,YAAQ,UAAU,MAAM;AAAE,WAAK,YAAY;AAAG,WAAK,SAAS;AAAG,WAAK,QAAQ,SAAS;AAAA,IAAG;AACxF,UAAM,OAAO,KAAK,QAAQ,QAAQ,QAAQ,kCAAkC;AAC5E,SAAK,UAAU,MAAM;AAAE,WAAK,YAAY;AAAG,WAAK,SAAS;AAAG,WAAK,QAAQ,MAAM;AAAA,IAAG;AAClF,UAAM,UAAU,KAAK,WAAW,OAAO,WAAW,uCAAuC;AACzF,YAAQ,UAAU,MAAM,KAAK,cAAc;AAC3C,UAAM,OAAO;AAAA,MAAK;AAAA,MAAQ;AAAA,MAAW;AAAA,MACnC,cAAc,IAAI,wEAAmE,6BAAwB,iBAAiB;AAAA,IAAiB;AACjJ,SAAK,UAAU,MAAM,KAAK,kBAAkB,IAAI;AAChD,UAAM,OAAO,SAAS,MAAM,SAAS,IAAI;AAGzC,QAAI,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,GAAG;AAChD,YAAM,UAAU,KAAK,WAAW,QAAQ,kBAAkB,kCAAkC;AAC5F,cAAQ,UAAU,MAAM;AAAE,aAAK,YAAY;AAAG,aAAK,SAAS;AAAG,aAAK,OAAO,SAAS;AAAA,MAAG;AACvF,YAAM,YAAY,OAAO;AAAA,IAC3B;AAEA,UAAM,QAAQ,KAAK,IAAI,SAAS;AAChC,UAAM,UAAU,GAAG,UAAU,UAAU;AACvC,YAAQ,QAAQ,QAAQ,KAAK;AAC7B,YAAQ,aAAa,cAAc,QAAQ,KAAK,EAAE;AAClD,YAAQ,YAAY;AACpB,SAAK,WAAW,QAAQ,cAAc,SAAS;AAG/C,YAAQ,UAAU,MAAM;AAAE,UAAI,KAAK,iBAAkB;AAAQ,WAAK,SAAS;AAAA,IAAG;AAC9E,YAAQ,iBAAiB,eAAe,KAAK,gBAAgB;AAC7D,YAAQ,iBAAiB,eAAe,KAAK,gBAAgB;AAC7D,YAAQ,iBAAiB,aAAa,KAAK,cAAc;AACzD,YAAQ,iBAAiB,iBAAiB,KAAK,cAAc;AAI7D,UAAM,OAAO,GAAG,UAAU,UAAU;AACpC,SAAK,QAAQ,MAAM;AACnB,SAAK,QAAQ;AACb,SAAK,aAAa,cAAc,eAAe;AAC/C,SAAK,aAAa,iBAAiB,OAAO;AAC1C,SAAK,YAAY;AACjB,SAAK,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,UAAU;AAAA,IAAG;AAE/D,UAAM,OAAO,GAAG,OAAO,UAAU;AACjC,SAAK,OAAO,SAAS,IAAI;AACzB,YAAQ,OAAO,OAAO,IAAI;AAC1B,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,YAAY;AAClB,SAAK,cAAc,CAAC,KAAK;AACzB,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAqDQ,YAAY,GAAW,GAAqC;AAClE,UAAM,IAAI;AACV,WAAO;AAAA,MACL,GAAG,QAAQ,KAAK,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,aAAa,WAAW,CAAC,CAAC;AAAA,MAC1E,GAAG,QAAQ,KAAK,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,cAAc,WAAW,CAAC,CAAC;AAAA,IAC7E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,mBAAmB;AACzB,UAAM,IAAI,KAAK,WAAW;AAC1B,QAAI,KAAK,QAAQ;AACf,YAAM,EAAE,GAAG,EAAE,IAAI,KAAK,YAAY,KAAK,OAAO,GAAG,KAAK,OAAO,CAAC;AAC9D,YAAM,QAAQ,IAAI,WAAW,IAAI,OAAO,cAAc;AACtD,YAAM,SAAS,IAAI,WAAW,IAAI,OAAO,aAAa;AACtD,QAAE,OAAO,SAAS,GAAG,CAAC,OAAO;AAC7B,QAAE,QAAQ,SAAS,SAAS,GAAG,KAAK,IAAI,GAAG,OAAO,aAAa,IAAI,QAAQ,CAAC;AAC5E,QAAE,MAAM,QAAQ,GAAG,CAAC,OAAO;AAC3B,QAAE,SAAS,QAAQ,SAAS,GAAG,KAAK,IAAI,GAAG,OAAO,cAAc,IAAI,QAAQ,CAAC;AAC7E,WAAK,WAAW,UAAU,OAAO,UAAU,KAAK;AAChD,WAAK,WAAW,UAAU,OAAO,WAAW,MAAM;AAClD;AAAA,IACF;AACA,UAAM,WAAW,KAAK,aAAa;AACnC,MAAE,OAAO,WAAW,SAAS;AAC7B,MAAE,QAAQ,WAAW,SAAS;AAC9B,MAAE,MAAM;AACR,MAAE,SAAS;AACX,SAAK,WAAW,UAAU,OAAO,QAAQ;AACzC,SAAK,WAAW,UAAU,OAAO,WAAW,QAAQ;AAAA,EACtD;AAAA,EAEQ,wBAAwB;AAC9B,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,kBAAkB,QAAiB;AACzC,QAAI,KAAK,mBAAmB,OAAQ;AACpC,SAAK,iBAAiB;AACtB,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,UAAM,QAAQ,KAAK,IAAI,SAAS;AAChC,UAAM,OAAO,cAAc,IAAI,gDAAgD,cAAc,iBAAiB;AAC9G,SAAK,MAAM,SACP,GAAG,WAAW,KAAK,CAAC,2BAAsB,IAAI,sBAC9C,GAAG,WAAW,KAAK,CAAC,mBAAmB;AAAA,EAC7C;AAAA;AAAA,EAGA,eAAe;AAAE,SAAK,kBAAkB,KAAK;AAAA,EAAG;AAAA;AAAA,EAGhD,eAAe;AAAE,SAAK,kBAAkB,IAAI;AAAA,EAAG;AAAA;AAAA,EAGvC,MAAM,MAAc,KAAK,KAAM;AACrC,SAAK,QAAQ,YAAY;AACzB,SAAK,QAAQ,UAAU,IAAI,MAAM;AACjC,WAAO,aAAa,KAAK,UAAU;AACnC,SAAK,aAAa,OAAO,WAAW,MAAM,KAAK,QAAQ,UAAU,OAAO,MAAM,GAAG,EAAE;AAAA,EACrF;AAAA,EAEQ,cAAc;AACpB,QAAI,CAAC,KAAK,YAAa;AACvB,SAAK,cAAc;AACnB,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGQ,gBAAgB;AACtB,SAAK,gBAAgB,CAAC,KAAK;AAC3B,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGQ,WAAW;AACjB,SAAK,WAAW,UAAU,OAAO,YAAY,KAAK,WAAW;AAC7D,UAAM,OAAO,KAAK,WAAW,cAAc,mBAAmB;AAC9D,UAAM,aAAa,iBAAiB,OAAO,KAAK,WAAW,CAAC;AAC5D,UAAM,aAAa,cAAc,KAAK,cAAc,wBAAwB,eAAe;AAC3F,UAAM,UAAU,KAAK,WAAW,cAAc,sBAAsB;AACpE,aAAS,UAAU,OAAO,MAAM,KAAK,aAAa;AAClD,aAAS,aAAa,gBAAgB,OAAO,KAAK,aAAa,CAAC;AAEhE,SAAK,QAAQ,UAAU,OAAO,aAAa,KAAK,aAAa;AAAA,EAC/D;AAAA;AAAA,EAGQ,QAAQ,MAAc,OAAe,MAAiC;AAC5E,UAAM,IAAI,GAAG,QAAQ;AACrB,MAAE,QAAQ,OAAO;AACjB,MAAE,aAAa,cAAc,KAAK;AAClC,MAAE,YAAY,qBAAqB,IAAI,8BAA8B,KAAK;AAC1E,WAAO;AAAA,EACT;AAAA,EAoHQ,cAAc,MAAc,MAAc;AAChD,UAAM,IAAI,KAAK;AACf,WAAO,OAAO,KAAK,OAAO,OAAO;AAAA,MAC/B,SAAS;AAAA,MACT,MAAM,KAAK,IAAI,EAAE,GAAG,IAAI,IAAI;AAAA,MAAM,KAAK,KAAK,IAAI,EAAE,GAAG,IAAI,IAAI;AAAA,MAC7D,OAAO,KAAK,IAAI,OAAO,EAAE,CAAC,IAAI;AAAA,MAAM,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC,IAAI;AAAA,IACrE,CAAC;AAAA,EACH;AAAA,EAEQ,aAAa;AACnB,SAAK,YAAY;AACjB,aAAS,oBAAoB,eAAe,KAAK,cAAc,IAAI;AACnE,aAAS,oBAAoB,aAAa,KAAK,YAAY,IAAI;AAC/D,aAAS,oBAAoB,iBAAiB,KAAK,gBAAgB,IAAI;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,mBAAmB,IAAiE;AAC1F,UAAM,WAAW,KAAK,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAC3D,UAAM,WAAWC,iBAAgB,UAAU,EAAE;AAC7C,QAAI;AACJ,QAAI,UAAU;AACZ,YAAM,KAAK,SAAS,sBAAsB;AAC1C,YAAM;AAAA,QACJ,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG;AAAA,QAAO,KAAK,GAAG,IAAI,GAAG,OAAO,GAAG;AAAA,QAC1D,IAAI,GAAG,IAAI,GAAG;AAAA,QAAO,IAAI,GAAG,IAAI,GAAG;AAAA,MACrC;AAAA,IACF;AACA,UAAM,SAAqB,EAAE,GAAG,GAAG,IAAI,OAAO,SAAS,GAAG,GAAG,IAAI,OAAO,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI;AACvG,WAAO,EAAE,QAAQ,SAAS,SAAS;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,6BAA6B;AACzC,UAAM,KAAiB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AACjF,UAAM,UAAU,KAAK,IAAI,iBAAiB;AAC1C,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,QAAQ,EAAE;AAAA,IACzB,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,OAAO,OAAO,cAAc,MAAM,gBAAgB,IAAI;AAC5D,UAAM,OAAO,OAAO,UAAU,GAAG,IAAI;AACrC,UAAM,OAAO,OAAO,UAAU,GAAG,IAAI;AACrC,UAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,WAAW;AAC7D,UAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,YAAY;AAC9D,UAAM,SAAS,EAAE,GAAG,MAAM,OAAO,IAAI,GAAG,GAAG,MAAM,OAAO,IAAI,EAAE;AAC9D,SAAK,QAAQ,KAAK;AAClB,SAAK;AAAA,MACH,EAAE,MAAM,QAAQ,QAAQ,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,2BAAwB;AAAA,MACpF;AAAA,MACA,OAAO,cAAc;AAAA,MACrB,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAY;AAClB,SAAK,QAAQ,KAAK;AAClB,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO;AACb,UAAM,SAAS;AACf,UAAM,MAAM,UAAU;AACtB,UAAM,WAAW,MAAM;AACrB,YAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,YAAM,OAAO;AACb,UAAI,CAAC,KAAM;AACX,YAAM,OAAO,OAAO,UAAU,OAAO,aAAa;AAClD,YAAM,OAAO,OAAO,UAAU,OAAO,cAAc;AACnD,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,WAAW;AAC7D,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,YAAY;AAC9D,YAAM,SAAS,EAAE,GAAG,MAAM,OAAO,IAAI,GAAG,GAAG,MAAM,OAAO,IAAI,EAAE;AAC9D,WAAK;AAAA,QACH,EAAE,MAAM,QAAQ,QAAQ,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,sBAAmB;AAAA,QAC/E;AAAA,QACA,OAAO,cAAc;AAAA,QACrB,CAAC,IAAI;AAAA,MACP;AAAA,IACF;AAEA,SAAK,OAAO,YAAY,KAAK;AAC7B,UAAM,MAAM;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,aAAa,IAAgB;AACzC,SAAK,OAAO,MAAM,UAAU;AAC5B,UAAM,EAAE,QAAQ,QAAQ,IAAI,KAAK,mBAAmB,EAAE;AACtD,UAAM,SAAwB,EAAE,MAAM,UAAU,QAAQ,QAAQ;AAGhE,SAAK,aAAa,QAAQ,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC;AAC3C,UAAM,UAAU,KAAK,IAAI,iBAAiB;AAC1C,SAAK,cAAc,QAAQ,EAAE;AAC7B,SAAK,KAAK,YAAY,KAAK,CAAC,SAAS;AACnC,UAAI,QAAQ,KAAK,YAAY,OAAQ,QAAO,aAAa;AAAA,IAC3D,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,gBAAgB,IAAgB;AAC5C,SAAK,OAAO,MAAM,UAAU;AAC5B,UAAM,EAAE,QAAQ,QAAQ,IAAI,KAAK,mBAAmB,EAAE;AACtD,UAAM,UAAU,KAAK,IAAI,oBAAoB;AAC7C,SAAK,WAAW;AAChB,QAAI;AACJ,QAAI;AAEF,kBAAY,MAAM,QAAQ,IAAI;AAAA,QAC5B,OAAO;AAAA,QACP,UAAU,CAAC,SAAS;AAAE,eAAK,gBAAgB;AAAA,QAAM;AAAA,MACnD,CAAC;AAAA,IACH,QAAQ;AACN,kBAAY;AAAA,IACd;AACA,SAAK,WAAW;AAChB,QAAI,CAAC,UAAW;AAChB,UAAM,SAAwB,EAAE,MAAM,UAAU,QAAQ,SAAS,UAAU;AAC3E,UAAM,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,GAAG,OAAO,aAAa,GAAG;AACvD,SAAK,aAAa,QAAQ,GAAG,GAAG,CAAC;AAAA,EACnC;AAAA,EAEQ,aAAa;AACnB,SAAK,gBAAgB;AACrB,SAAK,OAAO,YAAY;AACxB,SAAK,OAAO,UAAU,IAAI,MAAM;AAAA,EAClC;AAAA,EACQ,aAAa;AACnB,SAAK,OAAO,UAAU,OAAO,MAAM;AACnC,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGQ,KAAK,GAAW,GAA2B;AACjD,UAAM,QAAQ,KAAK,GAAG,MAAM;AAC5B,SAAK,GAAG,MAAM,UAAU;AACxB,UAAM,OAAO,SAAS,iBAAiB,GAAG,CAAC;AAC3C,SAAK,GAAG,MAAM,UAAU;AACxB,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,KAAK,OAAO,gBAAiB,KAAiB,UAAU,aAAa,EAAG,QAAO;AACnF,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ,MAAY;AAE1B,QAAI,SAAS,OAAO;AAClB,UAAI,CAAC,KAAK,KAAM,MAAK,OAAO;AAC5B,UAAI,KAAK,QAAQ,YAAY;AAAE,aAAK,MAAM;AAAY,aAAK,UAAU;AAAA,MAAG;AACxE,WAAK,gBAAgB;AAAA,IACvB;AACA,SAAK,OAAO;AACZ,SAAK,GAAG,MAAM,UAAU;AACxB,SAAK,OAAO,MAAM,UAAU;AAC5B,SAAK,WAAW;AAChB,aAAS,KAAK,MAAM,SAAS,SAAS,QAAQ,KAAK;AACnD,IAAC,KAAK,KAAK,cAAc,uBAAuB,GAAmB,UAAU,OAAO,MAAM,SAAS,SAAS;AAC5G,IAAC,KAAK,KAAK,cAAc,oBAAoB,GAAmB,UAAU,OAAO,MAAM,SAAS,MAAM;AACtG,IAAC,KAAK,KAAK,cAAc,sBAAsB,GAAmB,UAAU,OAAO,MAAM,SAAS,QAAQ;AAC1G,IAAC,KAAK,KAAK,cAAc,sBAAsB,GAAmB,UAAU,OAAO,MAAM,SAAS,QAAQ;AAG1G,SAAK,KAAK,UAAU,OAAO,cAAc,SAAS,KAAK;AAEvD,aAAS,oBAAoB,eAAe,KAAK,QAAQ,IAAI;AAC7D,aAAS,oBAAoB,eAAe,KAAK,QAAQ,IAAI;AAC7D,aAAS,oBAAoB,SAAS,KAAK,SAAS,IAAI;AACxD,aAAS,oBAAoB,SAAS,KAAK,aAAa,IAAI;AAC5D,aAAS,oBAAoB,eAAe,KAAK,cAAc,IAAI;AAEnE,QAAI,SAAS,MAAO;AACpB,aAAS,iBAAiB,WAAW,KAAK,OAAO,IAAI;AACrD,SAAK,cAAc;AACnB,QAAI,SAAS,WAAW;AACtB,eAAS,iBAAiB,eAAe,KAAK,QAAQ,IAAI;AAG1D,eAAS,iBAAiB,eAAe,KAAK,QAAQ,IAAI;AAC1D,eAAS,iBAAiB,SAAS,KAAK,SAAS,IAAI;AAAA,IACvD,WAAW,SAAS,QAAQ;AAC1B,eAAS,iBAAiB,SAAS,KAAK,aAAa,IAAI;AAAA,IAC3D,WAAW,SAAS,YAAY,cAAc,GAAG;AAI/C,WAAK,KAAK,2BAA2B;AAAA,IACvC,WAAW,SAAS,YAAY,cAAc,GAAG;AAG/C,YAAM,KAAiB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AACjF,WAAK,QAAQ,KAAK;AAClB,WAAK,KAAK,gBAAgB,EAAE;AAAA,IAC9B,WAAW,SAAS,YAAY,SAAS,UAAU;AACjD,eAAS,iBAAiB,eAAe,KAAK,cAAc,IAAI;AAAA,IAClE;AAAA,EACF;AAAA;AAAA,EAuBQ,aAAa,QAAuB,GAAW,GAAW,YAAoB,CAAC,GAAG;AACxF,SAAK,UAAU;AACf,UAAM,cAAc,OAAO,SAAS,YAAY,CAAC,CAAC,OAAO;AACzD,UAAM,IAAI,KAAK;AACf,MAAE,YAAY;AACd,UAAM,QAAQ;AAAA,MAAG;AAAA,MAAO;AAAA,MACtB,OAAO,SAAS,YAAY,SAAS,OAAO,OAAO,IAC/C,OAAO,SAAS,WACb,cACG,yBAAiB,KAAK,MAAM,OAAO,OAAO,CAAC,CAAC,OAAI,KAAK,MAAM,OAAO,OAAO,CAAC,CAAC,QAC3E,eAAY,KAAK,MAAM,OAAO,OAAO,CAAC,CAAC,OAAI,KAAK,MAAM,OAAO,OAAO,CAAC,CAAC,QAC1E,OAAO,SAAS;AAAA,IAAkC;AAC1D,UAAM,QAAQ,GAAG,SAAS,OAAO;AACjC,UAAM,OAAO;AACb,UAAM,cAAc;AAEpB,UAAM,KAAK,GAAG,UAAU;AACxB,OAAG,cAAc,cAAc,+CAC3B,OAAO,SAAS,WAAW,0CACzB,OAAO,SAAS,SAAS,6BACvB;AAIR,UAAM,QAAgB,UAAU,MAAM;AACtC,UAAM,SAAS,GAAG,OAAO,QAAQ;AACjC,UAAM,OAAO,GAAG,UAAU,QAAQ,+BAA0B;AAC5D,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO;AACb,UAAM,SAAS;AACf,UAAM,WAAW;AACjB,UAAM,MAAM,UAAU;AACtB,UAAM,QAAQ,GAAG,OAAO,OAAO;AAC/B,UAAM,MAAM,GAAG,OAAO,KAAK;AAC3B,UAAM,YAAY,MAAM;AACtB,YAAM,YAAY;AAClB,YAAM,QAAQ,CAAC,GAAG,QAAQ;AACxB,cAAM,OAAO,GAAG,QAAQ,QAAQ,GAAG,eAAe,EAAE,IAAI,MAAM,UAAU,cAAO,WAAI,IAAI,EAAE,IAAI,EAAE;AAC/F,cAAMC,KAAI,GAAG,UAAU,KAAK,MAAG;AAC/B,QAAAA,GAAE,UAAU,MAAM;AAAE,gBAAM,OAAO,KAAK,CAAC;AAAG,oBAAU;AAAA,QAAG;AACvD,aAAK,YAAYA,EAAC;AAClB,cAAM,YAAY,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;AACA,UAAM,WAAW,MAAM;AACrB,UAAI,cAAc;AAClB,iBAAW,KAAK,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,GAAG;AAC7C,YAAI,MAAM,UAAU,WAAW;AAAE,cAAI,cAAc,SAAS,SAAS;AAAW;AAAA,QAAO;AACvF,cAAM,MAAM,eAAe,EAAE,IAAI,MAAM,UAAU,kBAAkB;AACnE,YAAI,EAAE,OAAO,KAAK;AAAE,cAAI,cAAc,GAAG,EAAE,IAAI;AAAkB;AAAA,QAAU;AAC3E,cAAM,KAAK,CAAC;AAAA,MACd;AACA,YAAM,QAAQ;AACd,gBAAU;AAAA,IACZ;AACA,SAAK,UAAU,MAAM,MAAM,MAAM;AACjC,WAAO,OAAO,MAAM,OAAO,OAAO,GAAG;AACrC,QAAI,MAAM,OAAQ,WAAU;AAE5B,UAAM,MAAM,GAAG,OAAO,KAAK;AAG3B,UAAM,OAAO,GAAG,OAAO,OAAO;AAC9B,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,YAAY;AACpB,YAAQ,QAAQ;AAChB,YAAQ,aAAa,cAAc,UAAU;AAC7C,eAAW,KAAK,oBAAoB;AAClC,cAAQ,OAAO,SAAS,gBAAgB,CAAC,GAAG,GAAG,MAAM,gBAAgB,CAAC;AAAA,IACxE;AACA,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,YAAY;AACpB,YAAQ,QAAQ;AAChB,YAAQ,aAAa,cAAc,aAAa;AAChD,eAAW,KAAK,cAAc;AAC5B,cAAQ,OAAO,SAAS,mBAAmB,CAAC,GAAG,GAAG,MAAM,mBAAmB,CAAC;AAAA,IAC9E;AACA,SAAK,OAAO,SAAS,OAAO;AAE5B,QAAI,MAA+B;AACnC,QAAI,OAAO,SAAS,UAAU,CAAC,aAAa;AAC1C,YAAM,MAAM,GAAG,SAAS,KAAK;AAC7B,YAAM,SAAS,cAAc,OAAO;AAAG,UAAI,OAAO;AAGlD,UAAI,UAAU;AACd,UAAI,OAAO,KAAK,SAAS,eAAe,mBAAmB,CAAC;AAC5D,UAAI,OAAO,GAAG;AAAA,IAChB,OAAO;AACL,UAAI,MAAM,iBAAiB;AAAA,IAC7B;AACA,UAAM,OAAO,GAAG,OAAO,MAAM;AAC7B,UAAM,SAAS,GAAG,UAAU,SAAS,QAAQ;AAC7C,WAAO,UAAU,MAAM,KAAK,cAAc;AAC1C,UAAM,OAAO,GAAG,UAAU,WAAW,SAAS;AAC9C,SAAK,WAAW;AAChB,UAAM,OAAO,MAAM;AAAE,WAAK,WAAW,CAAC,MAAM,MAAM,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK;AAAA,IAAG;AAC9E,UAAM,UAAU;AAChB,OAAG,UAAU;AACb,SAAK;AACL,SAAK,UAAU,MAAM,KAAK;AAAA,MACxB;AAAA,MAAQ,MAAM,MAAM,KAAK;AAAA,MAAG,GAAG,MAAM,KAAK;AAAA,MAAG,MAAM,IAAI,UAAU;AAAA,MAAO,MAAM,MAAM;AAAA,MACpF,QAAQ;AAAA,MAA0B,QAAQ;AAAA,IAC5C;AACA,SAAK,OAAO,KAAK,YAAY,EAAE,GAAG,QAAQ,IAAI;AAC9C,QAAI,OAAO,IAAI;AACf,MAAE,OAAO,OAAO,OAAO,IAAI,QAAQ,MAAM,GAAG;AAG5C,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,OAAO,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,EAAE,GAAG,OAAO,aAAa,IAAI,CAAC;AACpE,UAAM,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,EAAE,GAAG,OAAO,cAAc,IAAI,CAAC;AACpE,WAAO,OAAO,EAAE,OAAO,EAAE,SAAS,SAAS,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,CAAC;AAG/E,QAAI,CAAC,cAAc,EAAG,IAAG,MAAM;AAAA,EACjC;AAAA,EAEQ,gBAAgB;AACtB,SAAK,SAAS,MAAM,UAAU;AAC9B,SAAK,UAAU;AACf,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAc,OACZ,QACA,OACA,MACA,UACA,OACA,WAA4B,kBAC5B,aAAyB,qBACzB;AACA,QAAI,CAAC,SAAS,CAAC,KAAM;AACrB,UAAM,UAAU,KAAK,SAAS,cAAc,UAAU;AACtD,QAAI,SAAS;AAAE,cAAQ,WAAW;AAAM,cAAQ,cAAc;AAAA,IAAW;AAEzE,QAAI,QAAgB,SAA6B;AACjD,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI,aAA6B;AAEjC,QAAI,OAAO,SAAS,WAAW;AAC7B,YAAM,UAAU,KAAK,IAAI,qBAAqB;AAC9C,mBAAa,WAAW,MAAM,QAAQ,OAAO,OAAO,IAAI;AACxD,eAAS,cAAc,OAAO,OAAO;AACrC,gBAAU,sBAAsB,OAAO,OAAO;AAC9C,eAAS,KAAK;AACd,mBAAa,OAAO;AAAA,IACtB,WAAW,OAAO,SAAS,QAAQ;AAGjC,mBAAa;AACb,eAAS,WAAW,OAAO,KAAK;AAChC,gBAAU,EAAE,MAAM,IAAI,QAAQ,CAAC,EAAE;AACjC,eAAS,OAAO;AAAA,IAClB,OAAO;AAGL,kBAAY,OAAO;AACnB,mBAAa,CAAC,aAAa,WAAY,OAAO,cAAc,MAAM,KAAK,cAAe;AACtF,eAAS,OAAO;AAChB,eAAS,EAAE,GAAG,GAAG,GAAG,EAAE;AAGtB,UAAI,OAAO,SAAS;AAClB,iBAAS,cAAc,OAAO,OAAO;AACrC,kBAAU,sBAAsB,OAAO,OAAO;AAC9C,qBAAa,OAAO;AAAA,MACtB,OAAO;AACL,iBAAS,aAAa,MAAM;AAC5B,kBAAU,EAAE,MAAM,WAAW,MAAM,GAAG,QAAQ,CAAC,EAAE;AAAA,MACnD;AAAA,IACF;AAEA,UAAM,UAAmB;AAAA,MACvB,IAAIL,KAAI;AAAA,MACR,YAAY,KAAK,IAAI;AAAA,MACrB,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK,IAAI;AAAA,MACjB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,MAAM,OAAO;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,MAAM,KAAK,kBAAkB,KAAK;AAAA;AAAA;AAAA,MAG/C,UAAU;AAAA,QACR,GAAG,OAAO;AAAA,QACV,GAAG,OAAO;AAAA,QACV,GAAG;AAAA,QACH,OAAO,cAAc;AAAA,QACrB,QAAQ,cAAc;AAAA,QACtB,KAAK,eAAe;AAAA,MACtB;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,UAAM,KAAK,MAAM,KAAK,OAAO;AAC7B,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,SAAS,IAAI,QAAQ,IAAI,UAAU;AACxC,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,MAAM,QAAQ,EAAE;AAErB,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,iBAAY,QAAQ,SAAS,QAAQ,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK,SAAS;AAAA,MAC5E,QAAQ,CAAC,kBAAkB,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,WAAW,UAAU,QAAQ,GAAG,CAAC,EAAE,KAAK,QAAK;AAAA,IAC7G,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAc,kBAAkB,OAAkD;AAChF,QAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,UAAM,MAAoB,CAAC;AAC3B,eAAW,KAAK,OAAO;AACrB,UAAI;AACF,YAAI,KAAK,MAAM,KAAK,MAAM,OAAO,KAAK,IAAI,YAAY,CAAC,CAAC;AAAA,MAC1D,SAAS,GAAG;AACV,gBAAQ,KAAK,oCAAoC,EAAE,MAAM,CAAC;AAAA,MAC5D;AAAA,IACF;AACA,WAAO,IAAI,SAAS,MAAM;AAAA,EAC5B;AAAA;AAAA,EAIQ,aAAa;AAEnB,eAAW,CAAC,IAAI,GAAG,KAAK,KAAK,MAAM;AACjC,UAAI,CAAC,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG;AAAE,YAAI,OAAO;AAAG,aAAK,KAAK,OAAO,EAAE;AAAA,MAAG;AAAA,IACrF;AACA,SAAK,SAAS,QAAQ,CAAC,GAAG,MAAM;AAE9B,UAAI,EAAE,OAAQ;AACd,UAAI,MAAM,KAAK,KAAK,IAAI,EAAE,EAAE;AAC5B,UAAI,CAAC,KAAK;AACR,cAAM,GAAG,UAAU,KAAK;AACxB,YAAI,UAAU,MAAM;AAAE,eAAK,SAAS;AAAG,eAAK,MAAM,EAAE,EAAE;AAAA,QAAG;AACzD,aAAK,QAAQ,YAAY,GAAG;AAC5B,aAAK,KAAK,IAAI,EAAE,IAAI,GAAG;AAAA,MACzB;AACA,UAAI,cAAc,OAAO,IAAI,CAAC;AAC9B,UAAI,UAAU,OAAO,QAAQ,WAAW,CAAC,CAAC;AAC1C,UAAI,UAAU,OAAO,QAAQ,EAAE,SAAS,MAAM;AAAA,IAChD,CAAC;AACD,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,YAAY,QAAQ,KAAK,SAAS,QAAQ;AAChD,SAAK,QAAQ,cAAc,OAAO,KAAK;AACvC,UAAM,IAAI,KAAK,SAAS;AACxB,SAAK,SAAS,cAAc,IAAI,OAAO,CAAC,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiFQ,WAAW,GAAY,KAA4E;AACzG,UAAM,MAAM,EAAE,QAAQ;AACtB,QAAI,OAAO,UAAU,GAAG,GAAG;AACzB,YAAM,IAAI,IAAI,sBAAsB;AACpC,aAAO,EAAE,GAAG,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,GAAG,EAAE,MAAM,IAAI,KAAK,EAAE,QAAQ,GAAG,IAAI,KAAK,EAAE,OAAO,GAAG,IAAI,KAAK,EAAE,OAAO;AAAA,IACjH;AACA,QAAI,EAAE,QAAQ;AACZ,aAAO,EAAE,GAAG,EAAE,OAAO,IAAI,OAAO,SAAS,GAAG,EAAE,OAAO,IAAI,OAAO,SAAS,GAAG,EAAE,OAAO,GAAG,GAAG,EAAE,OAAO,EAAE;AAAA,IACxG;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU;AAChB,UAAM,aAAa,MAAM;AACvB,2BAAqB,KAAK,GAAG;AAC7B,WAAK,MAAM,sBAAsB,KAAK,QAAQ;AAAA,IAChD;AACA,WAAO,iBAAiB,UAAU,YAAY,IAAI;AAClD,WAAO,iBAAiB,UAAU,UAAU;AAC5C,WAAO,iBAAiB,UAAU,KAAK,WAAW;AAClD,QAAI,WAAW;AACf,SAAK,KAAK,IAAI,iBAAiB,MAAM;AACnC,mBAAa,QAAQ;AACrB,iBAAW,OAAO,WAAW,MAAM;AAAE,aAAK,SAAS;AAAG,aAAK,WAAW;AAAA,MAAG,GAAG,GAAG;AAAA,IACjF,CAAC;AACD,SAAK,GAAG,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,MAAM,YAAY,MAAM,eAAe,KAAK,CAAC;AAExG,SAAK,OAAO,OAAO,YAAY,KAAK,UAAU,GAAG;AAAA,EACnD;AAAA;AAAA,EAIQ,WAAW;AACjB,SAAK,OAAO;AACZ,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,YAAY;AAClB,SAAK,OAAO;AACZ,SAAK,QAAQ,KAAK;AAClB,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,QAAQ,MAAgB;AAC9B,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGQ,OAAO,KAAU;AACvB,QAAI,KAAK,QAAQ,IAAK;AACtB,QAAI,QAAQ,UAAU,CAAC,KAAK,OAAQ;AAEpC,QAAI,QAAQ,WAAY,MAAK,QAAQ,KAAK;AAC1C,SAAK,MAAM;AACX,SAAK,UAAU;AACf,SAAK,UAAU;AACf,QAAI,QAAQ,QAAQ;AAClB,WAAK,WAAW;AAChB,UAAI,KAAK,UAAU,SAAS,CAAC,KAAK,YAAY,OAAQ,MAAK,KAAK,gBAAgB;AAAA,IAClF;AACA,QAAI,QAAQ,WAAY,MAAK,WAAW;AACxC,QAAI,QAAQ,YAAY;AACtB,WAAK,eAAe;AACpB,WAAK,KAAK,aAAa;AAAA,IACzB;AACA,SAAK,iBAAiB;AACtB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,cAAc;AACpB,SAAK,QAAQ,KAAK,UAAU,SAAS,UAAU;AAC/C,SAAK,UAAU;AACf,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAMQ,WAAW,MAAmB;AACpC,UAAM,UAAU,KAAK,UAAU,SAAS,MAAM;AAC9C,SAAK,WAAW;AAChB,QAAI,CAAC,QAAS,MAAK,UAAU,IAAI,MAAM;AAAA,EACzC;AAAA,EAEQ,aAAa;AACnB,SAAK,SAAS,UAAU,OAAO,MAAM;AACrC,SAAK,cAAc,UAAU,OAAO,MAAM;AAAA,EAC5C;AAAA,EAEQ,UAAU,IAAY;AAC5B,QAAI,CAAC,WAAW,SAAS,EAAE,EAAG;AAC9B,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,aAAa,GAAY;AAC/B,SAAK,YAAY;AACjB,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGQ,cAAc,KAAsE;AAC1F,QAAI,QAAQ,kBAAkB;AAAE,WAAK,kBAAkB,CAAC,KAAK,cAAc;AAAG;AAAA,IAAQ;AACtF,QAAI,QAAQ,gBAAiB,MAAK,gBAAgB,CAAC,KAAK;AAAA,aAC/C,QAAQ,aAAc,MAAK,aAAa,CAAC,KAAK;AAAA,QAClD,MAAK,YAAY,CAAC,KAAK;AAC5B,SAAK,UAAU;AACf,QAAI,QAAQ,gBAAiB,MAAK,WAAW;AAC7C,QAAI,QAAQ,aAAa;AAAE,WAAK,WAAW;AAAG,WAAK,WAAW;AAAA,IAAG;AACjE,QAAI,QAAQ,aAAc,MAAK,UAAU;AACzC,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGQ,iBAAiB;AACvB,QAAI,CAAC,KAAK,aAAc;AACxB,UAAM,KAA8B;AAAA,MAClC,YAAY,KAAK;AAAA,MACjB,eAAe,CAAC,KAAK;AAAA,MACrB,WAAW,KAAK;AAAA,MAChB,gBAAgB,CAAC,KAAK;AAAA,IACxB;AACA,SAAK,aAAa,iBAA8B,YAAY,EAAE,QAAQ,CAAC,MAAM;AAC3E,YAAM,MAAM,EAAE,QAAQ;AACtB,UAAI,OAAO,GAAI,GAAE,aAAa,gBAAgB,OAAO,GAAG,GAAG,CAAC,CAAC;AAE7D,UAAI,QAAQ,WAAY,GAAE,SAAS,CAAC,KAAK;AAAA,IAC3C,CAAC;AACD,SAAK,aAAa,iBAA8B,eAAe,EAAE,QAAQ,CAAC,MACxE,EAAE,UAAU,OAAO,MAAM,EAAE,QAAQ,WAAW,KAAK,MAAM,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAc;AACpB,QAAI,CAAC,KAAK,OAAQ;AAClB,QAAI,KAAK,YAAY,KAAK,IAAK;AAC/B,SAAK,UAAU,KAAK;AACpB,UAAM,QAA4C;AAAA,MAChD,MAAM,KAAK,OAAO,cAAc,cAAc;AAAA,MAC9C,UAAU,KAAK,gBAAgB;AAAA,MAC/B,UAAU,KAAK,gBAAgB;AAAA,IACjC;AACA,eAAW,CAAC,IAAIM,KAAI,KAAK,KAAK,gBAAiB,OAAM,EAAE,IAAIA;AAC3D,UAAM,OAAO,MAAM,KAAK,GAAG;AAC3B,QAAI,CAAC,KAAM;AACX,SAAK,YAAY;AACjB,UAAM,OAAO,KAAK,WAAW,KAAK,GAAG;AACrC,QAAI,CAAC,QAAQ,CAAC,KAAK,cAAc,KAAK,aAAa,KAAK,UAAU,IAAI,KAAK,GAAG,EAAG;AAGjF,SAAK,UAAU,IAAI,KAAK,GAAG;AAC3B,SAAK,UAAU;AACf,SAAK,YACH,yCAAyC,WAAW,KAAK,KAAK,CAAC,6BACxC,WAAW,KAAK,IAAI,CAAC;AAG9C,IAAC,KAAK,cAAc,wBAAwB,EAAkB,UAAU,MAAM;AAC5E,WAAK,aAAa;AAGlB,WAAK,UAAU;AACf,WAAK,UAAU;AACf,WAAK,gBAAgB;AAAA,IACvB;AACA,IAAC,KAAK,cAAc,SAAS,EAAkB,UAAU,MAAM;AAAE,WAAK,YAAY;AAAA,IAAI;AAAA,EACxF;AAAA;AAAA,EAMQ,WAAW,IAAyD;AAC1E,QAAI,MAAM,MAAO,QAAO,MAAM,EAAgB;AAC9C,YAAQ,KAAK,IAAI,QAAQ,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG;AAAA,EACzD;AAAA;AAAA,EAIQ,YAAY;AAClB,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,gBAAgB;AACrB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,WAAW;AACjB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,OAAO,UAAU,OAAO,MAAM;AACnC,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,SAAS,MAAc;AAC7B,QAAI,OAAO,GAAG;AAAE,WAAK,SAAS;AAAG;AAAA,IAAQ;AACzC,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGQ,aAAa;AACnB,QAAI,KAAK,WAAW,KAAK,KAAK,YAAY,KAAK,QAAQ;AACrD,WAAK,OAAO,UAAU,OAAO,MAAM;AACnC;AAAA,IACF;AACA,UAAM,OAAO,KAAK,KAAK,QAAQ;AAC/B,QAAI,KAAK,QAAQ,KAAK,IAAK,MAAK,OAAO,KAAK,GAAG;AAC/C,SAAK,OAAO,UAAU,IAAI,MAAM;AAEhC,UAAM,MAAM;AACZ,UAAM,SAAS,KAAK,OAAO,cAAc,KAAK,GAAG;AACjD,UAAM,MAAM,QAAQ,sBAAsB;AAC1C,UAAM,IAAI,OAAO,IAAI,QACjB,EAAE,MAAM,IAAI,OAAO,KAAK,KAAK,IAAI,MAAM,KAAK,OAAO,IAAI,QAAQ,MAAM,GAAG,QAAQ,IAAI,SAAS,MAAM,EAAE,IAErG,EAAE,MAAM,OAAO,aAAa,GAAG,KAAK,OAAO,cAAc,GAAG,OAAO,GAAG,QAAQ,EAAE;AACpF,SAAK,SAAS,MAAM,OAAO,GAAG,EAAE,IAAI;AACpC,SAAK,SAAS,MAAM,MAAM,GAAG,EAAE,GAAG;AAClC,SAAK,SAAS,MAAM,QAAQ,GAAG,EAAE,KAAK;AACtC,SAAK,SAAS,MAAM,SAAS,GAAG,EAAE,MAAM;AAExC,UAAM,OAAO,KAAK,aAAa,KAAK,SAAS;AAC7C,SAAK,SAAS,YACZ,2BAA2B,WAAW,KAAK,KAAK,CAAC,gCACvB,WAAW,KAAK,IAAI,CAAC,wDAEpB,KAAK,IAAI,CAAC,GAAG,MAAM,aAAa,MAAM,KAAK,WAAW,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,aAC3G,KAAK,WAAW,IAAI,yCAAyC,MAC9D,8DAC0B,OAAO,SAAS,MAAM;AAMlD,UAAMC,KAAI;AACV,UAAM,IAAI,KAAK,SAAS,gBAAgB;AACxC,UAAM,iBAAiB,CAAC,GAAW,MACjC,IAAI,EAAE,OAAO,EAAE,QAAQ,KAAK,IAAIA,KAAI,EAAE,OAAO,KAAK,IAAI,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,IAAI,EAAE,MAAM;AAChG,UAAM,aAAiC;AAAA,MACrC,CAAC,EAAE,OAAO,EAAE,QAAQ,IAAIA,KAAI,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE;AAAA;AAAA,MACpD,CAAC,EAAE,OAAO,EAAE,QAAQ,IAAIA,KAAI,GAAG,EAAE,MAAM,IAAI,EAAE;AAAA;AAAA,MAC7C,CAAC,EAAE,OAAOA,KAAI,IAAI,EAAE,MAAM,EAAE,SAAS,IAAI,IAAI,CAAC;AAAA;AAAA,MAC9C,CAAC,EAAE,OAAO,EAAE,QAAQ,IAAI,EAAE,MAAM,EAAE,SAAS,IAAI,IAAI,CAAC;AAAA;AAAA,IACtD;AACA,QAAI,KAAK,QAAQ,WAAW,CAAC,EAAG,CAAC,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,aAAaA,KAAI,CAAC,CAAC;AAC7E,QAAI,KAAK,QAAQ,WAAW,CAAC,EAAG,CAAC,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,cAAc,IAAI,CAAC,CAAC;AAC9E,eAAW,CAAC,GAAG,CAAC,KAAK,YAAY;AAC/B,YAAM,KAAK,QAAQ,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,aAAaA,KAAI,CAAC,CAAC;AAC/D,YAAM,KAAK,QAAQ,GAAG,GAAG,KAAK,IAAI,GAAG,OAAO,cAAc,IAAI,CAAC,CAAC;AAChE,WAAK;AAAI,WAAK;AACd,UAAI,CAAC,eAAe,IAAI,EAAE,EAAG;AAAA,IAC/B;AACA,SAAK,SAAS,MAAM,OAAO,GAAG,EAAE;AAChC,SAAK,SAAS,MAAM,MAAM,GAAG,EAAE;AAE/B,IAAC,KAAK,SAAS,cAAc,SAAS,GAA0B,iBAAiB,SAAS,MAAM,KAAK,SAAS,KAAK,WAAW,CAAC,CAAC;AAChI,IAAC,KAAK,SAAS,cAAc,SAAS,EAAmB,iBAAiB,SAAS,MAAM,KAAK,SAAS,CAAC;AACxG,IAAC,KAAK,SAAS,cAAc,SAAS,EAAmB,iBAAiB,SAAS,MAAM;AACvF,UAAI,KAAM,MAAK,SAAS;AAAA,UAAQ,MAAK,SAAS,KAAK,WAAW,CAAC;AAAA,IACjE,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,WAAW;AAAE,WAAO,OAAO,cAAc;AAAA,EAAK;AAAA,EAE9C,YAAY;AAClB,QAAI;AACF,YAAM,IAAI,aAAa,QAAQ,YAAY;AAC3C,UAAI,CAAC,EAAG;AACR,YAAM,IAAI,KAAK,MAAM,CAAC;AACtB,UAAI,WAAW,SAAS,GAAG,IAAI,EAAG,MAAK,WAAW,EAAE;AACpD,UAAI,OAAO,GAAG,SAAS,UAAW,MAAK,OAAO,EAAE;AAChD,UAAI,GAAG,UAAU,WAAW,GAAG,UAAU,OAAQ,MAAK,QAAQ,EAAE;AAChE,YAAM,QAAQ,CAAC,GAAG,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,OAAO,OAAO,UAAU,KAAK,MAAM,GAAG,IAAI,KAAK,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACvI,UAAI,OAAO,GAAG,QAAQ,YAAY,MAAM,SAAS,EAAE,GAAG,EAAG,MAAK,MAAM,EAAE;AACtE,UAAI,GAAG,UAAU,UAAU,GAAG,UAAU,MAAO,MAAK,QAAQ,EAAE;AAC9D,UAAI,OAAO,GAAG,eAAe,SAAU,MAAK,aAAa,EAAE;AAC3D,UAAI,OAAO,GAAG,iBAAiB,YAAY,EAAE,gBAAgB,aAAc,MAAK,eAAe,EAAE;AACjG,UAAI,CAAC,UAAU,UAAU,MAAM,EAAE,SAAS,GAAG,SAAS,EAAG,MAAK,YAAY,EAAE;AAC5E,UAAI,GAAG,SAAS,OAAO,EAAE,MAAM,MAAM,SAAU,MAAK,YAAY,EAAE,GAAG,KAAK,WAAW,GAAG,EAAE,MAAM;AAChG,UAAI,OAAO,GAAG,kBAAkB,UAAW,MAAK,gBAAgB,EAAE;AAClE,UAAI,OAAO,GAAG,mBAAmB,UAAW,MAAK,iBAAiB,EAAE;AACpE,UAAI,GAAG,OAAO,OAAO,EAAE,IAAI,MAAM,YAAY,OAAO,EAAE,IAAI,MAAM,SAAU,MAAK,SAAS,EAAE,GAAG,EAAE,IAAI,GAAG,GAAG,EAAE,IAAI,EAAE;AACjH,UAAI,GAAG,UAAU,WAAW,SAAS,EAAE,MAAM,EAAG,MAAK,SAAS,EAAE;AAChE,UAAI,OAAO,GAAG,cAAc,UAAW,MAAK,YAAY,EAAE;AAC1D,UAAI,OAAO,GAAG,eAAe,UAAW,MAAK,aAAa,EAAE;AAC5D,UAAI,OAAO,GAAG,cAAc,UAAW,MAAK,YAAY,EAAE;AAC1D,UAAI,OAAO,GAAG,aAAa,UAAW,MAAK,WAAW,EAAE;AACxD,UAAI,MAAM,QAAQ,GAAG,SAAS,EAAG,MAAK,YAAY,IAAI,IAAI,EAAE,UAAU,OAAO,CAAC,MAAe,OAAO,MAAM,QAAQ,CAAC;AAAA,IACrH,QAAQ;AAAA,IAAuC;AAAA,EACjD;AAAA,EAEQ,YAAY;AAClB,QAAI;AACF,mBAAa,QAAQ,cAAc,KAAK,UAAU;AAAA,QAChD,MAAM,KAAK;AAAA,QAAU,MAAM,KAAK;AAAA,QAAM,OAAO,KAAK;AAAA,QAAO,KAAK,KAAK;AAAA,QAAK,OAAO,KAAK;AAAA,QACpF,eAAe,KAAK;AAAA,QAAe,gBAAgB,KAAK;AAAA,QAAgB,KAAK,KAAK;AAAA,QAClF,OAAO,KAAK;AAAA,QAAO,YAAY,KAAK;AAAA,QAAY,cAAc,KAAK;AAAA,QAAc,WAAW,KAAK;AAAA,QACjG,QAAQ,KAAK;AAAA,QAAQ,WAAW,KAAK;AAAA,QAAW,YAAY,KAAK;AAAA,QACjE,WAAW,KAAK;AAAA,QAAW,UAAU,KAAK;AAAA,QAAU,WAAW,CAAC,GAAG,KAAK,SAAS;AAAA,MACnF,CAAC,CAAC;AAAA,IACJ,QAAQ;AAAA,IAAe;AAAA,EACzB;AAAA;AAAA,EAGQ,kBAAkB;AACxB,SAAK,KAAK,UAAU,OAAO,eAAe,KAAK,UAAU,OAAO;AAChE,SAAK,SAAS,QAAQ,KAAK,UAAU,SAAS,0BAA0B;AACxE,SAAK,SAAS,YAAY,KAAK,UAAU,SAAS,QAAQ;AAI1D,UAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,KAAK,QAAQ,CAAC;AACrE,SAAK,KAAK,MAAM,YAAY,YAAY,KAAK,UAAU,UAAU,OAAO,QAAQ,OAAO,IAAI;AAC3F,SAAK,KAAK,MAAM,YAAY,iBAAiB,OAAO,IAAI;AAExD,UAAM,IAAI,KAAK;AACf,MAAE,UAAU,OAAO,QAAQ,KAAK,IAAI;AACpC,eAAW,KAAK,WAAY,GAAE,UAAU,OAAO,UAAU,GAAG,KAAK,aAAa,CAAC;AAC/E,MAAE,UAAU,OAAO,aAAa,KAAK,SAAS;AAE9C,UAAM,YAAY,KAAK,SAAS,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AAC9D,SAAK,OAAO,YACV,0DAC0B,SAAS,aAAa,KAAK,UAAU,QAAQ,oBAAoB,cAAc;AAE3G,eAAW,KAAK,KAAK,QAAS,GAAE,UAAU,OAAO,OAAO,EAAE,EAAE,IAAI,KAAK,QAAQ,EAAE,EAAE;AACjF,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,QAAS,MAAK,UAAU,OAAO,MAAM,OAAO,KAAK,GAAG;AAClF,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,MAAE,iBAA8B,YAAY,EAAE,QAAQ,CAAC,MACrD,EAAE,UAAU,OAAO,MAAM,EAAE,QAAQ,QAAQ,KAAK,GAAG,CAAC;AACtD,SAAK,QAAQ,iBAA8B,YAAY,EAAE,QAAQ,CAAC,MAChE,EAAE,UAAU,OAAO,MAAM,EAAE,QAAQ,QAAQ,KAAK,QAAQ,CAAC;AAC3D,SAAK,eAAe;AACpB,SAAK,YAAY;AAEjB,QAAI,KAAK,aAAa,SAAS;AAC7B,YAAM,KAAK,OAAO,YAAY,KAAK,OAAO;AAC1C,UAAI,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,KAAK;AAC1B,UAAI,QAAQ,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC;AAC1C,UAAI,QAAQ,GAAG,KAAK,KAAK,EAAE;AAC3B,UAAI,KAAK,KAAK,KAAK,GAAG;AAAE,YAAI,KAAK,IAAI,IAAI,KAAK,IAAI,EAAE;AAAG,YAAI;AAAA,MAAI;AAC/D,UAAI,QAAQ,GAAG,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC;AACzC,UAAI,QAAQ,GAAG,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC;AACzC,WAAK,YAAY,EAAE,GAAG,GAAG,GAAG,EAAE;AAC9B,aAAO,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,MAAM,KAAK,IAAI,MAAM,OAAO,IAAI,MAAM,QAAQ,IAAI,MAAM,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAAA,IAC5H,OAAO;AACL,iBAAW,KAAK,CAAC,QAAQ,OAAO,SAAS,UAAU,SAAS,QAAQ,EAAY,GAAE,MAAM,CAAC,IAAI;AAAA,IAC/F;AAEA,MAAE,iBAA8B,mBAAmB,EAAE,QAAQ,CAAC,MAC5D,EAAE,UAAU,OAAO,MAAM,EAAE,QAAQ,SAAS,KAAK,QAAQ,CAAC;AAI5D,SAAK,WAAW,UAAU,OAAO,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,cAAc;AAG3E,SAAK,UAAU,UAAU,OAAO,QAAQ,CAAC,KAAK,QAAQ,KAAK,kBAAkB,cAAc,CAAC;AAC5F,SAAK,iBAAiB;AACtB,SAAK,SAAS;AAEd,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,WAAW;AACjB,UAAM,KAAK,SAAS;AACpB,OAAG,MAAM,aAAa,GAAG,MAAM,cAAc,GAAG,MAAM,eAAe;AAGrE,QAAI,CAAC,KAAK,QAAQ,KAAK,aAAa,WAAW,KAAK,SAAS,EAAG;AAChE,UAAM,IAAI,KAAK,KAAK,sBAAsB;AAC1C,QAAI,KAAK,aAAa,OAAQ,IAAG,MAAM,aAAa,EAAE,QAAQ;AAAA,aACrD,KAAK,aAAa,QAAS,IAAG,MAAM,cAAc,EAAE,QAAQ;AAAA,aAC5D,KAAK,aAAa,SAAU,IAAG,MAAM,eAAe,EAAE,SAAS;AAAA,EAC1E;AAAA;AAAA,EAoDQ,aAAa;AACnB,SAAK,OAAO,YAAY;AACxB,UAAM,IAAI,KAAK,OAAO,KAAK,EAAE,YAAY;AACzC,UAAM,UAAU,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK;AAEhD,QAAI,QAAQ,KAAK,gBAAgB,OAAO,CAAC,MAAM;AAC7C,YAAM,QAAQ,gBAAgB,EAAE,MAAM;AACtC,UAAI,KAAK,eAAe,UAAU,UAAU,WAAY,QAAO;AAC/D,UAAI,KAAK,eAAe,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAO,QAAO;AACrF,UAAI,KAAK,eAAe,cAAc,UAAU,WAAY,QAAO;AACnE,UAAI,KAAK,eAAe,YAAY,UAAU,cAAc,EAAE,KAAK,MAAM,EAAE,SAAS,IAAI,UAAW,QAAO;AAC1G,UAAI,KAAK,gBAAgB,UAAU,KAAK,aAAc,QAAO;AAC7D,aAAO,CAAC,KAAK,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,QAAQ,QAAQ,EAAE,GAAG,YAAY,EAAE,SAAS,CAAC;AAAA,IAC5F,CAAC;AAID,UAAM,QAAQ,KAAK,cAAc,KAAK,UAAU,QAAQ,WAAW;AACnE,QAAI,KAAK,QAAS,MAAK,QAAQ,QAAQ;AACvC,QAAI,KAAK,UAAW,MAAK,UAAU,QAAQ,KAAK;AAChD,QAAI,UAAU,SAAU,SAAQ,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAChG,QAAI,UAAU,SAAU,SAAQ,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAEhG,UAAM,UAAU,UAAU;AAC1B,UAAM,SAAS,oBAAI,IAAoB;AACvC,QAAI,QAAS,YAAW,KAAK,MAAO,QAAO,IAAI,SAAS,EAAE,SAAS,IAAI,OAAO,IAAI,SAAS,EAAE,SAAS,CAAC,KAAK,KAAK,CAAC;AAElH,SAAK,gBAAgB;AAErB,QAAI,CAAC,MAAM,QAAQ;AACjB,WAAK,OAAO,YAAY;AAAA,QAAG;AAAA,QAAO;AAAA,QAChC,KAAK,aACD,4BACA,KAAK,eACH,cAAc,aAAa,KAAK,YAAyC,CAAC,MAC5E,IACE,mCACA,KAAK,UAAU,QACb,qCACA;AAAA,MAAkG,CAAC;AAAA,IAC/G;AAEA,QAAI,UAAU;AACd,UAAM,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAI,SAAS;AACX,cAAM,MAAM,SAAS,EAAE,SAAS;AAChC,cAAM,OAAO,KAAK,cAAc,IAAI,GAAG;AACvC,YAAI,QAAQ,SAAS;AAEnB,gBAAM,OAAO,GAAG,UAAU,cAAc,OAAO,UAAU,KAAK,GAAG;AACjE,eAAK,QAAQ,IAAI,OAAO,OAAO,IAAI,GAAG,KAAK,CAAC;AAC5C,eAAK,aAAa,iBAAiB,OAAO,CAAC,IAAI,CAAC;AAChD,eAAK,UAAU,MAAM;AACnB,gBAAI,KAAM,MAAK,cAAc,OAAO,GAAG;AAAA,gBAClC,MAAK,cAAc,IAAI,GAAG;AAC/B,iBAAK,WAAW;AAAA,UAClB;AACA,eAAK,OAAO,YAAY,IAAI;AAC5B,oBAAU;AAAA,QACZ;AACA,YAAI,KAAM;AAAA,MACZ;AACA,WAAK,OAAO,YAAY,KAAK,SAAS,GAAG,CAAC,CAAC;AAAA,IAC7C,CAAC;AACD,SAAK,YAAY,MAAM,MAAM;AAAA,EAC/B;AAAA,EAEQ,SAAS,GAAY,GAAwB;AACnD,UAAM,WAAW,KAAK,KAAK,IAAI,EAAE,EAAE,GAAG,UAAU,SAAS,UAAU,KAAK,CAAC,WAAW,CAAC;AACrF,UAAM,OAAO,KAAK,SAAS,IAAI,EAAE,EAAE;AACnC,UAAM,OAAO,GAAG,OAAO,UAAU,OAAO,KAAK,aAAa;AAC1D,UAAM,MAAM,GAAG,OAAO,KAAK;AAC3B,UAAM,MAAM,GAAG,QAAQ,SAAS,WAAW,CAAC,IAAI,UAAU,WAAW,cAAc,KAAK,OAAO,IAAI,CAAC,CAAC;AACrG,QAAI,OAAO,GAAG;AACd,QAAI,EAAE,UAAW,KAAI,YAAY,GAAG,QAAQ,UAAU,kBAAa,CAAC;AACpE,UAAM,KAAK,EAAE,UAAU;AACvB,QAAI,IAAI;AACN,YAAM,OAAO,KAAK,MAAM,WAAW,KAAK,OAAO,WAAW;AAC1D,YAAM,OAAO,KAAK,MAAM,cAAO,KAAK,OAAO,WAAM;AACjD,UAAI,YAAY,GAAG,QAAQ,UAAU,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IACzD;AACA,QAAI,EAAE,QAAQ;AACZ,YAAM,OAAO,GAAG,QAAQ,WAAW,QAAQ,EAAE,OAAO,eAAe,EAAE,OAAO,SAAS,EAAE;AACvF,WAAK,QAAQ,EAAE,OAAO,WAClB,WAAW,EAAE,OAAO,SAAS,QAAQ,EAAE,OAAO,SAAS,KAAK,KAC5D;AACJ,UAAI,YAAY,IAAI;AAAA,IACtB;AACA,UAAM,MAAM,EAAE;AACd,QAAI,OAAO,IAAI,WAAW,QAAQ;AAChC,YAAM,QAAQ,IAAI,oBAAoB,IAAI,WAAW,OAAO,YAAY;AACxE,YAAM,KAAK,IAAI,WAAW;AAC1B,YAAM,SAAS,KAAK,IAAI,SAAS;AACjC,UAAI,QAAQ;AAEV,cAAM,OAAO,OAAO,SAAS,aAAa,gBAAgB,OAAO,MAAM,CAAC;AACxE,cAAM,OAAO,CAAC,UAAK,KAAK,IAAI,OAAO,WAAW,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAC9E,cAAM,OAAO,OAAO,OAAO,gBAAgB,KAAK,OAAO,GAAG,IAAI,OAAO,MAAM;AAC3E,cAAM,OAAO,GAAG,OAAO,MAAM,QAAQ,cAAc,gBAAgB,OAAO,MAAM,CAAC,IAAI,IAAI;AACzF,aAAK,QAAQ,GAAG,KAAK,KAAK,IAAI,GAAG,OAAO,KAAK,mBAAc,OAAO,OAAO,EAAE,CAAC,KAAK,EAAE;AACnF,YAAI,MAAM;AACR,UAAC,KAA2B,OAAO;AACnC,eAAK,aAAa,UAAU,QAAQ;AACpC,eAAK,aAAa,OAAO,YAAY;AACrC,eAAK,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAAA,QAC3D;AACA,YAAI,YAAY,IAAI;AAAA,MACtB,OAAO;AACL,cAAM,OAAO,GAAG,QAAQ,KAAK,YAAY,eAAe,KAAK,UAAK,KAAK,KAAK,UAAK,KAAK,SAAS;AAC/F,aAAK,QAAQ,KAAK,WAAW,KAAK,KAAK,qBAAqB,KAAK,GAAG,IAAI,QAAQ,KAAK,IAAI,KAAK,KAAK,EAAE;AACrG,YAAI,YAAY,IAAI;AAAA,MACtB;AAAA,IACF;AACA,QAAI,WAAW,CAAC,EAAG,KAAI,YAAY,GAAG,QAAQ,cAAc,UAAU,CAAC;AAAA,aAC9D,UAAU;AAGjB,YAAM,IAAI,GAAG,QAAQ,kBAAkB,OAAO;AAC9C,QAAE,QAAQ;AACV,UAAI,YAAY,CAAC;AAAA,IACnB;AAIA,UAAM,KAAK,UAAU,CAAC;AACtB,QAAI,IAAI;AAIN,UAAI,GAAG,UAAU,WAAY,KAAI,YAAY,GAAG,QAAQ,eAAe,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAC5F,UAAI,GAAG,IAAI;AACT,cAAM,KAAK,GAAG,GAAG,GAAG,MAAM,MAAM,QAAQ,SAAS,GAAG,GAAG,QAAQ,OAAO,GAAG,GAAG,KAAK,KAAK,EAAE,IAAI,IAAI,GAAG,GAAG,MAAM,EAAE;AAC9G,WAAG,QAAQ,iBAAiB,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,QAAQ,WAAM,GAAG,GAAG,KAAK,KAAK,EAAE;AACjF,YAAI,GAAG,GAAG,KAAK;AACb,UAAC,GAAyB,OAAO,GAAG,GAAG;AACvC,aAAG,aAAa,UAAU,QAAQ;AAClC,aAAG,aAAa,OAAO,YAAY;AACnC,aAAG,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAAA,QACzD;AACA,YAAI,YAAY,EAAE;AAAA,MACpB;AACA,UAAI,GAAG,QAAQ;AACb,cAAM,QAAQ,GAAG,QAAQ,QAAQ;AACjC,cAAM,QAAQ,iBAAY,GAAG,OAAO,IAAI;AACxC,cAAM,YACJ,0BAA0B,WAAW,GAAG,OAAO,IAAI,CAAC,mDACR,KAAK,MAAM,GAAG,OAAO,QAAQ,GAAG,CAAC;AAC/E,YAAI,YAAY,KAAK;AAAA,MACvB;AAGA,UAAI,GAAG,IAAI,YAAY;AACrB,cAAM,UAAU,GAAG,KAAK,eAAe,SAAS;AAChD,gBAAQ,OAAO,GAAG,GAAG;AACrB,gBAAQ,SAAS;AACjB,gBAAQ,MAAM;AACd,gBAAQ,QAAQ,mBAAmB,GAAG,GAAG,UAAU;AACnD,gBAAQ,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAC5D,YAAI,YAAY,OAAO;AAAA,MACzB;AAAA,IACF;AAIA,UAAM,YAAY,eAAe,CAAC;AAClC,QAAI,WAAW;AACb,YAAM,OAAO,GAAG,QAAQ,YAAY,SAAS;AAC7C,WAAK,QAAQ,uBAAuB,EAAE,cAAc;AACpD,UAAI,YAAY,IAAI;AAAA,IACtB;AAGA,QAAI,KAAK,aAAa,KAAK,UAAU,SAAS,EAAE,KAAK;AACnD,UAAI,YAAY,GAAG,QAAQ,WAAW,UAAU,EAAE,GAAG,CAAC,CAAC;AAAA,IACzD;AACA,QAAI,YAAY,GAAG,QAAQ,SAAS,OAAO,WAAM,QAAG,CAAC;AACrD,SAAK,YAAY,GAAG;AAGpB,UAAM,UAAU,EAAE,UAAU,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK,IAAI,MAAM,GAAG,GAAG,KAAK;AAC1E,SAAK,YAAY,GAAG,OAAO,WAAW,OAAO,CAAC;AAK9C,UAAM,MAAM,GAAG,OAAO,KAAK;AAC3B,UAAM,OAAO,KAAK,QAAQ,EAAE,SAAS;AACrC,QAAI,YACF,MAAM,WAAW,EAAE,QAAQ,MAAM,KAAK,KAAK,SAAS,CAAC,UACpD,OAAO,yBAAsB,WAAW,EAAE,SAAS,CAAC,YAAY,WAAW,OAAO,EAAE,SAAS,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,YAAY;AACnI,SAAK,YAAY,GAAG;AAEpB,UAAM,SAAS,GAAG,OAAO,QAAQ;AAIjC,UAAM,kBAAkB,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,CAAC;AACpD,UAAM,UAAU,gBAAgB,SAAS,gBAAgB,gBAAgB,SAAS,CAAC,IAAI;AACvF,UAAM,YAAY,SAAS;AAAA,MACzB,QAAQ,EAAE;AAAA,MACV,MAAM,UAAU,EAAE,WAAW,QAAQ,OAAO,SAAS,SAAS,MAAM,QAAQ,KAAK,IAAI;AAAA,MACrF,aAAa,KAAK,UAAU,IAAI,SAAS,MAAM,EAAE;AAAA,IACnD,CAAC;AACD,QAAI,EAAE,WAAW,cAAc,UAAU,SAAS,UAAU,WAAW,UAAU;AAC/E,YAAM,OAAO,GAAG,OAAO,WAAW;AAClC,WAAK,OAAO,GAAG,QAAQ,WAAW,GAAG,GAAG,QAAQ,IAAI,UAAU,SAAS,WAAW,CAAC;AACnF,aAAO,YAAY,IAAI;AAAA,IACzB;AAGA,QAAI,EAAE,WAAW,YAAa,QAAO,YAAY,KAAK,aAAa,CAAC,CAAC;AAErE,QAAI,EAAE,SAAU,QAAO,YAAY,KAAK,aAAa,CAAC,CAAC;AAGvD,QAAI,EAAE,SAAS,EAAE,KAAK,SAAS,IAAI,EAAG,QAAO,YAAY,GAAG,OAAO,QAAQ,EAAE,IAAI,CAAC;AAClF,WAAO,YAAY,GAAG,OAAO,QAAQ,eAAe,CAAC,CAAC,CAAC;AAEvD,QAAI,EAAE,WAAW;AACf,YAAM,IAAI,GAAG,SAAS,MAAM;AAC5B,QAAE,MAAM,EAAE;AACV,QAAE,WAAW;AACb,QAAE,cAAc;AAChB,UAAI,EAAE,WAAY,GAAE,SAAS,EAAE;AAC/B,aAAO,YAAY,CAAC;AAAA,IACtB,WAAW,EAAE,YAAY;AACvB,YAAM,MAAM,GAAG,OAAO,MAAM;AAC5B,UAAI,MAAM,EAAE;AACZ,aAAO,YAAY,GAAG;AAAA,IACxB;AAGA,eAAW,KAAK,EAAE,eAAe,CAAC,GAAG;AACnC,UAAI,EAAE,SAAS,SAAS;AACtB,cAAM,IAAI,GAAG,SAAS,MAAM;AAC5B,UAAE,MAAM,EAAE;AACV,UAAE,WAAW;AACb,UAAE,cAAc;AAChB,eAAO,YAAY,CAAC;AAAA,MACtB,OAAO;AACL,cAAM,MAAM,GAAG,OAAO,MAAM;AAC5B,YAAI,MAAM,EAAE;AACZ,YAAI,MAAM,EAAE,QAAQ;AACpB,eAAO,YAAY,GAAG;AAAA,MACxB;AAAA,IACF;AAEA,UAAM,UAAU,GAAG,OAAO,SAAS;AACnC,UAAM,UAAU,GAAG,UAAU,IAAI,WAAW,CAAC,IAAI,WAAW,SAAS;AACrE,YAAQ,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,KAAK,eAAe,CAAC;AAAA,IAAG;AAC7E,UAAM,MAAM,GAAG,UAAU,IAAI,QAAQ;AACrC,QAAI,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,KAAK,cAAc,CAAC;AAAA,IAAG;AACxE,YAAQ,OAAO,SAAS,GAAG;AAC3B,WAAO,YAAY,OAAO;AAE1B,WAAO,YAAY,KAAK,iBAAiB,CAAC,CAAC;AAE3C,WAAO,YAAY,KAAK,aAAa,CAAC,CAAC;AACvC,SAAK,YAAY,MAAM;AAEvB,SAAK,UAAU,MAAM;AACnB,UAAI,KAAM,MAAK,SAAS,OAAO,EAAE,EAAE;AAAA,WAC9B;AACH,aAAK,SAAS,IAAI,EAAE,EAAE;AAEtB,aAAK,KAAK,aAAa,CAAC;AAAA,MAC1B;AACA,WAAK,WAAW;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAAe,GAAY;AACvC,UAAM,SAAS,WAAW,CAAC,IAAI,UAAU;AACzC,UAAM,KAAK,MAAM,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC;AACxC,eAAW,KAAK,CAAC,GAAG,GAAG,KAAK,UAAU,GAAG,KAAK,WAAW,EAAG,KAAI,EAAE,OAAO,EAAE,GAAI,GAAE,SAAS;AAC1F,SAAK,WAAW;AAAG,SAAK,WAAW;AAAG,SAAK,WAAW;AACtD,SAAK,YAAY;AAAA,MACf,MAAM,WAAW,aAAa,oBAAoB;AAAA,MAClD,OAAO,GAAG,WAAW,aAAa,aAAa,UAAU,UAAK,EAAE,SAAS,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK,SAAS;AAAA,IAC7G,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAc,cAAc,GAAY;AACtC,UAAM,KAAK,MAAM,OAAO,EAAE,EAAE;AAC5B,SAAK,WAAW,KAAK,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;AACzD,SAAK,cAAc,KAAK,YAAY,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;AAC/D,SAAK,SAAS,OAAO,EAAE,EAAE;AACzB,SAAK,WAAW;AAAG,SAAK,WAAW;AAAG,SAAK,WAAW;AACtD,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,iBAAY,EAAE,SAAS,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK,SAAS;AAAA,MAChE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,aAAa,GAAyB;AAC5C,UAAM,QAAQ,EAAE,SAAS,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK;AAClD,UAAM,SAAS,GAAG,OAAO,WAAW;AACpC,WAAO,YAAY;AAEnB,UAAM,UAAU,GAAG,UAAU,eAAe,SAAS;AACrD,YAAQ,UAAU,OAAO,MAAM;AAC7B,QAAE,gBAAgB;AAClB,cAAQ,WAAW;AACnB,cAAQ,cAAc;AACtB,YAAM,KAAK,MAAM,OAAO,EAAE,IAAI,EAAE,QAAQ,WAAW,CAAC;AACpD,QAAE,SAAS;AACX,WAAK,WAAW;AAChB,WAAK,WAAW;AAChB,WAAK,WAAW;AAChB,WAAK,YAAY,EAAE,MAAM,kBAAkB,OAAO,kBAAa,KAAK,SAAI,CAAC;AAAA,IAC3E;AAEA,UAAM,UAAU,GAAG,UAAU,eAAe,aAAa;AACzD,YAAQ,UAAU,CAAC,MAAM;AACvB,QAAE,gBAAgB;AAGlB,YAAM,SAAS,KAAK,SAAS,IAAI,EAAE,EAAE;AACrC,UAAI,UAAU,OAAO,aAAa;AAChC,cAAM,IAAI,OAAO,sBAAsB;AACvC,aAAK,aAAa,EAAE,MAAM,WAAW,SAAS,OAAO,GAAG,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,MAAM,EAAE,MAAM;AAAA,MAChG,OAAO;AACL,aAAK,QAAQ,MAAM;AAAA,MACrB;AAAA,IACF;AAEA,WAAO,OAAO,SAAS,OAAO;AAG9B,QAAI,EAAE,UAAU;AACd,YAAM,SAAS,GAAG,UAAU,cAAc,eAAe;AACzD,aAAO,UAAU,CAAC,MAAM;AACtB,UAAE,gBAAgB;AAClB,cAAM,OAAO,OAAO,eAAe,cAAc,SAAS;AAC1D,YAAI,CAAC,KAAM;AACX,cAAM,QAAQ,KAAK,UAAU,OAAO,MAAM;AAC1C,aAAK,MAAM,UAAU,QAAQ,KAAK;AAClC,eAAO,cAAc,QAAQ,kBAAkB;AAAA,MACjD;AACA,aAAO,YAAY,MAAM;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,GAAyB;AAC5C,UAAM,IAAI,EAAE;AACZ,UAAM,OAAO,GAAG,OAAO,QAAQ;AAC/B,SAAK,MAAM,UAAU;AACrB,SAAK,YACH,iFACqB,WAAW,EAAE,QAAQ,GAAG,EAAE,KAAK;AAAA;AAAA,EAAO,EAAE,IAAI,KAAK,EAAE,IAAI,CAAC,YAC5E,EAAE,SAAS,OAAO,wBAAwB,WAAW,EAAE,QAAQ,IAAI,CAAC,WAAW,MAChF,8DACwD,EAAE,SAAS,SAAM,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,YACnG,EAAE,QAAQ,qBAAqB,WAAW,EAAE,KAAK,CAAC,WAAW,OAC7D,EAAE,OAAO,wBAAwB,WAAW,EAAE,IAAI,CAAC,WAAW,OAC9D,EAAE,MAAM,wBAAwB,WAAW,EAAE,GAAG,CAAC,WAAW,MAC7D;AACF,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,kBAAkB;AACxB,QAAI,CAAC,KAAK,UAAW;AACrB,UAAM,UAAU,eAAe,KAAK,eAAe;AACnD,QAAI,CAAC,QAAQ,QAAQ;AACnB,WAAK,UAAU,YAAY;AAC3B,WAAK,UAAU,MAAM,UAAU;AAC/B;AAAA,IACF;AACA,UAAM,KAAK,KAAK,eAAe;AAC/B,SAAK,UAAU,MAAM,UAAU;AAC/B,SAAK,UAAU,YACb,qDACyB,QAAQ,MAAM,gFACO,KAAK,aAAa,QAAQ;AAC1E,IAAC,KAAK,UAAU,cAAc,yBAAyB,EAAkB,UAAU,MAAM;AACvF,WAAK,aAAa,KAAK,KAAK;AAC5B,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,aAAa,GAAyB;AAC5C,UAAM,OAAO,GAAG,OAAO,SAAS;AAChC,UAAM,QAAQ,KAAK,WAAW,IAAI,EAAE,EAAE,KAAK,gBAAgB;AAC3D,UAAM,MAAM,QAAiB,KAAK;AAClC,UAAM,OAAO,KAAK,QAAQ,IAAI,EAAE,EAAE;AAElC,QAAI,KAAK,YAAY,EAAE,IAAI;AACzB,YAAM,OAAO,GAAG,UAAU,YAAY,MAAM,0BAAqB,0BAAqB;AACtF,WAAK,UAAU,CAAC,MAAM;AACpB,UAAE,gBAAgB;AAClB,aAAK,UAAU,EAAE;AACjB,aAAK,WAAW;AAAA,MAClB;AACA,WAAK,YAAY,IAAI;AACrB,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,KAAK,IAAI,UAAU;AAGtB,YAAM,OAAO,GAAG,OAAO,SAAS;AAChC,WAAK,YACH;AAGF,YAAM,MAAM,GAAG,UAAU,YAAY,4BAA4B;AACjE,UAAI,UAAU,OAAO,MAAM;AACzB,UAAE,gBAAgB;AAClB,YAAI,WAAW;AACf,YAAI,cAAc;AAClB,cAAM,KAAK,IAAI,kBAAkB;AAAA,UAC/B,YAAY;AAAA,UAAY,MAAM,KAAK,IAAI;AAAA,UAAM,YAAY,KAAK,IAAI;AAAA,QACpE,CAAC;AACD,aAAK,YAAY;AAAA,UACf,MAAM;AAAA,UAAkB,OAAO;AAAA,UAC/B,QAAQ,KAAK,IAAI;AAAA,UAAY,OAAO;AAAA,QACtC,CAAC;AAAA,MACH;AACA,WAAK,YAAY,GAAG;AACpB,UAAI,CAAC,KAAK,IAAI,iBAAiB;AAC7B,aAAK,YAAY,GAAG,OAAO,aAAa,yDAAyD,CAAC;AAAA,MACpG;AACA,WAAK,YAAY,IAAI;AACrB,WAAK,YAAY,KAAK,SAAS,CAAC,CAAC;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,GAAG,OAAO,SAAS;AAChC,SAAK,YAAY;AACjB,UAAM,MAAM,GAAG,QAAQ,SAAS;AAChC,UAAM,OAAO,GAAG,UAAU,YAAY,QAAG;AACzC,SAAK,WAAW,CAAC,QAAQ,OAAO,EAAE;AAClC,SAAK,aAAa,cAAc,oBAAoB;AACpD,SAAK,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,cAAc,EAAE,IAAI,KAAc,OAAO,EAAE,CAAC;AAAA,IAAG;AACjG,UAAM,QAAQ,GAAG,QAAQ,SAAS,WAAW,KAAK,CAAC;AACnD,UAAM,OAAO,GAAG,UAAU,YAAY,QAAG;AACzC,SAAK,WAAW,CAAC,QAAQ,OAAO,CAAC;AACjC,SAAK,aAAa,cAAc,gBAAgB;AAChD,SAAK,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,cAAc,EAAE,IAAI,KAAc,OAAO,CAAC,CAAC;AAAA,IAAG;AAChG,QAAI,OAAO,MAAM,OAAO,IAAI;AAC5B,SAAK,YAAY,GAAG;AAEpB,UAAMC,QAAO,GAAG,UAAU,YAAY,MAAM;AAC5C,IAAAA,MAAK,WAAW,CAAC,QAAQ,KAAK,KAAK;AACnC,IAAAA,MAAK,UAAU,CAAC,MAAM;AACpB,QAAE,gBAAgB;AAClB,WAAK,cAAc,EAAE,IAAI,KAAc,KAAK,CAAC;AAC7C,WAAK,YAAY,EAAE,MAAM,iBAAiB,OAAO,2BAA2B,CAAC;AAAA,IAC/E;AACA,SAAK,OAAOA,OAAM,KAAK,SAAS,CAAC,CAAC;AAClC,SAAK,YAAY,IAAI;AAErB,QAAI,MAAM;AACR,WAAK,YAAY,GAAG,OAAO,WAAW,kBAAa,CAAC;AAAA,IACtD,WAAW,KAAK;AAGd,YAAM,QAAQ,GAAG,OAAO,UAAU;AAClC,UAAI,EAAE,YAAY;AAChB,cAAM,OAAO,GAAG,OAAO,SAAS;AAChC,aAAK,MAAM,EAAE;AACb,aAAK,MAAM;AACX,cAAM,YAAY,IAAI;AAAA,MACxB;AACA,YAAM,QAAQ,GAAG,UAAU,UAAU;AACrC,YAAM,aAAa,WAAW,EAAE;AAChC,YAAM,aAAa,SAAS,0BAA0B;AAGtD,YAAM,SAAS,uJAC8D,IAAI,OAAO,EAAE,WAAW,IAAI,IAAI;AAC7G,YAAM,MAAM,UAAU,OAAO,KAAK,UAAU;AAC5C,YAAM,YAAY,KAAK;AACvB,WAAK,YAAY,KAAK;AAEtB,YAAM,SAAS,GAAG,OAAO,WAAW;AACpC,aAAO,YAAY;AACnB,YAAM,QAAQ,GAAG,SAAS,UAAU;AACpC,YAAM,OAAO;AACb,YAAM,MAAM;AACZ,YAAM,MAAM;AACZ,YAAM,QAAQ,OAAO,KAAK,MAAM,KAAK,aAAa,GAAG,CAAC;AACtD,YAAM,aAAa,cAAc,0BAA0B;AAG3D,YAAM,UAAU,MAAM;AACpB,aAAK,aAAa,OAAO,MAAM,KAAK,IAAI;AACxC,cAAM,MAAM,UAAU,OAAO,KAAK,UAAU;AAAA,MAC9C;AACA,aAAO,OAAO,OAAO,GAAG,QAAQ,QAAQ,GAAG,KAAK,MAAM,KAAK,aAAa,GAAG,CAAC,GAAG,CAAC;AAChF,WAAK,YAAY,MAAM;AAEvB,UAAI,IAAI,MAAO,MAAK,YAAY,GAAG,OAAO,YAAY,IAAI,KAAK,CAAC;AAAA,IAClE,OAAO;AACL,WAAK,YAAY,GAAG,OAAO,YAAY,wBAAwB,CAAC;AAAA,IAClE;AAGA,UAAM,OAAO,GAAG,OAAO,SAAS;AAChC,UAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,aAAa,cAAc,gBAAgB;AAChD,SAAK;AAAA,MACH,SAAS,UAAU,UAAU,IAAI;AAAA,MACjC,SAAS,UAAU,UAAU,KAAK;AAAA,IACpC;AACA,UAAM,QAAQ,GAAG,SAAS,SAAS;AACnC,UAAM,OAAO;AACb,UAAM,cAAc,MAAM,8CAAoC;AAC9D,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE,EAAE,KAAK;AAC1C,UAAM,UAAU,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,MAAM,KAAK;AAE1D,eAAW,KAAK,CAAC,MAAM,KAAK,EAAG,GAAE,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AACrF,UAAM,OAAO,GAAG,UAAU,aAAa,MAAM;AAC7C,SAAK,WAAW;AAChB,SAAK,UAAU,CAAC,MAAM;AACpB,QAAE,gBAAgB;AAClB,YAAM,UAAU,KAAK,UAAU,IAAI,EAAE,EAAE,KAAK,IAAI,KAAK;AACrD,UAAI,CAAC,OAAQ;AACb,WAAK,UAAU,OAAO,EAAE,EAAE;AAC1B,WAAK,KAAK,YAAY,GAAG,QAAQ,KAAK,KAA4B;AAAA,IACpE;AACA,UAAM,YAAY,CAAC,MAAM;AAAE,UAAI,EAAE,QAAQ,QAAS,MAAK,MAAM;AAAA,IAAG;AAChE,SAAK,OAAO,MAAM,OAAO,IAAI;AAC7B,SAAK,YAAY,IAAI;AACrB,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,GAAyB;AACxC,UAAM,IAAI,GAAG,UAAU,SAAS,QAAG;AACnC,MAAE,aAAa,cAAc,OAAO;AACpC,MAAE,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,UAAU;AAAM,WAAK,WAAW;AAAA,IAAG;AAClF,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,IAAY,OAAuB;AACvD,SAAK,WAAW,IAAI,IAAI,KAAK;AAC7B,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAMA,MAAc,YAAY,GAAY,QAAgB,MAAwC;AAC5F,UAAM,WAAW,KAAK,IAAI;AAC1B,QAAI,CAAC,SAAU;AACf,UAAM,QAAQ,KAAK,WAAW,IAAI,EAAE,EAAE,KAAK,gBAAgB;AAC3D,SAAK,QAAQ,IAAI,EAAE,EAAE;AACrB,SAAK,UAAU,EAAE;AACjB,SAAK,WAAW;AAChB,UAAM,UAAU,KAAK,IAAI;AACzB,QAAI;AACF,YAAM,MAAM,MAAM,SAAS;AAAA,QACzB,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,UAAU,QAAiB,KAAK,KAAK;AAAA,QACrC,SAAS,KAAK,QAAQ;AAAA,MACxB,CAAC;AACD,YAAM,OAAO,aAAa,OAAO;AAAA,QAC/B,IAAI,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,QACzE,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC3B,MAAM,IAAI;AAAA,QACV,KAAK,IAAI;AAAA,QACT,OAAO,IAAI;AAAA,QACX;AAAA,QACA;AAAA,MACF,CAAC;AACD,WAAK,QAAQ,OAAO,EAAE,EAAE;AACxB,WAAK,WAAW,IAAI,EAAE,IAAI,IAAI;AAC9B,WAAK,YAAY;AAAA,QACf,MAAM,YAAY,IAAI;AAAA,QACtB,OAAO,GAAG,SAAS,aAAa,cAAc,aAAa,UAAK,EAAE,SAAS,MAAM;AAAA,QACjF,QAAQ,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,WAAW,GAAI,CAAC,UAAO,WAAW,IAAI,CAAC;AAAA,MAC7E,CAAC;AAAA,IACH,SAAS,GAAG;AACV,WAAK,QAAQ,OAAO,EAAE,EAAE;AACxB,WAAK,YAAY;AAAA,QACf,MAAM;AAAA,QACN,OAAO,sBAAsB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,QACvE,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,kBAAkB,KAAa,OAAgD,CAAC,GAAG;AACjF,UAAM,OAAO,kBAAW,KAAK,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;AACtD,QAAI,SAAS,KAAK,QAAS;AAC3B,SAAK,UAAU;AACf,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,cAAc;AACnB,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,iBAAiB,GAAG;AAAA,MAC3B,QAAQ,KAAK;AAAA,MACb,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,WAAW,QAA8B;AACvC,SAAK,UAAU,EAAE,GAAG,KAAK,SAAS,SAAS,UAAU,OAAU;AAC/D,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,iBAAiB,MAAc;AACrC,UAAM,MAAM,KAAK,QAAQ,cAAc,cAAc;AACrD,QAAI,IAAK,KAAI,cAAc;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,YAAY,KAAkB;AAC1C,UAAM,MAAM,gBAAiB,IAAI,cAAc,YAAY,EAAuB,KAAK;AACvF,UAAM,QAAS,IAAI,cAAc,cAAc,EAAuB,MAAM,KAAK;AACjF,QAAI,CAAC,KAAK;AACR,WAAK,YAAY;AACjB,WAAK,mBAAmB;AACxB;AAAA,IACF;AACA,SAAK,YAAY;AACjB,SAAK,iBAAiB,gBAAW;AACjC,UAAM,MAAM,IAAI,gBAAgB;AAChC,UAAM,QAAQ,WAAW,MAAM,IAAI,MAAM,GAAG,GAAI;AAChD,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,GAAG,cAAc,EAAE,QAAQ,IAAI,OAAO,CAAC;AAClE,UAAI,CAAC,IAAI,IAAI;AACX,aAAK,iBAAiB,8BAA8B,IAAI,MAAM,GAAG;AACjE;AAAA,MACF;AACA,YAAM,OAAY,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AACnD,YAAM,MAAgB,MAAM,QAAQ,MAAM,IAAI,IAC1C,KAAK,KAAK,IAAI,CAAC,MAAW,OAAO,GAAG,MAAM,EAAE,CAAC,EAAE,OAAO,OAAO,IAC7D,CAAC;AAGL,UAAI,SAAS,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,MAAM,MAAM,SAAS,EAAE,WAAW,GAAG,KAAK,GAAG,CAAC,GAAG;AACrF,cAAM,QAAQ,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AACvC,aAAK,iBAAiB,2BAAsB,KAAK,4BAAkB,KAAK,GAAG,IAAI,SAAS,IAAI,aAAQ,EAAE,EAAE;AACxG;AAAA,MACF;AACA,WAAK;AAAA,QACH,IAAI,SAAS,oBAAe,IAAI,MAAM,SAAS,IAAI,WAAW,IAAI,KAAK,GAAG,gBAAgB;AAAA,MAC5F;AAAA,IACF,SAAS,GAAG;AACV,WAAK,iBAAkB,GAAa,SAAS,eACzC,4EACA,mFAAmF;AAAA,IACzF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAAA,EAEQ,gBAAgB;AACtB,QAAI,CAAC,KAAK,UAAW;AACrB,QAAI,CAAC,UAAe,KAAK,OAAO,GAAG;AACjC,WAAK,UAAU,YAAY;AAC3B,WAAK,UAAU,MAAM,UAAU;AAC/B;AAAA,IACF;AACA,UAAM,IAAI,KAAK,QAAQ;AACvB,SAAK,UAAU,MAAM,UAAU;AAC/B,SAAK,UAAU,YACb,uDACM,WAAW,EAAE,aAAa,UAAU,CAAC,sDACpB,WAAW,EAAE,GAAG,CAAC,YACvC,EAAE,SAAS,uBAAuB,WAAW,EAAE,MAAM,CAAC,WAAW,MAClE;AAEF,IAAC,KAAK,UAAU,cAAc,UAAU,EAAkB,UAAU,MAAM;AACxE,YAAM,EAAE,OAAO,IAAI,OAAc,KAAK,SAAS,KAAK;AACpD,WAAK,UAAU;AACf,WAAK,cAAc;AACnB,WAAK,YAAY,EAAE,MAAM,YAAY,OAAO,oBAAoB,EAAE,GAAG,GAAG,CAAC;AAAA,IAC3E;AACA,IAAC,KAAK,UAAU,cAAc,QAAQ,EAAkB,UAAU,MAAM;AACtE,YAAM,EAAE,QAAQ,WAAW,IAAI,OAAc,KAAK,SAAS,IAAI;AAC/D,WAAK,UAAU;AACf,WAAK,cAAc;AACnB,WAAK,YAAY,EAAE,MAAM,aAAa,OAAO,UAAU,UAAU,GAAG,CAAC;AAErE,UAAI,WAAY,QAAO,SAAS,OAAO,UAAU;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAGQ,oBAAoB;AAC1B,SAAK,UAAU,SAAgB,KAAK,OAAO;AAC3C,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGQ,YAAY,QAA0C;AAC5D,UAAM,OAAQ,OAAe,qBAAsB,OAAe;AAClE,UAAM,IAAI,GAAG,UAAU,SAAS,EAAE;AAClC,SAAK,UAAU;AACf,QAAI,CAAC,MAAM;AAET,QAAE,cAAc;AAChB,QAAE,WAAW;AACb,QAAE,QAAQ;AACV,QAAE,aAAa,cAAc,uBAAuB;AACpD,aAAO;AAAA,IACT;AACA,UAAM,OAAO,MAAM;AACjB,QAAE,UAAU,OAAO,IAAI;AACvB,QAAE,cAAc;AAChB,QAAE,aAAa,cAAc,SAAS;AACtC,QAAE,QAAQ;AAAA,IACZ;AACA,UAAM,YAAY,MAAM;AACtB,QAAE,UAAU,IAAI,IAAI;AACpB,QAAE,cAAc;AAChB,QAAE,aAAa,cAAc,gBAAgB;AAC7C,QAAE,QAAQ;AAAA,IACZ;AACA,SAAK;AACL,MAAE,UAAU,CAAC,MAAM;AACjB,QAAE,gBAAgB;AAClB,UAAI,KAAK,OAAO;AAAE,aAAK,UAAU;AAAG,aAAK;AAAG;AAAA,MAAQ;AACpD,YAAM,MAAM,IAAI,KAAK;AACrB,UAAI,aAAa;AACjB,UAAI,iBAAiB;AACrB,UAAI,OAAO,SAAS,gBAAgB,QAAQ;AAC5C,UAAI,OAAO,OAAO,QAAQ,GAAG,OAAO,KAAK,MAAM;AAC/C,UAAI,WAAW,CAAC,OAAY;AAC1B,YAAI,OAAO;AACX,iBAAS,IAAI,GAAG,aAAa,IAAI,GAAG,QAAQ,QAAQ,IAAK,SAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE;AAClF,eAAO,SAAS,OAAO,MAAM,QAAQ,QAAQ,GAAG,EAAE,UAAU;AAC5D,eAAO,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AAAA,MAC5D;AACA,UAAI,UAAU,CAAC,OAAY;AACzB,aAAK,UAAU;AACf,aAAK;AACL,aAAK,YAAY,EAAE,MAAM,eAAe,OAAO,qBAAqB,IAAI,SAAS,SAAS,IAAI,OAAO,QAAQ,CAAC;AAAA,MAChH;AACA,UAAI,QAAQ,MAAM;AAAE,aAAK,QAAQ;AAAM,aAAK;AAAA,MAAG;AAC/C,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,UAAI;AACF,YAAI,MAAM;AACV,kBAAU;AAAA,MACZ,QAAQ;AACN,aAAK,QAAQ;AACb,aAAK;AAAA,MACP;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAIQ,YAAY;AAClB,QAAI;AAAE,WAAK,OAAO,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAwB;AAC1D,SAAK,QAAQ;AACb,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBQ,iBAAiB,GAAyB;AAChD,UAAM,OAAO,GAAG,OAAO,OAAO;AAC9B,UAAM,UAAU,KAAK,SAAS,IAAI,EAAE,EAAE;AAEtC,QAAI,YAAY,QAAW;AACzB,WAAK,YAAY,GAAG,OAAO,iBAAiB,4BAAuB,CAAC;AACpE,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,QAAQ,IAAI,CAAC,OAAO;AAAA,MACjC,IAAI,EAAE;AAAA,MAAW,YAAY,EAAE,OAAO;AAAA,MAAM,MAAM,EAAE;AAAA,MAAM,WAAW,EAAE,OAAO,SAAS;AAAA,IACzF,EAAE;AACF,UAAM,eAAe,mBAAmB,GAAG,OAAO;AAElD,UAAM,OAAO,GAAG,OAAO,MAAM;AAC7B,eAAW,KAAK,cAAc;AAC5B,YAAM,YAAY,EAAE,OAAO,SAAS;AACpC,YAAM,QAAQ,KAAK,WAAW,IAAI,EAAE,EAAE,IAAI,aAAa,KAAK,UAAU,IAAI,EAAE,EAAE,IAAI,YAAY;AAC9F,YAAM,MAAM,GAAG,OAAO,SAAS,YAAY,WAAW,MAAM,KAAK;AACjE,YAAM,YAAY,EAAE,OAAO,QAAQ,KAAK,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY;AACvE,YAAM,OAAO,GAAG,OAAO,UAAU;AACjC,WAAK;AAAA,QACH,GAAG,QAAQ,YAAY,YAAY,WAAW,KAAK,QAAQ;AAAA,QAC3D,GAAG,KAAK,YAAY,EAAE,OAAO,IAAI;AAAA,QACjC,GAAG,QAAQ,YAAY,OAAO,EAAE,SAAS,CAAC;AAAA,MAC5C;AACA,MAAC,KAAK,iBAAiC,QAAQ,KAAK,QAAQ,EAAE,SAAS;AACvE,UAAI,UAAW,MAAK,YAAY,GAAG,QAAQ,WAAW,OAAO,CAAC;AAC9D,UAAI,EAAE,OAAQ,MAAK,YAAY,GAAG,QAAQ,kBAAkB,QAAQ,EAAE,OAAO,eAAe,EAAE,OAAO,SAAS,EAAE,CAAC;AAGjH,YAAM,OAAO,GAAG,OAAO,UAAU;AACjC,iBAAW,OAAO,gBAAgB,EAAE,MAAM,cAAc,EAAE,IAAI,CAAC,GAAG;AAChE,YAAI,IAAI,QAAS,MAAK,YAAY,GAAG,QAAQ,WAAW,IAAI,IAAI,CAAC;AAAA,YAC5D,MAAK,YAAY,SAAS,eAAe,IAAI,IAAI,CAAC;AAAA,MACzD;AACA,UAAI,OAAO,MAAM,IAAI;AAKrB,YAAM,QAAQ,GAAG,OAAO,MAAM;AAC9B,iBAAW,KAAK,mBAAmB,KAAK,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,KAAK,IAAI,KAAK,EAAE,GAAG;AAClF,cAAM,OAAO,GAAG,UAAU,SAAS,EAAE,OAAO,UAAU,GAAG;AACzD,aAAK,OAAO,SAAS,eAAe,EAAE,KAAK,GAAG,GAAG,QAAQ,SAAS,OAAO,EAAE,KAAK,CAAC,CAAC;AAClF,aAAK,QAAQ,EAAE,MAAM,KAAK,IAAI;AAC9B,aAAK,UAAU,CAAC,MAAM;AAAE,YAAE,gBAAgB;AAAG,eAAK,KAAK,MAAM,GAAG,EAAE,IAAI,EAAE,KAAK;AAAA,QAAG;AAChF,cAAM,YAAY,IAAI;AAAA,MACxB;AACA,YAAM,MAAM,GAAG,UAAU,WAAW,QAAG;AACvC,UAAI,QAAQ;AACZ,UAAI,UAAU,CAAC,MAAM;AACnB,UAAE,gBAAgB;AAClB,cAAM,OAAO,MAAM,cAAc,WAAW;AAC5C,cAAM,iBAAiB,WAAW,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;AAC7D,YAAI,KAAM;AACV,cAAM,OAAO,GAAG,OAAO,UAAU;AACjC,mBAAW,SAAS,kBAAkB;AACpC,gBAAM,IAAI,GAAG,UAAU,WAAW,KAAK;AACvC,YAAE,UAAU,CAAC,OAAO;AAAE,eAAG,gBAAgB;AAAG,iBAAK,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AAAA,UAAG;AAC7E,eAAK,YAAY,CAAC;AAAA,QACpB;AACA,cAAM,YAAY,IAAI;AAAA,MACxB;AACA,YAAM,YAAY,GAAG;AACrB,UAAI,YAAY,KAAK;AAIrB,UAAI,EAAE,aAAa,QAAQ;AACzB,cAAM,QAAQ,GAAG,OAAO,UAAU;AAClC,mBAAW,KAAK,EAAE,aAAa;AAC7B,cAAI,EAAE,SAAS,SAAS;AACtB,kBAAM,MAAM,GAAG,OAAO,SAAS;AAC/B,gBAAI,MAAM,EAAE;AACZ,gBAAI,MAAM,EAAE,QAAQ;AACpB,gBAAI,UAAU;AACd,gBAAI,UAAU,CAAC,MAAM;AAAE,gBAAE,gBAAgB;AAAG,qBAAO,KAAK,EAAE,KAAK,UAAU,UAAU;AAAA,YAAG;AACtF,kBAAM,YAAY,GAAG;AAAA,UACvB,WAAW,EAAE,SAAS,SAAS;AAC7B,kBAAM,QAAQ,GAAG,SAAS,SAAS;AACnC,kBAAM,MAAM,EAAE;AACd,kBAAM,WAAW;AACjB,kBAAM,UAAU;AAChB,kBAAM,UAAU,CAAC,MAAM,EAAE,gBAAgB;AACzC,kBAAM,YAAY,KAAK;AAAA,UACzB;AAAA,QACF;AACA,YAAI,MAAM,kBAAmB,KAAI,YAAY,KAAK;AAAA,MACpD;AAEA,UAAI,KAAK,WAAW,IAAI,EAAE,EAAE,EAAG,KAAI,YAAY,GAAG,OAAO,aAAa,eAAU,CAAC;AACjF,UAAI,KAAK,UAAU,IAAI,EAAE,EAAE,GAAG;AAC5B,cAAM,SAAS,GAAG,OAAO,kBAAkB;AAC3C,eAAO,OAAO,SAAS,eAAe,KAAK,OAAO,IAAI,EAAE,EAAE,KAAK,iBAAiB,CAAC;AACjF,cAAM,QAAQ,GAAG,UAAU,aAAa,OAAO;AAC/C,cAAM,UAAU,CAAC,MAAM;AAAE,YAAE,gBAAgB;AAAG,eAAK,KAAK,OAAO,GAAG,EAAE,EAAE;AAAA,QAAG;AACzE,eAAO,YAAY,KAAK;AACxB,YAAI,YAAY,MAAM;AAAA,MACxB;AACA,WAAK,YAAY,GAAG;AAAA,IACtB;AACA,SAAK,YAAY,IAAI;AAGrB,UAAM,QAAQ,GAAG,OAAO,OAAO;AAC/B,UAAM,QAAQ,GAAG,YAAY,UAAU;AACvC,UAAM,OAAO;AACb,UAAM,cAAc;AACpB,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE,EAAE,KAAK;AAE1C,UAAM,UAAU,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,MAAM,KAAK;AAC1D,UAAM,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAC1D,UAAM,YAAY,CAAC,MAAM;AAEvB,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AAAE,UAAE,eAAe;AAAG,aAAK,KAAK,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,MAAG;AAAA,IACjH;AACA,UAAM,OAAO,GAAG,OAAO,YAAY;AACnC,UAAM,OAAO,GAAG,UAAU,cAAc,aAAQ;AAChD,SAAK,aAAa,cAAc,YAAY;AAC5C,SAAK,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,KAAK,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,IAAG;AAEhG,UAAM,SAAS,GAAG,OAAO;AACzB,WAAO,OAAO;AACd,WAAO,WAAW;AAClB,WAAO,SAAS;AAChB,WAAO,MAAM,UAAU;AACvB,UAAM,YAAY,GAAG,UAAU,gBAAgB,WAAI;AACnD,cAAU,QAAQ;AAClB,cAAU,aAAa,cAAc,eAAe;AACpD,cAAU,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,aAAO,MAAM;AAAA,IAAG;AAClE,UAAM,UAAkB,CAAC;AACzB,UAAM,QAAQ,GAAG,OAAO,aAAa;AACrC,UAAM,eAAe,MAAM;AACzB,YAAM,cAAc;AACpB,cAAQ,QAAQ,CAAC,GAAG,MAAM;AACxB,cAAM,OAAO,GAAG,QAAQ,QAAQ,GAAG,eAAe,EAAE,IAAI,MAAM,UAAU,cAAO,WAAI,IAAI,EAAE,IAAI,EAAE;AAC/F,cAAM,IAAI,GAAG,UAAU,UAAU,QAAG;AACpC,UAAE,QAAQ;AACV,UAAE,UAAU,CAAC,OAAO;AAAE,aAAG,gBAAgB;AAAG,kBAAQ,OAAO,GAAG,CAAC;AAAG,uBAAa;AAAA,QAAG;AAClF,aAAK,YAAY,CAAC;AAClB,cAAM,YAAY,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;AACA,WAAO,WAAW,MAAM;AACtB,iBAAW,KAAK,MAAM,KAAK,OAAO,SAAS,CAAC,CAAC,GAAG;AAC9C,cAAM,MAAM,eAAe,EAAE,IAAI,MAAM,UAAU,kBAAkB;AACnE,YAAI,EAAE,OAAO,KAAK;AAChB,eAAK,YAAY,EAAE,MAAM,SAAS,OAAO,SAAS,OAAO,GAAG,EAAE,IAAI,0BAA0B,CAAC;AAC7F;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO,QAAQ;AACf,mBAAa;AAAA,IACf;AAEA,UAAM,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAC1D,SAAK,OAAO,GAAG,QAAQ,cAAc,cAAc,GAAG,WAAW,IAAI;AAGrE,UAAM,UAAU,GAAG,OAAO,cAAc;AACxC,YAAQ,MAAM,UAAU;AACxB,UAAM,qBAAqB,MAAM;AAC/B,YAAM,UAAU,mBAAmB,MAAM,OAAO,MAAM,kBAAkB,MAAM,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,IAAI,UAAU,KAAK,CAAC,CAAC;AACtI,cAAQ,cAAc;AACtB,UAAI,CAAC,QAAQ,QAAQ;AAAE,gBAAQ,MAAM,UAAU;AAAQ;AAAA,MAAQ;AAC/D,cAAQ,MAAM,UAAU;AACxB,iBAAW,UAAU,SAAS;AAC5B,cAAM,IAAI,GAAG,UAAU,gBAAgB,OAAO,IAAI;AAClD,UAAE,UAAU,CAAC,MAAM;AACjB,YAAE,gBAAgB;AAClB,gBAAM,SAAS,MAAM,MAAM,MAAM,GAAG,MAAM,kBAAkB,MAAM,MAAM,MAAM;AAC9E,gBAAM,KAAK,OAAO,YAAY,GAAG;AACjC,gBAAM,QAAQ,MAAM,MAAM,MAAM,MAAM,kBAAkB,MAAM,MAAM,MAAM;AAE1E,gBAAM,QAAQ,GAAG,OAAO,MAAM,GAAG,EAAE,CAAC,IAAI,OAAO,KAAK,QAAQ,QAAQ,EAAE,CAAC,IAAI,KAAK;AAChF,eAAK,UAAU,IAAI,EAAE,IAAI,MAAM,KAAK;AACpC,kBAAQ,MAAM,UAAU;AACxB,gBAAM,MAAM;AAAA,QACd;AACA,gBAAQ,YAAY,CAAC;AAAA,MACvB;AAAA,IACF;AACA,UAAM,UAAU,MAAM;AAAE,WAAK,UAAU,IAAI,EAAE,IAAI,MAAM,KAAK;AAAG,yBAAmB;AAAA,IAAG;AACrF,UAAM,UAAU,MAAM,mBAAmB;AACzC,UAAM,SAAS,MAAM,WAAW,MAAM;AAAE,cAAQ,MAAM,UAAU;AAAA,IAAQ,GAAG,GAAG;AAC9E,UAAM,OAAO,OAAO,SAAS,OAAO,QAAQ,IAAI;AAChD,SAAK,YAAY,KAAK;AAGtB,UAAM,WAAW,eAAe,GAAG,MAAM;AACzC,UAAM,KAAK,GAAG,OAAO,IAAI;AACzB,OAAG,YAAY,GAAG,OAAO,QAAQ,UAAU,CAAC;AAC5C,eAAW,SAAS,UAAU;AAC5B,YAAM,OAAO,GAAG,OAAO,WAAW,MAAM,IAAI,EAAE;AAC9C,WAAK,OAAO,GAAG,QAAQ,QAAQ,GAAG,GAAG,QAAQ,QAAQ,MAAM,KAAK,CAAC;AACjE,UAAI,MAAM,OAAQ,MAAK,YAAY,GAAG,QAAQ,QAAQ,MAAM,MAAM,CAAC;AACnE,SAAG,YAAY,IAAI;AAAA,IACrB;AACA,SAAK,YAAY,EAAE;AAGnB,UAAM,UAAU,GAAG,OAAO,SAAS;AACnC,UAAM,cAAc,GAAG,UAAU,UAAU,kBAAkB;AAC7D,gBAAY,UAAU,CAAC,MAAM;AAC3B,QAAE,gBAAgB;AAClB,YAAM,OAAO;AAAA,QACX;AAAA,UACE,IAAI,EAAE;AAAA,UAAI,MAAM,EAAE;AAAA,UAAM,OAAO,EAAE;AAAA,UAAO,KAAK,EAAE;AAAA,UAAK,QAAQ,EAAE;AAAA,UAAQ,WAAW,EAAE;AAAA,UACnF,MAAM,EAAE;AAAA,UAAM,QAAQ,EAAE,KAAK,EAAE,QAAQ,KAAK,UAAU,EAAE,QAAQ,QAAQ;AAAA,UACxE,UAAU,EAAE;AAAA,UAAU,IAAI,EAAE;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AACA,WAAK,KAAK,SAAS,aAAa,IAAI;AAAA,IACtC;AACA,UAAM,gBAAgB,GAAG,UAAU,UAAU,aAAa;AAC1D,kBAAc,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,KAAK,WAAW,eAAe,CAAC;AAAA,IAAG;AAC9F,YAAQ,OAAO,aAAa,aAAa;AACzC,SAAK,YAAY,OAAO;AAExB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,gBAAgB;AACtB,UAAM,SAAS,KAAK,IAAI;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,OAAO,QAAQ,OAAO,EAAE;AACrC,UAAM,UAAU,SAAS,WAAW,SAAS;AAE7C,UAAM,OAAO,YAAY;AACvB,UAAI;AACF,YAAI,CAAC,KAAK,QAAQ;AAChB,gBAAM,MAAM,MAAM,MAAM,GAAG,IAAI,aAAa;AAAA,YAC1C,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,SAAS,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAAA,UAC3F,CAAC;AACD,cAAI,CAAC,IAAI,GAAI;AACb,gBAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,eAAK,SAAS,KAAK,MAAM;AAAA,QAC3B,OAAO;AACL,gBAAM,MAAM,MAAM,MAAM,GAAG,IAAI,aAAa,mBAAmB,KAAK,MAAM,CAAC,cAAc,EAAE,QAAQ,OAAO,CAAC;AAG3G,cAAI,IAAI,WAAW,IAAK,MAAK,SAAS;AAAA,QACxC;AACA,cAAM,SAAS,MAAM;AAAA,UACnB,GAAG,IAAI,iBAAiB,mBAAmB,OAAO,CAAC,WAAW,mBAAmB,KAAK,UAAU,EAAE,CAAC;AAAA,QACrG;AACA,YAAI,OAAO,IAAI;AACb,gBAAM,OAAQ,MAAM,OAAO,KAAK;AAChC,eAAK,QAAQ,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;AACvD,eAAK,YAAY;AAAA,QACnB;AAAA,MACF,QAAQ;AAEN,aAAK,QAAQ,CAAC;AACd,aAAK,YAAY;AAAA,MACnB;AAAA,IACF;AAEA,SAAK,KAAK;AACV,SAAK,YAAY,YAAY,MAAM,KAAK,KAAK,GAAG,iBAAiB;AAAA,EACnE;AAAA,EAEQ,cAAc;AACpB,QAAI,CAAC,KAAK,OAAQ;AAClB,SAAK,OAAO,cAAc;AAC1B,QAAI,CAAC,KAAK,MAAM,QAAQ;AAAE,WAAK,OAAO,MAAM,UAAU;AAAQ;AAAA,IAAQ;AACtE,SAAK,OAAO,MAAM,UAAU;AAC5B,eAAW,KAAK,KAAK,MAAM,MAAM,GAAG,CAAC,GAAG;AACtC,YAAM,KAAK,GAAG,QAAQ,WAAW,WAAW,EAAE,IAAI,CAAC;AACnD,SAAG,QAAQ,GAAG,EAAE,IAAI;AACpB,WAAK,OAAO,YAAY,EAAE;AAAA,IAC5B;AACA,QAAI,KAAK,MAAM,SAAS,EAAG,MAAK,OAAO,YAAY,GAAG,QAAQ,aAAa,IAAI,KAAK,MAAM,SAAS,CAAC,EAAE,CAAC;AAAA,EACzG;AAAA,EAEQ,eAAe;AACrB,QAAI,KAAK,UAAW,eAAc,KAAK,SAAS;AAChD,SAAK,YAAY;AAEjB,QAAI,KAAK,IAAI,UAAU,KAAK,QAAQ;AAClC,YAAM,OAAO,KAAK,IAAI,OAAO,QAAQ,OAAO,EAAE;AAC9C,WAAK,MAAM,GAAG,IAAI,aAAa,mBAAmB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,UAAU,WAAW,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACzH;AACA,SAAK,SAAS;AACd,SAAK,QAAQ,CAAC;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,mBAAmB;AACzB,UAAM,SAAS,KAAK,IAAI;AACxB,QAAI,CAAC,UAAU,KAAK,WAAY;AAEhC,QAAI,OAAO,gBAAgB,YAAa;AACxC,QAAI;AACF,YAAM,SAAS,IAAI,YAAY,GAAG,OAAO,QAAQ,OAAO,EAAE,CAAC,iBAAiB;AAE5E,aAAO,iBAAiB,UAAU,CAAC,OAAO;AACxC,YAAI;AACJ,YAAI;AAAE,mBAAS,KAAK,MAAO,GAAoB,IAAI;AAAA,QAAG,QAAQ;AAAE;AAAA,QAAQ;AACxE,YAAI,CAAC,UAAU,OAAO,OAAO,aAAa,SAAU;AACpD,YAAI,CAAC,KAAK,SAAS,IAAI,OAAO,QAAQ,EAAG;AACzC,aAAK,KAAK,gBAAgB,OAAO,QAAQ;AAAA,MAC3C,CAAC;AAED,aAAO,UAAU,MAAM;AAAA,MAAC;AACxB,WAAK,aAAa;AAAA,IACpB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,gBAAgB,UAAkB;AAC9C,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,MAAM,aAAa,QAAQ;AACnD,UAAI,CAAC,MAAM,QAAQ,IAAI,EAAG;AAC1B,WAAK,SAAS,IAAI,UAAU,IAAI;AAChC,WAAK,WAAW;AAAA,IAClB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAKQ,YAAY,UAAkB,WAA+B;AACnE,WAAO,KAAK,UAAU,IAAI,GAAG,QAAQ,IAAI,SAAS,EAAE,KAAK,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,MAAM,GAAY,WAAmB,OAAe;AAChE,UAAM,MAAM,GAAG,EAAE,EAAE,IAAI,SAAS;AAChC,UAAM,SAAS,KAAK,YAAY,EAAE,IAAI,SAAS;AAC/C,SAAK,UAAU,IAAI,KAAK,eAAe,QAAQ;AAAA,MAC7C;AAAA,MAAW;AAAA,MAAO,QAAQ,KAAK,IAAI,KAAK;AAAA,MAAI,UAAU,KAAK,IAAI,KAAK;AAAA,IACtE,CAAC,CAAC;AACF,SAAK,WAAW;AAChB,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,MAAM,eAAe;AAAA,QAC3C,UAAU,EAAE;AAAA,QAAI;AAAA,QAAW;AAAA,QAAO,QAAQ,KAAK,IAAI,KAAK;AAAA,QAAI,UAAU,KAAK,IAAI,KAAK;AAAA,MACtF,CAAC;AACD,WAAK,UAAU,IAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK,YAAY,EAAE,IAAI,SAAS,CAAC;AAAA,IACxF,QAAQ;AAEN,WAAK,UAAU,IAAI,KAAK,MAAM;AAAA,IAChC;AACA,SAAK,WAAW;AAAA,EAClB;AAAA,EAKA,MAAc,aAAa;AACzB,QAAI,KAAK,OAAO,IAAI,KAAK,IAAI,UAAU,EAAG;AAC1C,QAAI;AACF,WAAK,OAAO,IAAI,KAAK,IAAI,YAAY,MAAM,KAAK,MAAM,WAAW,KAAK,IAAI,UAAU,CAAC;AAAA,IACvF,QAAQ;AACN,WAAK,OAAO,IAAI,KAAK,IAAI,YAAY,CAAC,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,aAAa,GAAY;AACrC,QAAI,KAAK,SAAS,IAAI,EAAE,EAAE,EAAG;AAE7B,SAAK,KAAK,WAAW;AAErB,SAAK,KAAK,MAAM,cAAc,EAAE,EAAE,EAAE,KAAK,CAAC,QAAQ;AAChD,UAAI,CAAC,MAAM,QAAQ,GAAG,EAAG;AACzB,iBAAW,KAAK,KAAK;AACnB,cAAM,MAAM,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS;AAClC,cAAM,OAAO,KAAK,UAAU,IAAI,GAAG,KAAK,CAAC;AACzC,YAAI,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAG,MAAK,KAAK,CAAC;AAChF,aAAK,UAAU,IAAI,KAAK,IAAI;AAAA,MAC9B;AACA,WAAK,WAAW;AAAA,IAClB,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACjB,QAAI;AACF,WAAK,SAAS,IAAI,EAAE,IAAI,MAAM,KAAK,MAAM,aAAa,EAAE,EAAE,CAAC;AAAA,IAC7D,QAAQ;AACN,WAAK,SAAS,IAAI,EAAE,IAAI,CAAC,CAAC;AAAA,IAC5B;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,UAAU,GAAY,KAAa,QAAgB,CAAC,GAAG;AACnE,UAAM,OAAO,IAAI,KAAK;AAEtB,QAAI,CAAC,QAAQ,CAAC,MAAM,OAAQ;AAC5B,UAAM,SAAuB;AAAA,MAC3B,IAAI,KAAK,IAAI,KAAK;AAAA,MAAI,MAAM,KAAK,IAAI,KAAK;AAAA,MAAM,OAAO,KAAK,IAAI,KAAK;AAAA,MAAO,MAAM;AAAA,IACpF;AAGA,UAAM,cAAc,MAAM,SAAS,MAAM,KAAK,kBAAkB,KAAK,IAAI;AACzE,UAAM,aAA4B;AAAA,MAChC,IAAI,WAAW,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,MAAI,UAAU,EAAE;AAAA,MAAI;AAAA,MAAQ;AAAA,MAClE;AAAA,MAAa,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACjD;AACA,SAAK,SAAS,IAAI,EAAE,IAAI,CAAC,GAAI,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,CAAC,GAAI,UAAU,CAAC;AACxE,SAAK,WAAW,IAAI,WAAW,EAAE;AACjC,SAAK,UAAU,OAAO,EAAE,EAAE;AAC1B,SAAK,WAAW;AAEhB,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI,EAAE,QAAQ,MAAM,YAAY,CAAC;AAC7E,WAAK,SAAS,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,MAAO,EAAE,OAAO,WAAW,KAAK,QAAQ,CAAE,CAAC;AACxG,WAAK,WAAW,OAAO,WAAW,EAAE;AACpC,WAAK,YAAY,EAAE,MAAM,kBAAkB,OAAO,oBAAe,EAAE,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,SAAI,CAAC;AAAA,IACpG,SAAS,GAAG;AACV,WAAK,WAAW,OAAO,WAAW,EAAE;AACpC,WAAK,UAAU,IAAI,WAAW,EAAE;AAChC,WAAK,OAAO,IAAI,WAAW,IAAI,aAAa,QAAQ,EAAE,UAAU,iBAAiB;AAAA,IACnF;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAc,OAAO,GAAY,IAAY;AAC3C,UAAM,SAAS,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrE,QAAI,CAAC,MAAO;AACZ,SAAK,UAAU,OAAO,EAAE;AACxB,SAAK,OAAO,OAAO,EAAE;AACrB,SAAK,WAAW,IAAI,EAAE;AACtB,SAAK,WAAW;AAChB,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,MAAM,WAAW,EAAE,IAAI,EAAE,QAAQ,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC;AAC1F,WAAK,SAAS,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI,EAAE,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,QAAQ,CAAE,CAAC;AAC7F,WAAK,WAAW,OAAO,EAAE;AAAA,IAC3B,SAAS,GAAG;AACV,WAAK,WAAW,OAAO,EAAE;AACzB,WAAK,UAAU,IAAI,EAAE;AACrB,WAAK,OAAO,IAAI,IAAI,aAAa,QAAQ,EAAE,UAAU,iBAAiB;AAAA,IACxE;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAc,SAAS,QAA2B,MAAc;AAC9D,UAAM,WAAW,OAAO;AACxB,QAAI;AACF,UAAI,CAAC,UAAU,WAAW,UAAW,OAAM,IAAI,MAAM,uBAAuB;AAC5E,YAAM,UAAU,UAAU,UAAU,IAAI;AACxC,aAAO,cAAc;AAAA,IACvB,QAAQ;AACN,aAAO,cAAc;AAAA,IACvB;AACA,eAAW,MAAM;AAAE,aAAO,cAAc;AAAA,IAAU,GAAG,IAAI;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,WAAW,QAA2B,GAAY;AAC9D,UAAM,WAAW,OAAO;AACxB,UAAM,UAAU,CAAC,EAAE,YAAY,IAAI,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,EACxG,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AACjC,QAAI,CAAC,QAAQ,QAAQ;AACnB,aAAO,cAAc;AACrB,iBAAW,MAAM;AAAE,eAAO,cAAc;AAAA,MAAU,GAAG,IAAI;AACzD;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQ,MAAM,QAAQ,IAAI,QAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,OAAO,SAAS,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC;AACjG,YAAM,QAA8B,CAAC;AACrC,YAAM,QAAQ,CAAC,MAAM,MAAM;AAAE,cAAM,MAAM,IAAI,cAAc,aAAa,CAAC,EAAE,IAAI;AAAA,MAAM,CAAC;AACtF,YAAO,UAAU,UAAkB,MAAM,CAAC,IAAK,OAAe,cAAc,KAAK,CAAC,CAAC;AACnF,aAAO,cAAc;AAAA,IACvB,QAAQ;AACN,aAAO,cAAc;AAAA,IACvB;AACA,eAAW,MAAM;AAAE,aAAO,cAAc;AAAA,IAAU,GAAG,IAAI;AAAA,EAC3D;AAAA,EAEQ,MAAM,IAAY;AACxB,UAAM,IAAI,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC/C,UAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAE5B,QAAI,GAAG,SAAS,QAAQ;AACtB,iBAAW,KAAK,KAAK,KAAK,OAAO,EAAG,GAAE,UAAU,OAAO,QAAQ;AAC/D,WAAK,UAAU,IAAI,QAAQ;AAC3B,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,WAAW;AAC7D,YAAM,OAAO,KAAK,IAAI,GAAG,SAAS,gBAAgB,YAAY;AAC9D,aAAO,SAAS;AAAA,QACd,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,IAAI,OAAO,OAAO,cAAc,CAAC;AAAA,QAC3D,MAAM,KAAK,IAAI,GAAG,EAAE,OAAO,IAAI,OAAO,OAAO,aAAa,CAAC;AAAA,QAC3D,UAAU;AAAA,MACZ,CAAC;AACD,WAAK,SAAS;AACd;AAAA,IACF;AAEA,QAAI,GAAG,SAAS,YAAY,EAAE,QAAQ;AACpC,iBAAW,KAAK,KAAK,KAAK,OAAO,EAAG,GAAE,UAAU,OAAO,QAAQ;AAC/D,WAAK,UAAU,IAAI,QAAQ;AAE3B,WAAK,iBAAiB;AACtB,aAAO,aAAa,KAAK,WAAW;AACpC,WAAK,cAAc,OAAO,WAAW,MAAM;AACzC,aAAK,iBAAiB;AACtB,aAAK,UAAU,MAAM,UAAU;AAAA,MACjC,GAAG,IAAI;AAGP,YAAMC,OAAM,KAAK,SAAS,IAAI,EAAE;AAChC,UAAIA,KAAK,CAAAA,KAAI,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS,CAAC;AAAA,UAC9D,QAAO,SAAS,EAAE,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,GAAG,UAAU,SAAS,CAAC;AACpH,WAAK,SAAS;AACd;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,IAAI,UAAU,SAAS,UAAU,EAAG;AAChD,eAAW,KAAK,KAAK,KAAK,OAAO,EAAG,GAAE,UAAU,OAAO,QAAQ;AAC/D,QAAI,UAAU,IAAI,QAAQ;AAC1B,UAAM,MAAM,KAAK,SAAS,IAAI,EAAE;AAChC,QAAI,IAAK,KAAI,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS,CAAC;AAAA,EACrE;AAAA;AAAA,EAGQ,QAAQ,KAAqB;AACnC,WAAO,YAAY,KAAK,KAAK,IAAI,QAAQ,KAAK,IAAI,QAAQ;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,qBAA6B;AACnC,UAAM,OAAO,KAAK,IAAI,kBAAkB,IAAI,KAAK,EAAE,QAAQ,OAAO,EAAE;AACpE,QAAI,CAAC,OAAO,QAAQ,YAAa,QAAO;AACxC,UAAM,MAAM,0BAA0B,WAAW,kCAAkC,GAAG;AAEtF,WAAO,wCAAqC,WAAW,GAAG,CAAC,cAAc,WAAW,GAAG,CAAC;AAAA,EAC1F;AAAA,EAEA,UAAU;AACR,SAAK,YAAY,MAAM;AACvB,SAAK,aAAa;AAClB,SAAK,iBAAiB,MAAM;AAC5B,SAAK,kBAAkB;AACvB,QAAI,KAAK,cAAe,eAAc,KAAK,aAAa;AACxD,QAAI,KAAK,aAAc,eAAc,KAAK,YAAY;AACtD,SAAK,eAAe;AACpB,QAAI,KAAK,SAAU,eAAc,KAAK,QAAQ;AAC9C,SAAK,WAAW;AAChB,aAAS,oBAAoB,oBAAoB,KAAK,aAAa;AACnE,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,QAAQ,KAAK;AAClB,SAAK,IAAI,WAAW;AACpB,QAAI,KAAK,KAAM,eAAc,KAAK,IAAI;AACtC,WAAO,aAAa,KAAK,WAAW;AACpC,WAAO,oBAAoB,UAAU,KAAK,WAAW;AACrD,WAAO,oBAAoB,eAAe,KAAK,iBAAiB;AAChE,WAAO,oBAAoB,aAAa,KAAK,eAAe;AAC5D,WAAO,oBAAoB,eAAe,KAAK,YAAY;AAC3D,WAAO,oBAAoB,aAAa,KAAK,UAAU;AACvD,WAAO,oBAAoB,eAAe,KAAK,gBAAgB;AAC/D,WAAO,oBAAoB,aAAa,KAAK,cAAc;AAC3D,WAAO,oBAAoB,iBAAiB,KAAK,cAAc;AAC/D,WAAO,aAAa,KAAK,UAAU;AACnC,aAAS,oBAAoB,WAAW,KAAK,aAAa;AAC1D,aAAS,oBAAoB,SAAS,KAAK,iBAAiB,IAAI;AAChE,aAAS,oBAAoB,WAAW,KAAK,SAAS;AACtD,aAAS,oBAAoB,WAAW,KAAK,OAAO,IAAI;AAExD,UAAM,KAAK,SAAS;AACpB,OAAG,MAAM,aAAa,GAAG,MAAM,cAAc,GAAG,MAAM,eAAe;AACrE,SAAK,MAAM,OAAO;AAAA,EACpB;AACF;AAIA,SAAS,GAA0C,KAAQ,MAAM,IAAI,OAAO,IAA8B;AACxG,QAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAI,IAAK,GAAE,YAAY;AACvB,MAAI,KAAM,GAAE,cAAc;AAC1B,SAAO;AACT;AACA,SAAS,MAAM,GAAW;AAAE,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AAAG;AAEhE,SAAS,OAAO,KAAqB;AACnC,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,OAAO,MAAM,IAAI,EAAG,QAAO;AAC/B,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,QAAQ,GAAI,CAAC;AAC5D,MAAI,IAAI,GAAI,QAAO;AACnB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,SAAO,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC;AAC9B;AACA,IAAI,oBAAoB;AAOxB,SAAS,YAAY,KAAa,QAAiB,UAA2B;AAC5E,QAAM,IAAI,KAAK,MAAM,GAAG;AACxB,MAAI,OAAO,MAAM,CAAC,EAAG,QAAO;AAC5B,QAAM,OAAmC;AAAA,IACvC,KAAK;AAAA,IAAW,OAAO;AAAA,IAAS,MAAM;AAAA,IAAW,MAAM;AAAA,IAAW,QAAQ;AAAA,EAC5E;AACA,MAAI;AACF,WAAO,IAAI,KAAK,eAAe,UAAU,QAAW,EAAE,GAAG,MAAM,UAAU,YAAY,OAAU,CAAC,EAAE,OAAO,CAAC;AAAA,EAC5G,SAAS,KAAK;AACZ,QAAI,CAAC,mBAAmB;AACtB,0BAAoB;AACpB,cAAQ,KAAK,qCAAqC,YAAY,GAAG,MAAM,UAAU,GAAG,0BAA0B,GAAG;AAAA,IACnH;AACA,WAAO,IAAI,KAAK,eAAe,QAAW,IAAI,EAAE,OAAO,CAAC;AAAA,EAC1D;AACF;AAEA,SAAS,UAAU,KAAqB;AACtC,MAAI;AAAE,WAAO,IAAI,IAAI,KAAK,SAAS,MAAM,EAAE,YAAY;AAAA,EAAK,QAAQ;AAAE,WAAO;AAAA,EAAK;AACpF;AAMA,SAAS,gBAAgB,KAA4B;AACnD,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,CAAC,EAAG,QAAO;AACf,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,CAAC;AACnB,QAAI,EAAE,aAAa,WAAW,EAAE,aAAa,SAAU,QAAO;AAC9D,QAAI,CAAC,EAAE,SAAU,QAAO;AACxB,UAAM,OAAO,EAAE,SAAS,QAAQ,QAAQ,EAAE;AAC1C,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAS,KAAqB;AACrC,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,MAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AACtC,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,UAAU,CAAC,MAAY,IAAI,KAAK,EAAE,YAAY,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC,EAAE,QAAQ;AAC1F,QAAM,OAAO,KAAK,OAAO,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,KAAU;AAClE,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,OAAO,EAAG,QAAO,GAAG,IAAI;AAC5B,SAAO,EAAE,mBAAmB,QAAW,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AAC5F;AACA,SAAS,QAAQ,GAAW,KAAa,KAAa;AAAE,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC;AAAG;AAGhG,SAAS,SAAS,MAAc,OAAe,UAAsC;AACnF,QAAM,IAAI,SAAS,cAAc,QAAQ;AACzC,IAAE,QAAQ;AACV,IAAE,cAAc;AAChB,IAAE,WAAW;AACb,SAAO;AACT;AACA,SAAS,WAAW,GAAmB;AACrC,SAAO,EAAE,QAAQ,YAAY,CAAC,OAAO,EAAE,KAAK,SAAS,KAAK,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,GAAE,CAAC,CAAG;AACnH;AAEA,SAAS,WAAW,GAAmB;AACrC,SAAO,WAAW,CAAC;AACrB;AAIA,IAAM,MAAM,CAAC,UACX,kFAAkF,KAAK;AACzF,IAAM,aAAa;AACnB,IAAM,cAAc,IAAI,GAAG,UAAU,2EAA2E;AAChH,IAAM,eAAe,IAAI,GAAG,UAAU,2EAA2E;AACjH,IAAM,gBAAgB,IAAI,GAAG,UAAU,4EAA4E;AACnH,IAAM,UAAU;AAAA,EACd;AACkE;AACpE,IAAM,QAAQ;AAAA,EACZ;AAG4H;AAC9H,IAAM,SAAS;AAAA,EACb;AAAgI;AAClI,IAAM,UAAU;AAAA,EACd;AAAgH;AAClH,IAAM,SAAS;AAAA,EACb;AAC8L;AAChM,IAAM,aAAa;AAAA,EACjB;AAAsF;AAGxF,IAAM,YAAY;AAAA,EAChB;AACoG;AAEtG,IAAM,SAAS;AAAA,EACb;AACiG;AACnG,IAAM,QAAQ;AAAA,EACZ;AACwE;AAC1E,IAAM,SAAS;AAAA,EACb;AAEyF;AAE3F,IAAM,YAAY;AAAA,EAChB;AACF;AACA,IAAM,gBACJ,uBAAuB,IAAI,0HAA0H,CAAC;AAGxJ,IAAM,cACJ;AAKF,IAAM,YACJ;AAKF,IAAM,cACJ;AAMF,IAAM,aACJ;AAMF,IAAM,WACJ;AAGF,IAAM,UACJ;AAGF,IAAM,aACJ;AAGF,IAAM,WACJ;AAKF,SAAS,WAAW,OAAyC;AAC3D,SAAO;AAAA,IACL,KAAK;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO,CAAC;AAAA,IACR,WAAW;AAAA,IACX,MAAM,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC,GAAG,GAAG,KAAK,MAAM,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,IACnE,UAAU,EAAE,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AAAA,EAC1D;AACF;AAGA,SAAS,aAAa,QAA4B;AAChD,SAAO;AAAA,IACL,KAAK;AAAA,IACL,SAAS,UAAU,KAAK,MAAM,OAAO,CAAC,CAAC,OAAI,KAAK,MAAM,OAAO,CAAC,CAAC;AAAA,IAC/D,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO,CAAC;AAAA,IACR,WAAW;AAAA,IACX,MAAM,EAAE,GAAG,KAAK,MAAM,OAAO,CAAC,GAAG,GAAG,KAAK,MAAM,OAAO,CAAC,GAAG,GAAG,KAAK,MAAM,OAAO,CAAC,GAAG,GAAG,KAAK,MAAM,OAAO,CAAC,EAAE;AAAA,IAC3G,UAAU,EAAE,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AAAA,EAC1D;AACF;AACA,SAAS,WAAW,QAA4B;AAC9C,SAAO,sCAAsC,KAAK,MAAM,OAAO,CAAC,CAAC,OAAI,KAAK,MAAM,OAAO,CAAC,CAAC,mBAAmB,KAAK,MAAM,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,CAAC,CAAC;AAC3J;AAEA,SAAS,SAAS,KAAsB;AACtC,QAAM,SAAS,IAAI,aAAa,aAAa,KAAK,IAAI,aAAa,WAAW;AAC9E,QAAM,MAAM,IAAI,QAAQ,YAAY;AACpC,MAAI,OAAQ,QAAO,GAAG,GAAG,iBAAiB,MAAM;AAChD,MAAI,IAAI,GAAI,QAAO,GAAG,GAAG,IAAI,IAAI,EAAE;AACnC,QAAM,OAAO,IAAI,eAAe,IAAI,KAAK,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAC3E,SAAO,MAAM,GAAG,GAAG,eAAO,GAAG,WAAM;AACrC;AAMA,SAAS,eAAe,GAAoB;AAC1C,MAAI,EAAE,SAAS,OAAQ,QAAO;AAC9B,MAAI,EAAE,SAAS,YAAY,EAAE,QAAQ;AACnC,UAAM,OAAO,GAAG,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,OAAI,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC;AAChE,QAAI,EAAE,OAAO,QAAQ,SAAU,QAAO,QAAQ,IAAI;AAGlD,WAAO,QAAQ,IAAI,SAAM,UAAU,EAAE,OAAO,GAAG,IAAI,OAAO,MAAM,IAAI,YAAY,EAAE,MAAM,CAAC;AAAA,EAC3F;AACA,SAAO,YAAY,EAAE,MAAM;AAC7B;AACA,SAAS,YAAY,GAAmB;AACtC,QAAM,MAAM,EAAE,OAAO;AACrB,MAAI,EAAE,OAAQ,QAAO,GAAG,GAAG,iBAAiB,EAAE,MAAM;AACpD,QAAM,QAAQ,EAAE,QAAQ,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACtD,MAAI,KAAM,QAAO,GAAG,GAAG,eAAO,KAAK,SAAS,KAAK,KAAK,MAAM,GAAG,EAAE,EAAE,QAAQ,IAAI,WAAM,IAAI;AACzF,QAAM,QAAQ,EAAE,SAAS,CAAC;AAC1B,QAAM,QAAQ,MAAM,YAAY,KAAK,MAAM,SAAS,MAAM,eAAe,MAAM,OAAO,MAAM;AAC5F,MAAI,MAAO,QAAO,GAAG,GAAG,eAAO,KAAK;AACpC,SAAO,EAAE,WAAW;AACtB;AAGA,IAAM,mBAAmB;AAOzB,SAASL,iBAAgB,MAAsB,IAAgC;AAC7E,QAAM,OAAO,GAAG,IAAI,GAAG;AACvB,MAAI,QAAQ,EAAG,QAAO;AACtB,WAAS,IAAoB,MAAM,KAAK,MAAM,SAAS,QAAQ,MAAM,SAAS,iBAAiB,IAAI,EAAE,eAAe;AAClH,UAAM,IAAI,EAAE,sBAAsB;AAClC,QAAI,EAAE,SAAS,KAAK,EAAE,UAAU,EAAG;AACnC,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;AAC9E,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC;AAC9E,QAAK,KAAK,KAAM,QAAQ,iBAAkB,QAAO;AAAA,EACnD;AACA,SAAO;AACT;AAQA,SAAS,UAAU,KAA+D;AAChF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,KAAK,MAAM,KAAK;AACtB,SAAO,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI,KAAK;AAC7G;AAMA,SAAS,WAAW,GAAqB;AACvC,SAAO,gBAAgB,EAAE,MAAM,MAAM;AACvC;;;ACz6JA,IAAMM,cAAa,CAAC,MAClB,EAAE,QAAQ,YAAY,CAAC,OAAO,EAAE,KAAK,SAAS,KAAK,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,GAAE,CAAC,CAAG;AAErG,SAAS,aAAuB;AACrC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,CAAC,QAAyB;AAChC,YAAM,UAAU,IAAI,WAAW;AAC/B,YAAM,SAAS,KAAK;AAAA,QAClB;AAAA,UACE,YAAY;AAAA,YACV,OAAO;AAAA,cACL,SAAS;AAAA,cACT,MAAM,CAAC,MAAM,eAAe;AAAA,cAC5B,KAAK,EAAE,WAAW,SAAS,mBAAmB,IAAI,YAAY,iBAAiB,wBAAwB;AAAA,YACzG;AAAA,UACF;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,QAA4B;AAAA,QAChC,CAAC,qBAAqB,+EAA+E;AAAA,QACrG,CAAC,4BAA4B,mFAAmF;AAAA,QAChH,CAAC,qBAAqB,uLAAkL;AAAA,MAC1M;AAEA,aACE,uTAMA,MAAM,IAAI,CAAC,CAAC,OAAO,IAAI,GAAG,MACxB,4BAA4B,IAAI,CAAC,KAAKA,YAAW,KAAK,CAAC,8BAC/BA,YAAW,IAAI,CAAC,YACvC,MAAM,IAAI,2BAA2BA,YAAW,MAAM,CAAC,WAAW,MACnE,OAAO,EAAE,KAAK,EAAE,IAClB;AAAA,IAEJ;AAAA,EACF;AACF;;;AC/CA,IAAI,MAAuB;AAQpB,SAAS,KAAK,QAA2B;AAC9C,MAAI,IAAK;AACT,MAAI,CAAC,QAAQ,YAAY;AAAE,YAAQ,MAAM,oCAAoC;AAAG;AAAA,EAAQ;AACxF,MAAI,CAAC,OAAO,MAAM,IAAI;AAAE,YAAQ,MAAM,+BAA+B;AAAG;AAAA,EAAQ;AAEhF,QAAM,IAAI,SAAS,MAAM;AACzB,QAAM,OAAO,MAAM,IAAK,MAAM;AAC9B,MAAI,SAAS,eAAe,UAAW,UAAS,iBAAiB,oBAAoB,IAAI;AAAA,MACpF,MAAK;AACZ;AAGO,SAAS,UAAgB;AAC9B,OAAK,QAAQ;AACb,QAAM;AACR;AASO,SAAS,cAAc,OAAiC;AAC7D,OAAK,YAAY,KAAK;AACxB;AAGO,SAAS,kBAAkB,QAA8B;AAC9D,OAAK,kBAAkB,MAAM;AAC/B;AAGO,SAAS,gBAAsB;AACpC,OAAK,cAAc;AACrB;AAOO,SAASC,mBAAkB,KAAa,MAAsD;AACnG,OAAK,kBAAkB,KAAK,IAAI;AAClC;AAGO,SAAS,WAAW,QAAqD;AAC9E,OAAK,WAAW,MAAM;AACxB;AAGO,SAAS,SAAS,MAAgC;AACvD,OAAK,SAAS,IAAI;AACpB;AAMO,SAAS,eAAqB;AACnC,OAAK,aAAa;AACpB;AAGO,SAAS,eAAqB;AACnC,OAAK,aAAa;AACpB;","names":["el","svg","el","svg","current","el","blobToDataUrl","normalizeStage","normalizeStage","current","init","uid","el","url","label","regionContainer","x","slot","W","undo","elx","escapeHtml","requestNavigation"]}