@hexclave/next 1.0.14 → 1.0.16
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/clickmap/clickmap-core.d.ts +15 -0
- package/dist/clickmap/clickmap-core.d.ts.map +1 -0
- package/dist/clickmap/clickmap-core.js +1527 -0
- package/dist/clickmap/clickmap-core.js.map +1 -0
- package/dist/clickmap/clickmap-styles.d.ts +5 -0
- package/dist/clickmap/clickmap-styles.d.ts.map +1 -0
- package/dist/clickmap/clickmap-styles.js +1095 -0
- package/dist/clickmap/clickmap-styles.js.map +1 -0
- package/dist/clickmap/index.d.ts +16 -0
- package/dist/clickmap/index.d.ts.map +1 -0
- package/dist/clickmap/index.js +74 -0
- package/dist/clickmap/index.js.map +1 -0
- package/dist/components/api-key-dialogs.d.ts +1 -1
- package/dist/components/api-key-dialogs.js +5 -5
- package/dist/components/credential-sign-in.js +3 -3
- package/dist/components/credential-sign-up.js +5 -5
- package/dist/components/elements/sidebar-layout.js +1 -1
- package/dist/components/elements/user-avatar.js +1 -1
- package/dist/components/magic-link-sign-in.js +5 -5
- package/dist/components/message-cards/known-error-message-card.d.ts +1 -1
- package/dist/components/message-cards/predefined-message-card.js +1 -1
- package/dist/components/passkey-button.js +1 -1
- package/dist/components/profile-image-editor.js +1 -1
- package/dist/components/team-icon.js +1 -1
- package/dist/components/team-switcher.js +2 -2
- package/dist/components/user-button.js +1 -1
- package/dist/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
- package/dist/components-page/account-settings/editable-text.js +1 -1
- package/dist/components-page/account-settings/email-and-auth/emails-section.js +3 -3
- package/dist/components-page/account-settings/email-and-auth/mfa-section.js +1 -1
- package/dist/components-page/account-settings/email-and-auth/password-section.js +3 -3
- package/dist/components-page/account-settings/teams/team-api-keys-section.js +1 -1
- package/dist/components-page/account-settings/teams/team-creation-page.js +3 -3
- package/dist/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
- package/dist/components-page/account-settings.js +3 -3
- package/dist/components-page/auth-page.js +2 -2
- package/dist/components-page/cli-auth-confirm.js +2 -2
- package/dist/components-page/cli-auth-confirm.test.js +1 -1
- package/dist/components-page/email-verification.js +1 -1
- package/dist/components-page/forgot-password.d.ts.map +1 -1
- package/dist/components-page/forgot-password.js +6 -7
- package/dist/components-page/forgot-password.js.map +1 -1
- package/dist/components-page/hexclave-handler-client.d.ts +1 -1
- package/dist/components-page/hexclave-handler-client.js +2 -2
- package/dist/components-page/magic-link-callback.js +1 -1
- package/dist/components-page/mfa.js +7 -22
- package/dist/components-page/mfa.js.map +1 -1
- package/dist/components-page/oauth-callback.js +2 -2
- package/dist/components-page/onboarding.js +4 -4
- package/dist/components-page/password-reset.d.ts.map +1 -1
- package/dist/components-page/password-reset.js +12 -14
- package/dist/components-page/password-reset.js.map +1 -1
- package/dist/components-page/team-creation.js +5 -5
- package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +258 -262
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/dev-tool/dev-tool-styles.d.ts +1 -1
- package/dist/dev-tool/dev-tool-styles.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-styles.js +13 -143
- package/dist/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/dev-tool/index.d.ts.map +1 -1
- package/dist/dev-tool/index.js +4 -11
- package/dist/dev-tool/index.js.map +1 -1
- package/dist/esm/clickmap/clickmap-core.d.ts +15 -0
- package/dist/esm/clickmap/clickmap-core.d.ts.map +1 -0
- package/dist/esm/clickmap/clickmap-core.js +1525 -0
- package/dist/esm/clickmap/clickmap-core.js.map +1 -0
- package/dist/esm/clickmap/clickmap-styles.d.ts +5 -0
- package/dist/esm/clickmap/clickmap-styles.d.ts.map +1 -0
- package/dist/esm/clickmap/clickmap-styles.js +1093 -0
- package/dist/esm/clickmap/clickmap-styles.js.map +1 -0
- package/dist/esm/clickmap/index.d.ts +16 -0
- package/dist/esm/clickmap/index.d.ts.map +1 -0
- package/dist/esm/clickmap/index.js +72 -0
- package/dist/esm/clickmap/index.js.map +1 -0
- package/dist/esm/components/api-key-dialogs.d.ts +1 -1
- package/dist/esm/components/api-key-dialogs.js +5 -5
- package/dist/esm/components/credential-sign-in.js +3 -3
- package/dist/esm/components/credential-sign-up.js +5 -5
- package/dist/esm/components/elements/sidebar-layout.js +1 -1
- package/dist/esm/components/elements/user-avatar.js +1 -1
- package/dist/esm/components/magic-link-sign-in.js +5 -5
- package/dist/esm/components/message-cards/predefined-message-card.js +1 -1
- package/dist/esm/components/passkey-button.js +1 -1
- package/dist/esm/components/profile-image-editor.js +1 -1
- package/dist/esm/components/team-icon.js +1 -1
- package/dist/esm/components/team-switcher.js +2 -2
- package/dist/esm/components/user-button.js +1 -1
- package/dist/esm/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
- package/dist/esm/components-page/account-settings/editable-text.js +1 -1
- package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +3 -3
- package/dist/esm/components-page/account-settings/email-and-auth/mfa-section.js +1 -1
- package/dist/esm/components-page/account-settings/email-and-auth/password-section.js +3 -3
- package/dist/esm/components-page/account-settings/teams/team-api-keys-section.js +1 -1
- package/dist/esm/components-page/account-settings/teams/team-creation-page.js +3 -3
- package/dist/esm/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
- package/dist/esm/components-page/account-settings.d.ts +1 -1
- package/dist/esm/components-page/account-settings.js +3 -3
- package/dist/esm/components-page/auth-page.js +2 -2
- package/dist/esm/components-page/cli-auth-confirm.js +2 -2
- package/dist/esm/components-page/cli-auth-confirm.test.js +1 -1
- package/dist/esm/components-page/email-verification.js +1 -1
- package/dist/esm/components-page/forgot-password.d.ts.map +1 -1
- package/dist/esm/components-page/forgot-password.js +6 -7
- package/dist/esm/components-page/forgot-password.js.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.d.ts +1 -1
- package/dist/esm/components-page/hexclave-handler-client.js +2 -2
- package/dist/esm/components-page/magic-link-callback.js +1 -1
- package/dist/esm/components-page/mfa.js +7 -22
- package/dist/esm/components-page/mfa.js.map +1 -1
- package/dist/esm/components-page/oauth-callback.js +2 -2
- package/dist/esm/components-page/onboarding.js +4 -4
- package/dist/esm/components-page/password-reset.d.ts.map +1 -1
- package/dist/esm/components-page/password-reset.js +11 -13
- package/dist/esm/components-page/password-reset.js.map +1 -1
- package/dist/esm/components-page/team-creation.js +5 -5
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +35 -39
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.d.ts +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.js +13 -143
- package/dist/esm/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/esm/dev-tool/index.d.ts.map +1 -1
- package/dist/esm/dev-tool/index.js +1 -8
- package/dist/esm/dev-tool/index.js.map +1 -1
- package/dist/esm/generated/global-css.d.ts +1 -1
- package/dist/esm/generated/global-css.js +1 -1
- package/dist/esm/generated/global-css.js.map +1 -1
- package/dist/esm/generated/quetzal-translations.d.ts +2 -2
- package/dist/esm/in-page-ui/base-styles.d.ts +5 -0
- package/dist/esm/in-page-ui/base-styles.d.ts.map +1 -0
- package/dist/esm/in-page-ui/base-styles.js +166 -0
- package/dist/esm/in-page-ui/base-styles.js.map +1 -0
- package/dist/esm/in-page-ui/dom.d.ts +15 -0
- package/dist/esm/in-page-ui/dom.d.ts.map +1 -0
- package/dist/esm/in-page-ui/dom.js +44 -0
- package/dist/esm/in-page-ui/dom.js.map +1 -0
- package/dist/esm/lib/auth.js +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +6 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js +21 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +4 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.d.ts +13 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js +146 -14
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js +221 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts +5 -0
- package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/esm/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/esm/providers/theme-provider.js +1 -1
- package/dist/esm/providers/translation-provider.js +1 -1
- package/dist/generated/global-css.d.ts +1 -1
- package/dist/generated/global-css.js +1 -1
- package/dist/generated/global-css.js.map +1 -1
- package/dist/generated/quetzal-translations.d.ts +2 -2
- package/dist/in-page-ui/base-styles.d.ts +5 -0
- package/dist/in-page-ui/base-styles.d.ts.map +1 -0
- package/dist/in-page-ui/base-styles.js +168 -0
- package/dist/in-page-ui/base-styles.js.map +1 -0
- package/dist/in-page-ui/dom.d.ts +15 -0
- package/dist/in-page-ui/dom.d.ts.map +1 -0
- package/dist/in-page-ui/dom.js +51 -0
- package/dist/in-page-ui/dom.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/integrations/convex/component/convex.config.d.ts +1 -1
- package/dist/lib/auth.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +5 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js +21 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +4 -2
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.d.ts +13 -0
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.js +146 -14
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js +221 -0
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +5 -0
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
- package/dist/lib/hexclave-app/common.d.ts +1 -1
- package/dist/providers/hexclave-provider-client.d.ts +1 -1
- package/dist/providers/theme-provider.js +1 -1
- package/dist/providers/translation-provider.js +1 -1
- package/dist/{storage-CKzvsBxG.d.ts → storage-ksajV_p6.d.ts} +1 -1
- package/dist/{storage-CKzvsBxG.d.ts.map → storage-ksajV_p6.d.ts.map} +1 -1
- package/package.json +4 -4
- package/src/clickmap/clickmap-core.ts +1997 -0
- package/src/clickmap/clickmap-styles.ts +1102 -0
- package/src/clickmap/index.ts +95 -0
- package/src/components-page/forgot-password.tsx +1 -2
- package/src/components-page/mfa.tsx +12 -21
- package/src/components-page/password-reset.tsx +4 -6
- package/src/dev-tool/dev-tool-core.ts +38 -65
- package/src/dev-tool/dev-tool-styles.ts +13 -142
- package/src/dev-tool/index.ts +1 -14
- package/src/in-page-ui/base-styles.ts +171 -0
- package/src/in-page-ui/dom.ts +80 -0
- package/src/lib/hexclave-app/apps/implementations/admin-app-impl.ts +23 -1
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +7 -0
- package/src/lib/hexclave-app/apps/implementations/event-tracker.test.ts +287 -0
- package/src/lib/hexclave-app/apps/implementations/event-tracker.ts +226 -16
- package/src/lib/hexclave-app/apps/interfaces/admin-app.ts +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickmap-core.js","names":[],"sources":["../../../src/clickmap/clickmap-core.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\n// Standalone clickmap overlay. This module is fully independent from the dev\n// tool (packages/template/src/dev-tool): it has its own DOM root, its own\n// stylesheet, and its own mount lifecycle, so the dev tool can be changed or\n// removed without affecting clickmaps. It's opened via a dashboard-minted\n// token (the CLICKMAP_OVERLAY_TOKEN_UPDATED event / resume flow) — see\n// ./index.ts for the lazy-loading entry point.\n\nimport { AnalyticsClickmapResponseBodySchema, type AnalyticsClickmapResponse } from \"@hexclave/shared/dist/interface/admin-metrics\";\nimport {\n CLICKMAP_OVERLAY_RESUME_STORAGE_KEY,\n CLICKMAP_OVERLAY_TOKEN_STORAGE_KEY,\n CLICKMAP_OVERLAY_TOKEN_UPDATED_EVENT,\n} from \"@hexclave/shared/dist/utils/analytics-clickmap-overlay\";\nimport { CLICKMAP_ROOT_ID, DEV_TOOL_ROOT_ID } from \"@hexclave/shared/dist/utils/dev-tool\";\nimport { cssEscapeIdent } from \"@hexclave/shared/dist/utils/dom\";\nimport { buildElementsChain, parseElementsChain, type ElementsChainSegment } from \"@hexclave/shared/dist/utils/elements-chain\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { stringCompare } from \"@hexclave/shared/dist/utils/strings\";\nimport { getGlobalUiInstance, h, hasAppendChild, setGlobalUiInstance, setHtml, type UiGlobalInstance } from \"../in-page-ui/dom\";\nimport type { StackClientApp } from \"../lib/hexclave-app\";\nimport { hexclaveAppInternalsSymbol } from \"../lib/hexclave-app/common\";\nimport { clickmapCSS } from \"./clickmap-styles\";\n\ntype ClickmapPanelResult = { element: HTMLElement, cleanup?: () => void };\n\n// ---------------------------------------------------------------------------\n// Clickmap panel\n// ---------------------------------------------------------------------------\n\ntype ClickmapClickGroup = {\n selector: string;\n label: string;\n count: number;\n // Clicks on this element that produced no observable effect (is_dead rows).\n deadCount: number;\n element: Element | null;\n rect: DOMRect | null;\n};\n\ntype ClickmapGroupOverlayElement = {\n marker: HTMLElement;\n outline: HTMLElement;\n};\n\ntype ClickmapListRowElement = {\n row: HTMLElement;\n count: HTMLElement;\n check: HTMLButtonElement;\n eye: HTMLButtonElement;\n label: HTMLElement;\n dead: HTMLElement;\n selector: HTMLElement;\n group: ClickmapClickGroup | null;\n renderedEyeIcon: string;\n renderedCheckIcon: string;\n};\n\nconst CLICKMAP_FILTERS_STORAGE_KEY = 'hexclave-clickmap-overlay-filters';\n\ntype ClickmapRangeKey = '24h' | '7d' | '30d';\ntype ClickmapDeviceKey = 'all' | 'mobile' | 'tablet' | 'laptop' | 'desktop' | 'widescreen' | 'tv';\n\ntype ClickmapFilters = {\n range: ClickmapRangeKey,\n device: ClickmapDeviceKey,\n urlPattern: string,\n elementSearch: string,\n // Reveal dead clicks in the overlay. Off by default: every displayed count\n // is alive clicks only, dead chips are hidden, and elements whose clicks\n // were all dead are dropped. Pure client-side filter — the server response\n // always carries both clicks (total) and dead_clicks per element, so\n // toggling never refetches.\n showDead: boolean,\n};\n\ntype ClickmapViewportBucket = {\n min: number,\n max: number | null,\n};\n\nconst CLICKMAP_DEFAULT_FILTERS: ClickmapFilters = {\n range: '7d',\n device: 'all',\n urlPattern: '',\n elementSearch: '',\n showDead: false,\n};\n\nconst CLICKMAP_RANGE_MS: Record<ClickmapRangeKey, number> = {\n '24h': 24 * 60 * 60 * 1000,\n '7d': 7 * 24 * 60 * 60 * 1000,\n '30d': 30 * 24 * 60 * 60 * 1000,\n};\n\nconst CLICKMAP_VIEWPORT_BUCKETS: Record<Exclude<ClickmapDeviceKey, 'all'>, ClickmapViewportBucket> = {\n mobile: { min: 0, max: 767 },\n tablet: { min: 768, max: 1023 },\n laptop: { min: 1024, max: 1199 },\n desktop: { min: 1200, max: 1439 },\n widescreen: { min: 1440, max: 1919 },\n tv: { min: 1920, max: null },\n};\n\nfunction getClickmapViewportBucket(device: ClickmapDeviceKey): ClickmapViewportBucket | null {\n if (device === 'all') return null;\n return CLICKMAP_VIEWPORT_BUCKETS[device];\n}\n\nfunction isClickmapViewportWidthInBucket(width: number, bucket: ClickmapViewportBucket): boolean {\n return width >= bucket.min && (bucket.max == null || width <= bucket.max);\n}\n\nfunction getClickmapRecommendedViewportWidth(bucket: ClickmapViewportBucket): number {\n if (bucket.max == null) return bucket.min;\n return Math.round((bucket.min + bucket.max) / 2);\n}\n\nfunction formatClickmapViewportBucket(bucket: ClickmapViewportBucket): string {\n if (bucket.max == null) return `${bucket.min}px+`;\n return `${bucket.min}-${bucket.max}px`;\n}\n\nfunction isClickmapRangeKey(value: unknown): value is ClickmapRangeKey {\n return value === '24h' || value === '7d' || value === '30d';\n}\nfunction isClickmapDeviceKey(value: unknown): value is ClickmapDeviceKey {\n return value === 'all' || value === 'mobile' || value === 'tablet' || value === 'laptop' || value === 'desktop' || value === 'widescreen' || value === 'tv';\n}\nconst CLICKMAP_DOM_INDEX_DEBOUNCE_MS = 250;\n\ntype ServerClickmapSelector = {\n selector: string;\n clicks: number;\n};\n\ntype ServerClickmapElement = {\n elementsChain: string;\n elementsText: string;\n tagName: string;\n href: string | null;\n clicks: number;\n deadClicks: number;\n};\n\ntype ServerClickmap = {\n path: string;\n // True aggregate click total returned for the active filter (summed across\n // every matching route), independent of how many elements can be drawn on the\n // current page's DOM. The overlay can only render elements that exist on the\n // page you're viewing, but this count reflects the full pattern.\n totalClicks: number;\n selectors: ServerClickmapSelector[];\n elements: ServerClickmapElement[];\n};\n\nfunction cssEscapeAttrValue(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\nfunction readChainAttr(segment: ElementsChainSegment, attr: string): string {\n if (!Object.prototype.hasOwnProperty.call(segment.attrs, attr)) return '';\n const value = segment.attrs[attr];\n return typeof value === 'string' ? value : '';\n}\n\n// Compact, human-readable counts for tight UI surfaces (markers, chips,\n// stats): 999 → \"999\", 1234 → \"1.2k\", 1_250_000 → \"1.3m\", 2e9 → \"2b\". One\n// decimal place (trailing .0 drops out of the arithmetic), and rounding\n// cascades into the next unit so 999_950+ reads \"1m\" rather than \"1000k\".\nfunction formatClickmapCount(value: number): string {\n let scaled = value;\n let suffix = '';\n for (const nextSuffix of ['k', 'm', 'b']) {\n // 999.95 is the smallest value that would display as \"1000\" at one\n // decimal place, so it already belongs to the next unit up.\n if (scaled < 999.95) break;\n scaled /= 1000;\n suffix = nextSuffix;\n }\n if (suffix === '') return String(Math.round(scaled));\n return `${Math.round(scaled * 10) / 10}${suffix}`;\n}\n\nfunction getClickmapHue(count: number, maxCount: number): number {\n if (maxCount <= 1) return 185;\n const intensity = Math.min(1, count / maxCount);\n return 185 - Math.round(intensity * 155);\n}\n\n\nfunction getReadableElementLabel(element: Element): string {\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel != null && ariaLabel.trim() !== '') {\n return ariaLabel.trim().slice(0, 80);\n }\n const title = element.getAttribute('title');\n if (title != null && title.trim() !== '') {\n return title.trim().slice(0, 80);\n }\n const text = element.textContent.trim().replace(/\\s+/g, ' ');\n if (text !== '') {\n return text.slice(0, 80);\n }\n return element.tagName.toLowerCase();\n}\n\nfunction isElementVisibleForClickmap(element: Element): boolean {\n // Never treat our own UI (or the dev tool's, if it happens to be mounted\n // alongside) as a clickmap candidate.\n if (element.closest(`#${cssEscapeIdent(CLICKMAP_ROOT_ID)}, #${cssEscapeIdent(DEV_TOOL_ROOT_ID)}`) != null) {\n return false;\n }\n if (element.closest('[hidden], [aria-hidden=\"true\"], [inert]') != null) {\n return false;\n }\n const rect = element.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) {\n return false;\n }\n const style = window.getComputedStyle(element);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {\n return false;\n }\n return true;\n}\n\nfunction getElementFromSelector(selector: string): Element | null {\n try {\n const elements = Array.from(document.querySelectorAll(selector));\n return elements.find(isElementVisibleForClickmap) ?? null;\n } catch {\n return null;\n }\n}\n\nfunction getSessionStorageString(key: string): string | null {\n try {\n const value = sessionStorage.getItem(key);\n return value == null || value.trim() === '' ? null : value;\n } catch {\n return null;\n }\n}\n\nfunction removeSessionStorageItem(key: string): void {\n try {\n sessionStorage.removeItem(key);\n } catch {\n // Storage can be blocked in private or embedded contexts; the toolbar keeps\n // rendering the actionable error state in that case.\n }\n}\n\n// Read a string claim out of a JWT payload without verifying the signature. The\n// clickmap token is self-describing — it carries the `project_id` and `origin`\n// it was minted for — so the overlay derives both from the token itself instead\n// of needing them handed over alongside. The server still verifies the token on\n// every request; this is only used to scope/label the token client-side.\nfunction getJwtPayloadClaim(token: string, claim: string): string | null {\n const tokenParts = token.split('.');\n if (tokenParts.length < 2 || tokenParts[1] === '') {\n return null;\n }\n try {\n const payloadPart = tokenParts[1];\n const normalized = payloadPart.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=');\n const payload: unknown = JSON.parse(atob(padded));\n if (typeof payload !== 'object' || payload === null) {\n return null;\n }\n const value = Reflect.get(payload, claim);\n return typeof value === 'string' ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction getClickmapTokenFromStorage(): string | null {\n return getSessionStorageString(CLICKMAP_OVERLAY_TOKEN_STORAGE_KEY);\n}\n\nfunction getClickmapOriginFromStorage(): string | null {\n const token = getClickmapTokenFromStorage();\n return token == null ? null : getJwtPayloadClaim(token, 'origin');\n}\n\nfunction clearClickmapTokenStorage(): void {\n removeSessionStorageItem(CLICKMAP_OVERLAY_TOKEN_STORAGE_KEY);\n}\n\nfunction parseServerClickmapResponse(value: unknown, path: string): ServerClickmap {\n let parsed: AnalyticsClickmapResponse;\n try {\n // Validate against the canonical response contract instead of hand-walking\n // `unknown`. Anything that doesn't match is treated as \"no data\" so the\n // overlay stays alive rather than crashing on shape drift.\n parsed = AnalyticsClickmapResponseBodySchema.validateSync(value);\n } catch {\n return { path, totalClicks: 0, selectors: [], elements: [] };\n }\n return {\n path,\n // True aggregate across every matching route, independent of what the\n // current DOM can render.\n totalClicks: parsed.routes.reduce((sum, route) => sum + route.clicks, 0),\n selectors: parsed.selectors.map((selector) => ({ selector: selector.selector, clicks: selector.clicks })),\n elements: parsed.elements.map((element) => ({\n elementsChain: element.elements_chain,\n elementsText: element.elements_text,\n tagName: element.tag_name,\n href: element.href,\n clicks: element.clicks,\n deadClicks: element.dead_clicks,\n })),\n };\n}\n\n// Heuristic: does this path segment look like an opaque per-entity id (a UUID,\n// numeric id, Mongo ObjectId, ULID, etc.) rather than a human-readable slug?\n// Used to auto-wildcard slug routes so a single clickmap pattern aggregates\n// across every user/team instead of just the one currently in the URL.\nfunction isDynamicPathSegment(segment: string): boolean {\n if (segment === '') return false;\n let decoded = segment;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // keep the raw segment if it isn't valid percent-encoding\n }\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(decoded)) return true; // UUID\n if (/^[0-9a-f]{32}$/i.test(decoded)) return true; // UUID without dashes / md5\n if (/^[0-9a-f]{24}$/i.test(decoded)) return true; // Mongo ObjectId\n if (/^[0-9A-HJKMNP-TV-Z]{26}$/i.test(decoded)) return true; // ULID\n if (/^\\d+$/.test(decoded)) return true; // numeric id\n return false;\n}\n\n// Turn the current pathname into a clickmap URL pattern by replacing id-like\n// segments with `*` (PostHog-style wildcards). Stable slugs are preserved so\n// e.g. `/teams/<uuid>/settings` becomes `/teams/*/settings`.\nfunction wildcardizePathname(pathname: string): string {\n const trailingSlash = pathname.length > 1 && pathname.endsWith('/');\n const segments = pathname.split('/').map((segment) => (isDynamicPathSegment(segment) ? '*' : segment));\n const joined = segments.join('/');\n return trailingSlash ? `${joined}/` : joined;\n}\n\n// Translate a PostHog-style glob (where `*` is the only wildcard) into an\n// anchored regex source mirroring the backend's SQL LIKE semantics.\nfunction globToRegexSource(glob: string): string {\n return glob\n .split('*')\n .map((part) => part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('.*');\n}\n\n// Does `path` match the active URL pattern? Used to tell the user when the page\n// they're on isn't covered by the pattern, so the overlay can't be drawn here\n// even though aggregate data exists. Glob matching mirrors the backend's\n// anchored `LIKE`.\nfunction patternMatchesPath(pattern: string, path: string): boolean {\n if (pattern === '') return true;\n try {\n return new RegExp(`^${globToRegexSource(pattern)}$`).test(path);\n } catch {\n return false;\n }\n}\n\nfunction createClickmapPanel(app: StackClientApp<true>, onClose: () => void): ClickmapPanelResult {\n const container = h('div', { className: 'sdt-hm' });\n const overlayHighlight = h('div', { className: 'sdt-hm-highlight' });\n const overlayRoot = h('div', { className: 'sdt-hm-overlay-root', 'aria-hidden': 'true' }, overlayHighlight);\n const statsCount = h('div', { className: 'sdt-hm-stat-value' }, '0');\n const selectorCount = h('div', { className: 'sdt-hm-stat-value' }, '0');\n const viewportValue = h('div', { className: 'sdt-hm-stat-value' }, `${window.innerWidth}x${window.innerHeight}`);\n const list = h('div', { className: 'sdt-hm-list' });\n const empty = h('div', { className: 'sdt-hm-empty' }, 'Paste a clickmap token from the dashboard to load aggregated element clicks for this page.');\n const status = h('div', { className: 'sdt-hm-token-status' });\n const viewportWarningTitle = h('div', { className: 'sdt-hm-viewport-warning-title' });\n const viewportWarningBody = h('div', { className: 'sdt-hm-viewport-warning-body' });\n const viewportWarningWidthValue = h('code', { className: 'sdt-hm-viewport-warning-code' });\n const viewportWarningHeightValue = h('code', { className: 'sdt-hm-viewport-warning-code' });\n const viewportWarningWidthCopy = h('button', { className: 'sdt-hm-copy-btn', type: 'button' });\n const viewportWarningHeightCopy = h('button', { className: 'sdt-hm-copy-btn', type: 'button' });\n const viewportWarning = h('div', { className: 'sdt-hm-viewport-warning', role: 'status' },\n viewportWarningTitle,\n viewportWarningBody,\n h('div', { className: 'sdt-hm-viewport-warning-actions' },\n h('span', { className: 'sdt-hm-viewport-warning-action' },\n h('span', { className: 'sdt-hm-viewport-warning-label' }, 'Width'),\n viewportWarningWidthValue,\n viewportWarningWidthCopy,\n ),\n h('span', { className: 'sdt-hm-viewport-warning-action' },\n h('span', { className: 'sdt-hm-viewport-warning-label' }, 'Height'),\n viewportWarningHeightValue,\n viewportWarningHeightCopy,\n ),\n ),\n );\n const overlayToggle = h('button', { className: 'sdt-hm-btn sdt-hm-btn-primary' }, 'Hide');\n const expandButton = h('button', { className: 'sdt-hm-icon-btn', 'aria-label': 'Expand clickmap options', 'data-sdt-tip': 'Expand clickmap options' });\n const closeButton = h('button', { className: 'sdt-hm-icon-btn', 'aria-label': 'Close clickmap', 'data-sdt-tip': 'Close clickmap' });\n const miniClicks = h('span', { className: 'sdt-hm-toolbar-metric-value' }, '0');\n const miniElements = h('span', { className: 'sdt-hm-toolbar-metric-value' }, '0');\n\n function readStoredFilters(): ClickmapFilters {\n try {\n const raw = sessionStorage.getItem(CLICKMAP_FILTERS_STORAGE_KEY);\n if (raw == null) return { ...CLICKMAP_DEFAULT_FILTERS };\n const parsed: unknown = JSON.parse(raw);\n if (parsed == null || typeof parsed !== 'object') return { ...CLICKMAP_DEFAULT_FILTERS };\n const obj = parsed as Record<string, unknown>;\n return {\n range: isClickmapRangeKey(obj.range) ? obj.range : CLICKMAP_DEFAULT_FILTERS.range,\n device: isClickmapDeviceKey(obj.device) ? obj.device : CLICKMAP_DEFAULT_FILTERS.device,\n urlPattern: typeof obj.urlPattern === 'string' ? obj.urlPattern : CLICKMAP_DEFAULT_FILTERS.urlPattern,\n elementSearch: typeof obj.elementSearch === 'string' ? obj.elementSearch : CLICKMAP_DEFAULT_FILTERS.elementSearch,\n showDead: typeof obj.showDead === 'boolean' ? obj.showDead : CLICKMAP_DEFAULT_FILTERS.showDead,\n };\n } catch {\n return { ...CLICKMAP_DEFAULT_FILTERS };\n }\n }\n function persistFilters(next: ClickmapFilters) {\n try {\n sessionStorage.setItem(CLICKMAP_FILTERS_STORAGE_KEY, JSON.stringify(next));\n } catch {\n // ignore storage errors\n }\n }\n\n let currentPath = window.location.pathname;\n let serverClickmap: ServerClickmap = { path: currentPath, totalClicks: 0, selectors: [], elements: [] };\n let loadingServerClickmap = false;\n let serverClickmapError: string | null = null;\n let serverClickmapRequestId = 0;\n let overlayVisible = true;\n let expanded = false;\n let renderFrame = 0;\n let overlayMode: 'hidden' | 'elements' = 'hidden';\n let highlightedGroupSelector: string | null = null;\n let highlightRenderedSelector: string | null = null;\n let highlightSettleTimer: number | null = null;\n // Hovering a count marker tints its outline. The marker button is the only\n // pointer-interactive part of the overlay (outlines are pointer-events:none\n // so the page stays usable), so it owns the hover.\n let hoveredGroupSelector: string | null = null;\n const mutedGroupSelectors = new Set<string>();\n // Datagrid-style row selection, keyed by the same selector ids as muting but\n // independent of it: it drives the page highlight and scopes the list\n // header's bulk show/hide actions. The anchor remembers the last plainly\n // clicked row so shift+click can extend a contiguous range in list order.\n const selectedGroupSelectors = new Set<string>();\n let selectionAnchorSelector: string | null = null;\n // Snapshot of the groups from the last render, in list order. Range\n // selection and the header's bulk actions operate on this.\n let latestGroups: ClickmapClickGroup[] = [];\n const groupOverlayElements = new Map<string, ClickmapGroupOverlayElement>();\n const listRowElements = new Map<string, ClickmapListRowElement>();\n\n function resetCopyButton(button: HTMLElement, label: string) {\n button.textContent = label;\n }\n\n function copyClickmapViewportValue(button: HTMLElement, value: string, label: string) {\n runAsynchronously(async () => {\n try {\n await navigator.clipboard.writeText(value);\n button.textContent = 'Copied';\n window.setTimeout(() => resetCopyButton(button, label), 1200);\n } catch {\n button.textContent = 'Copy failed';\n window.setTimeout(() => resetCopyButton(button, label), 1600);\n }\n });\n }\n\n // DOM-index cache for fast element-chain inference.\n const domIndex = new Map<string, Element[]>();\n let domIndexDirty = true;\n let domIndexDebounce = 0;\n function rebuildDomIndex() {\n domIndex.clear();\n trimTargetCache = new WeakMap();\n const all = document.querySelectorAll('*');\n for (const el of all) {\n if (!isElementVisibleForClickmap(el)) continue;\n const tag = el.tagName.toLowerCase();\n const bucket = domIndex.get(tag) ?? [];\n bucket.push(el);\n domIndex.set(tag, bucket);\n }\n domIndexDirty = false;\n }\n\n // Attribute clicks to the logical control, not the fragment the browser\n // reported (PostHog's trimElement). A click on a <span> or <svg> inside a\n // button records a span/svg-leaf chain, so the matched element walks up to\n // the nearest clickable ancestor: a real control (semantic selector) or the\n // element where cursor:pointer begins (computed pointer while the parent's\n // isn't — catches div-as-button components with zero hardcoded tags). No\n // hit within the cap returns the element unchanged. Resolution happens here\n // at render time, never at capture: stored chains stay raw, so these rules\n // can evolve and historical clicks regroup for free.\n const CLICKMAP_TRIM_TARGET_SELECTOR = 'a[href], button, input, select, textarea, summary, label, [role=\"button\"], [role=\"link\"], [role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"], [role=\"tab\"], [role=\"checkbox\"], [role=\"radio\"], [role=\"switch\"], [role=\"option\"], [contenteditable=\"true\"]';\n const CLICKMAP_TRIM_MAX_HOPS = 10;\n // getComputedStyle on every hop is too hot for the per-render group loop;\n // resolutions are cached per matched element and dropped together with the\n // dom index (same trigger: the page's DOM changed).\n let trimTargetCache = new WeakMap<Element, { target: Element, key: string }>();\n function resolveClickTarget(start: Element): { target: Element, key: string } {\n const cached = trimTargetCache.get(start);\n if (cached != null) return cached;\n let target = start;\n let current: Element | null = start;\n for (let hops = 0; current != null && current !== document.body && current !== document.documentElement && hops < CLICKMAP_TRIM_MAX_HOPS; hops++) {\n if (current.matches(CLICKMAP_TRIM_TARGET_SELECTOR)) {\n target = current;\n break;\n }\n const parent: Element | null = current.parentElement;\n if (window.getComputedStyle(current).cursor === 'pointer' && (parent == null || window.getComputedStyle(parent).cursor !== 'pointer')) {\n target = current;\n break;\n }\n current = parent;\n }\n const resolved = { target, key: buildElementsChain(target) };\n trimTargetCache.set(start, resolved);\n return resolved;\n }\n function ensureDomIndex() {\n if (domIndexDirty) rebuildDomIndex();\n }\n function invalidateDomIndex() {\n domIndexDirty = true;\n }\n function scheduleDomIndexInvalidation() {\n if (domIndexDebounce !== 0) {\n window.clearTimeout(domIndexDebounce);\n }\n domIndexDebounce = window.setTimeout(() => {\n domIndexDebounce = 0;\n invalidateDomIndex();\n scheduleRender();\n }, CLICKMAP_DOM_INDEX_DEBOUNCE_MS);\n }\n\n function isElementChainCandidateUnique(matches: Element[]): Element | null {\n const visible = matches.filter(isElementVisibleForClickmap);\n return visible.length === 1 ? visible[0] : null;\n }\n\n function queryUniqueBySelector(selector: string): Element | null {\n try {\n const all = Array.from(document.querySelectorAll(selector));\n return isElementChainCandidateUnique(all);\n } catch {\n return null;\n }\n }\n\n function elementMatchesSegment(element: Element, segment: ElementsChainSegment, useClasses: boolean): boolean {\n if (element.tagName.toLowerCase() !== segment.tag) return false;\n if (useClasses) {\n for (const cls of segment.classes) {\n if (!element.classList.contains(cls)) return false;\n }\n }\n return true;\n }\n\n function ancestorMatchesChain(leaf: Element, chain: ElementsChainSegment[], useClasses: boolean, useNthOfType: boolean, useNthChild: boolean): boolean {\n let cursor: Element | null = leaf;\n for (let i = 0; i < chain.length; i++) {\n if (cursor == null) return false;\n const segment = chain[i];\n if (!elementMatchesSegment(cursor, segment, useClasses)) return false;\n if (useNthOfType && segment.nthOfType != null) {\n if (computeNthOfType(cursor) !== segment.nthOfType) return false;\n }\n if (useNthChild && segment.nthChild != null) {\n if (computeNthChild(cursor) !== segment.nthChild) return false;\n }\n cursor = cursor.parentElement;\n }\n return true;\n }\n\n function computeNthOfType(el: Element): number {\n let n = 1;\n let sib = el.previousElementSibling;\n const tag = el.tagName;\n while (sib != null) {\n if (sib.tagName === tag) n += 1;\n sib = sib.previousElementSibling;\n }\n return n;\n }\n\n function computeNthChild(el: Element): number {\n let n = 1;\n let sib = el.previousElementSibling;\n while (sib != null) {\n n += 1;\n sib = sib.previousElementSibling;\n }\n return n;\n }\n\n function inferElementFromChain(chain: ElementsChainSegment[]): Element | null {\n if (chain.length === 0) return null;\n const leaf = chain[0];\n\n // 1. Stable attribute selectors on leaf (no tag).\n const stableAttrOrder: Array<{ attr: string, prefix?: string }> = [\n { attr: 'data-hexclave-id' },\n { attr: 'data-testid' },\n { attr: 'data-test-id' },\n { attr: 'name' },\n ];\n for (const { attr } of stableAttrOrder) {\n const value = readChainAttr(leaf, attr);\n if (value === '') continue;\n const sel = `[${attr}=\"${cssEscapeAttrValue(value)}\"]`;\n const match: Element | null = queryUniqueBySelector(sel);\n if (match) return match;\n }\n const id = readChainAttr(leaf, 'id');\n if (id !== '') {\n const match: Element | null = queryUniqueBySelector(`#${cssEscapeIdent(id)}`);\n if (match) return match;\n }\n if (leaf.href != null && leaf.href !== '' && leaf.tag === 'a') {\n const match: Element | null = queryUniqueBySelector(`a[href=\"${cssEscapeAttrValue(leaf.href)}\"]`);\n if (match) return match;\n }\n\n // 2. Tag + stable attribute on the leaf.\n const otherStableAttrs = ['aria-label', 'role', 'placeholder', 'title', 'type'];\n for (const attr of otherStableAttrs) {\n const value = readChainAttr(leaf, attr);\n if (value === '') continue;\n const sel = `${leaf.tag}[${attr}=\"${cssEscapeAttrValue(value)}\"]`;\n const match: Element | null = queryUniqueBySelector(sel);\n if (match) return match;\n }\n\n // 3, 4, 5: walk the DOM index by leaf tag, score the chain.\n ensureDomIndex();\n const candidates = domIndex.get(leaf.tag) ?? [];\n if (candidates.length === 0) return null;\n\n // Variant 3: tag.classes across the chain, no nth.\n const v3: Element[] = [];\n for (const candidate of candidates) {\n if (ancestorMatchesChain(candidate, chain, true, false, false)) v3.push(candidate);\n }\n const u3 = isElementChainCandidateUnique(v3);\n if (u3 != null) return u3;\n\n // Variant 4: tag.classes + nth-of-type.\n const v4: Element[] = [];\n for (const candidate of candidates) {\n if (ancestorMatchesChain(candidate, chain, true, true, false)) v4.push(candidate);\n }\n const u4 = isElementChainCandidateUnique(v4);\n if (u4 != null) return u4;\n\n // Variant 5: tag.classes + nth-child.\n const v5: Element[] = [];\n for (const candidate of candidates) {\n if (ancestorMatchesChain(candidate, chain, true, true, true)) v5.push(candidate);\n }\n const u5 = isElementChainCandidateUnique(v5);\n if (u5 != null) return u5;\n\n return null;\n }\n\n setHtml(closeButton, '<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>');\n const chevronUpSvg = '<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m18 15-6-6-6 6\"/></svg>';\n const chevronDownSvg = '<svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>';\n const clicksIconSvg = '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 4.1 12 6\"/><path d=\"m5.1 8-2.9-.8\"/><path d=\"m6 12-1.9 2\"/><path d=\"M7.2 2.2 8 5.1\"/><path d=\"M9.037 9.69a.498.498 0 0 1 .653-.653l11 4.5a.5.5 0 0 1-.074.949l-4.349 1.041a1 1 0 0 0-.74.739l-1.04 4.35a.5.5 0 0 1-.95.074z\"/></svg>';\n const elementsIconSvg = '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/><path d=\"M3 9h18\"/><path d=\"M9 21V9\"/></svg>';\n const eyeIconSvg = '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>';\n const eyeOffIconSvg = '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\"/><path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\"/><path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\"/><path d=\"m2 2 20 20\"/></svg>';\n // Only swap the chevron when the expanded state actually changes. render()\n // runs constantly (route poll, scroll, body mutations), and rewriting the\n // button's SVG on every pass detaches the element under the user's pointer\n // mid-press, which makes the browser drop the click entirely — the button\n // appeared to have dead spots wherever the icon sat.\n let renderedExpandIcon = '';\n function syncExpandIcon() {\n const icon = expanded ? chevronDownSvg : chevronUpSvg;\n if (renderedExpandIcon === icon) return;\n renderedExpandIcon = icon;\n setHtml(expandButton, icon);\n }\n syncExpandIcon();\n resetCopyButton(viewportWarningWidthCopy, 'Copy width');\n resetCopyButton(viewportWarningHeightCopy, 'Copy height');\n viewportWarningWidthCopy.addEventListener('click', () => {\n copyClickmapViewportValue(viewportWarningWidthCopy, viewportWarningWidthValue.textContent, 'Copy width');\n });\n viewportWarningHeightCopy.addEventListener('click', () => {\n copyClickmapViewportValue(viewportWarningHeightCopy, viewportWarningHeightValue.textContent, 'Copy height');\n });\n\n const stats = h('div', { className: 'sdt-hm-stats' },\n h('div', { className: 'sdt-hm-stat' }, h('div', { className: 'sdt-hm-stat-label' }, 'Clicks'), statsCount),\n h('div', { className: 'sdt-hm-stat' }, h('div', { className: 'sdt-hm-stat-label' }, 'Elements'), selectorCount),\n h('div', { className: 'sdt-hm-stat' }, h('div', { className: 'sdt-hm-stat-label' }, 'Viewport'), viewportValue),\n );\n\n let filters: ClickmapFilters = readStoredFilters();\n let filterReloadDebounce = 0;\n // When the user hasn't typed a custom pattern, the URL pattern field mirrors\n // the current route with id-like segments auto-wildcarded (`/teams/*/settings`)\n // so the clickmap aggregates across all entities. A stored non-empty pattern\n // means the user took manual control, so we leave it alone.\n let urlPatternUserEdited = filters.urlPattern.trim() !== '';\n\n function getEffectiveUrlPattern(): string {\n if (urlPatternUserEdited) return filters.urlPattern.trim();\n return wildcardizePathname(window.location.pathname);\n }\n // Reflect the current route into the field while in auto mode. No-op once the\n // user has typed their own pattern.\n function syncAutoUrlPattern() {\n if (urlPatternUserEdited) return;\n const auto = wildcardizePathname(window.location.pathname);\n if (urlPatternInput.value !== auto) {\n urlPatternInput.value = auto;\n }\n }\n\n function makeFilterSelect(options: Array<[string, string]>, value: string): HTMLSelectElement {\n const el = h('select', { className: 'sdt-hm-filter-input' }) as HTMLSelectElement;\n for (const [optValue, label] of options) {\n const opt = h('option', { value: optValue }, label) as HTMLOptionElement;\n el.appendChild(opt);\n }\n el.value = value;\n return el;\n }\n\n const rangeSelect = makeFilterSelect([\n ['24h', 'Last 24h'],\n ['7d', 'Last 7 days'],\n ['30d', 'Last 30 days'],\n ], filters.range);\n // Viewport filter as a segmented switcher: equal-weight options with a single\n // pill that slides to the active mode, instead of a hidden-until-opened native\n // <select>. The thumb is an absolutely-positioned element measured from the\n // active button so labels of different widths still track precisely.\n const deviceOptions: [ClickmapDeviceKey, string][] = [\n ['all', 'All'],\n ['mobile', 'Mobile'],\n ['tablet', 'Tablet'],\n ['laptop', 'Laptop'],\n ['desktop', 'Desktop'],\n ['widescreen', 'Wide'],\n ['tv', 'TV'],\n ];\n const deviceThumb = h('span', { className: 'sdt-hm-seg-thumb', 'aria-hidden': 'true' });\n const deviceSwitcher = h('div', {\n className: 'sdt-hm-seg',\n role: 'radiogroup',\n 'aria-label': 'Viewport',\n }, deviceThumb);\n const deviceButtons = new Map<ClickmapDeviceKey, HTMLButtonElement>();\n // Skip the animated slide the very first time the thumb is placed (panel open),\n // so it appears already parked on the active option rather than sweeping in.\n let deviceThumbPlaced = false;\n function positionDeviceThumb() {\n const active = deviceButtons.get(filters.device);\n // While the panel is collapsed the switcher isn't laid out (offsetWidth 0);\n // defer until it has real geometry so the thumb lands in the right place.\n if (active == null || active.offsetWidth === 0) return;\n if (!deviceThumbPlaced) {\n deviceThumb.style.transition = 'none';\n }\n deviceThumb.style.transform = `translateX(${active.offsetLeft}px)`;\n deviceThumb.style.width = `${active.offsetWidth}px`;\n if (!deviceThumbPlaced) {\n // Force a reflow so the no-transition placement commits before we hand\n // animation back, otherwise the first real move wouldn't tween.\n void deviceThumb.offsetWidth;\n deviceThumb.style.transition = '';\n deviceThumbPlaced = true;\n }\n }\n for (const [key, label] of deviceOptions) {\n const btn = h('button', {\n className: 'sdt-hm-seg-btn',\n type: 'button',\n role: 'radio',\n }, label) as HTMLButtonElement;\n btn.setAttribute('aria-checked', String(key === filters.device));\n btn.addEventListener('click', () => {\n if (filters.device === key) return;\n updateFilters({ device: key });\n for (const [k, b] of deviceButtons) {\n b.setAttribute('aria-checked', String(k === key));\n }\n positionDeviceThumb();\n });\n deviceButtons.set(key, btn);\n deviceSwitcher.appendChild(btn);\n }\n const urlPatternInput = h('input', {\n className: 'sdt-hm-filter-input',\n type: 'text',\n placeholder: '/products/*',\n spellcheck: 'false',\n autocomplete: 'off',\n autocapitalize: 'off',\n }) as HTMLInputElement;\n urlPatternInput.value = getEffectiveUrlPattern();\n // Reverts the field back to the auto-wildcarded current route. Shown whenever\n // the field holds a custom pattern (i.e. reverting would change something).\n const urlPatternReset = h('button', {\n className: 'sdt-hm-filter-reset',\n type: 'button',\n 'aria-label': 'Revert the URL pattern to the current page',\n 'data-sdt-tip': 'Revert to the current page',\n }) as HTMLButtonElement;\n setHtml(urlPatternReset, '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 14 4 9l5-5\"/><path d=\"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5v0a5.5 5.5 0 0 1-5.5 5.5H11\"/></svg>');\n\n // The revert button appears the moment the field diverges from the\n // auto-wildcarded current route. Toggled directly from the input handlers (on\n // top of render()) so it shows up immediately on edit, independent of the\n // panel's expanded state and of whether the pattern still covers this page.\n function syncUrlPatternResetVisibility() {\n const auto = wildcardizePathname(window.location.pathname);\n const showReset = urlPatternUserEdited && filters.urlPattern.trim() !== auto;\n urlPatternReset.classList.toggle('sdt-hm-filter-reset-visible', showReset);\n }\n\n // Info button + popover explaining the URL pattern syntax. The backend\n // translates `*` into a SQL LIKE `%`, so `*` is the only wildcard — every\n // other character is matched literally against the page's pathname.\n const urlPatternInfo = h('button', {\n className: 'sdt-hm-filter-info',\n type: 'button',\n 'aria-label': 'URL pattern help',\n 'aria-expanded': 'false',\n 'data-sdt-tip': 'How URL patterns work',\n }) as HTMLButtonElement;\n setHtml(urlPatternInfo, '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/></svg>');\n\n function makeUrlHelpRow(pattern: string, description: string): HTMLElement {\n return h('div', { className: 'sdt-hm-url-help-row' },\n h('code', { className: 'sdt-hm-url-help-code' }, pattern),\n h('span', { className: 'sdt-hm-url-help-desc' }, description),\n );\n }\n function makeCode(text: string): HTMLElement {\n return h('code', { className: 'sdt-hm-url-help-code' }, text);\n }\n const urlHelpTitle = h('div', { className: 'sdt-hm-url-help-title' });\n const urlHelpBody = h('div', { className: 'sdt-hm-url-help-body' });\n const urlHelpRows = h('div', { className: 'sdt-hm-url-help-rows' });\n function renderUrlHelp() {\n urlHelpTitle.textContent = 'URL pattern · glob';\n urlHelpBody.replaceChildren(\n 'Limits the clickmap to pages whose path matches. Matched against the pathname only — no domain, hash, or query string. ',\n makeCode('*'),\n ' is the only wildcard and stands in for any characters (including ',\n makeCode('/'),\n '). Everything else is matched literally.',\n );\n urlHelpRows.replaceChildren(\n makeUrlHelpRow('/pricing', 'That exact page'),\n makeUrlHelpRow('/products/*', 'Any path under /products/'),\n makeUrlHelpRow('/teams/*/members', 'A wildcard segment in the middle'),\n makeUrlHelpRow('*/settings', 'Any path ending in /settings'),\n makeUrlHelpRow('*', 'Every page'),\n makeUrlHelpRow('(empty)', 'Auto-tracks the page you are viewing'),\n );\n }\n const urlPatternHelp = h('div', { className: 'sdt-hm-url-help', role: 'dialog', 'aria-label': 'URL pattern help' },\n urlHelpTitle,\n urlHelpBody,\n urlHelpRows,\n );\n\n let urlHelpOpen = false;\n function setUrlHelpOpen(open: boolean) {\n urlHelpOpen = open;\n urlPatternHelp.classList.toggle('sdt-hm-url-help-open', open);\n urlPatternInfo.setAttribute('aria-expanded', String(open));\n }\n urlPatternInfo.addEventListener('click', (event) => {\n event.stopPropagation();\n setUrlHelpOpen(!urlHelpOpen);\n });\n urlPatternHelp.addEventListener('click', (event) => {\n event.stopPropagation();\n });\n renderUrlHelp();\n\n const elementSearchInput = h('input', {\n className: 'sdt-hm-filter-input',\n type: 'text',\n placeholder: 'Search element text or tag',\n 'aria-label': 'Search element text or tag',\n spellcheck: 'false',\n autocomplete: 'off',\n autocapitalize: 'off',\n }) as HTMLInputElement;\n elementSearchInput.value = filters.elementSearch;\n\n function wrapFilterField(label: string, input: HTMLElement, action?: HTMLElement): HTMLElement {\n const labelRow = h('span', { className: 'sdt-hm-filter-label-row' },\n h('span', { className: 'sdt-hm-filter-label' }, label),\n );\n if (action != null) {\n labelRow.appendChild(action);\n }\n return h('label', { className: 'sdt-hm-filter-field' },\n labelRow,\n input,\n );\n }\n\n // The range and URL-pattern controls live in the always-visible toolbar so\n // they're reachable whether or not the panel is expanded (the previous pill\n // only showed a static title + a single clicks badge and felt empty). The\n // remaining filters stay in the expanded body.\n const clicksIcon = h('span', { className: 'sdt-hm-toolbar-metric-icon' });\n const elementsIcon = h('span', { className: 'sdt-hm-toolbar-metric-icon' });\n setHtml(clicksIcon, clicksIconSvg);\n setHtml(elementsIcon, elementsIconSvg);\n\n // \"Show dead clicks\" toggle. Two synced controls — a compact icon toggle in\n // the always-visible toolbar and a labeled button in the expanded actions\n // row — flip the same filters.showDead flag. Off (default) the overlay\n // pretends dead clicks don't exist: counts are alive-only and all-dead\n // elements are hidden; on, totals include dead clicks and the per-element\n // \"% dead\" chips appear. Icons are written once at creation (see\n // syncExpandIcon for the dead-spot hazard of rewriting SVG on every\n // render); state sync only toggles classes/attrs.\n const showDeadIconSvg = '<svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 10h.01\"/><path d=\"M15 10h.01\"/><path d=\"M12 2a8 8 0 0 0-8 8v12l3-3 2.5 2.5L12 19l2.5 2.5L17 19l3 3V10a8 8 0 0 0-8-8z\"/></svg>';\n const showDeadMiniToggle = h('button', {\n className: 'sdt-hm-icon-btn sdt-hm-dead-toggle',\n type: 'button',\n 'aria-pressed': 'false',\n 'aria-label': 'Show dead clicks',\n 'data-sdt-tip': 'Show dead clicks',\n }) as HTMLButtonElement;\n setHtml(showDeadMiniToggle, showDeadIconSvg);\n const showDeadToggleIcon = h('span', { className: 'sdt-hm-dead-toggle-icon' });\n setHtml(showDeadToggleIcon, showDeadIconSvg);\n const showDeadToggle = h('button', {\n className: 'sdt-hm-btn sdt-hm-dead-toggle',\n type: 'button',\n 'aria-pressed': 'false',\n 'data-sdt-tip': 'Include clicks that had no effect',\n }, showDeadToggleIcon, 'Dead clicks') as HTMLButtonElement;\n\n function syncShowDeadToggles() {\n for (const button of [showDeadMiniToggle, showDeadToggle]) {\n button.setAttribute('aria-pressed', String(filters.showDead));\n button.classList.toggle('sdt-hm-dead-toggle-active', filters.showDead);\n }\n }\n function setShowDead(next: boolean) {\n if (filters.showDead === next) return;\n filters = { ...filters, showDead: next };\n persistFilters(filters);\n syncShowDeadToggles();\n scheduleRender();\n }\n showDeadMiniToggle.addEventListener('click', () => setShowDead(!filters.showDead));\n showDeadToggle.addEventListener('click', () => setShowDead(!filters.showDead));\n syncShowDeadToggles();\n\n // Overlay visibility toggle in the always-visible toolbar, twinned with the\n // expanded panel's labeled button (both flip overlayVisible). Eye = shown,\n // eye-off = hidden; the icon is only rewritten on state flips (see\n // syncExpandIcon for the dead-spot hazard of rewriting SVG every render).\n const overlayMiniToggle = h('button', {\n className: 'sdt-hm-icon-btn',\n type: 'button',\n 'aria-pressed': 'false',\n 'aria-label': 'Hide overlay',\n 'data-sdt-tip': 'Hide overlay',\n }) as HTMLButtonElement;\n let renderedOverlayMiniIcon = '';\n function syncOverlayMiniToggle() {\n overlayMiniToggle.setAttribute('aria-pressed', String(!overlayVisible));\n const label = overlayVisible ? 'Hide overlay' : 'Show overlay';\n overlayMiniToggle.setAttribute('aria-label', label);\n overlayMiniToggle.setAttribute('data-sdt-tip', label);\n overlayMiniToggle.classList.toggle('sdt-hm-overlay-mini-off', !overlayVisible);\n const icon = overlayVisible ? eyeIconSvg : eyeOffIconSvg;\n if (renderedOverlayMiniIcon !== icon) {\n renderedOverlayMiniIcon = icon;\n setHtml(overlayMiniToggle, icon);\n }\n }\n overlayMiniToggle.addEventListener('click', () => {\n overlayVisible = !overlayVisible;\n render();\n });\n syncOverlayMiniToggle();\n const toolbar = h('div', { className: 'sdt-hm-toolbar' },\n closeButton,\n h('div', { className: 'sdt-hm-toolbar-title' }, 'Clickmap'),\n h('div', { className: 'sdt-hm-toolbar-filters' },\n rangeSelect,\n h('div', { className: 'sdt-hm-toolbar-url' }, urlPatternInput, urlPatternReset, urlPatternInfo, urlPatternHelp),\n ),\n h('div', { className: 'sdt-hm-toolbar-metrics' },\n h('span', { className: 'sdt-hm-toolbar-metric', 'data-sdt-tip': 'Aggregate clicks' }, miniClicks, clicksIcon),\n h('span', { className: 'sdt-hm-toolbar-metric', 'data-sdt-tip': 'Mapped elements' }, miniElements, elementsIcon),\n ),\n showDeadMiniToggle,\n overlayMiniToggle,\n expandButton,\n );\n\n // The mismatch warning is anchored directly under the viewport switcher it\n // describes (not in the scrollable body, where it sat below the status line\n // and could scroll out of view while the filter that triggered it stayed\n // visible). It can't live inside the field's <label>: a label click\n // activates its first labelable descendant, so warning text clicks would\n // press the first segment button.\n const filterRow = h('div', { className: 'sdt-hm-filters' },\n wrapFilterField('Viewport', deviceSwitcher),\n viewportWarning,\n );\n\n function scheduleFilterReload() {\n if (filterReloadDebounce !== 0) {\n window.clearTimeout(filterReloadDebounce);\n }\n filterReloadDebounce = window.setTimeout(() => {\n filterReloadDebounce = 0;\n runAsynchronously(loadServerClickmap());\n }, 250);\n }\n\n function updateFilters(next: Partial<ClickmapFilters>) {\n filters = { ...filters, ...next };\n persistFilters(filters);\n scheduleFilterReload();\n }\n\n let elementSearchDebounce = 0;\n function updateElementSearch(value: string) {\n filters = { ...filters, elementSearch: value };\n persistFilters(filters);\n if (elementSearchDebounce !== 0) {\n window.clearTimeout(elementSearchDebounce);\n }\n elementSearchDebounce = window.setTimeout(() => {\n elementSearchDebounce = 0;\n scheduleRender();\n }, 120);\n }\n\n rangeSelect.addEventListener('change', () => {\n if (isClickmapRangeKey(rangeSelect.value)) updateFilters({ range: rangeSelect.value });\n });\n urlPatternInput.addEventListener('input', () => {\n const value = urlPatternInput.value;\n // Clearing the field hands control back to auto mode (reflect the route).\n urlPatternUserEdited = value.trim() !== '';\n updateFilters({ urlPattern: value });\n syncUrlPatternResetVisibility();\n });\n urlPatternReset.addEventListener('click', () => {\n // Hand control back to auto mode and reflect the current route immediately,\n // so the pattern covers the page the overlay is bound to.\n urlPatternUserEdited = false;\n urlPatternInput.value = wildcardizePathname(window.location.pathname);\n updateFilters({ urlPattern: '' });\n syncUrlPatternResetVisibility();\n });\n elementSearchInput.addEventListener('input', () => {\n updateElementSearch(elementSearchInput.value);\n });\n\n // Two regions: a fixed head (viewport filter + stats/actions) and a\n // scrolling body (status, list header, list). Element search lives in the\n // sticky list header next to the selection and bulk-visibility controls,\n // so every list control sits in one row directly above the rows it\n // operates on. Keeping borders to a single head/body divider avoids the\n // dense stack of bordered bands that made the expanded panel feel\n // congested.\n const actions = h('div', { className: 'sdt-hm-actions' }, stats, showDeadToggle, overlayToggle);\n const head = h('div', { className: 'sdt-hm-head' },\n filterRow,\n actions,\n );\n // Datagrid-style list header: master checkbox + selection summary on the\n // left, bulk visibility actions on the right. Sticky inside the scrolling\n // body so the bulk actions stay reachable while the list scrolls.\n const listHeaderCheck = h('button', {\n className: 'sdt-hm-row-check',\n type: 'button',\n role: 'checkbox',\n 'aria-checked': 'false',\n 'aria-label': 'Select all elements',\n }) as HTMLButtonElement;\n const listHeaderSummary = h('span', { className: 'sdt-hm-list-header-summary' });\n const listShowButton = h('button', { className: 'sdt-hm-btn sdt-hm-btn-sm', type: 'button' }, 'Show all') as HTMLButtonElement;\n const listHideButton = h('button', { className: 'sdt-hm-btn sdt-hm-btn-sm', type: 'button' }, 'Hide all') as HTMLButtonElement;\n const listHeader = h('div', { className: 'sdt-hm-list-header' },\n listHeaderCheck,\n listHeaderSummary,\n elementSearchInput,\n listShowButton,\n listHideButton,\n );\n listHeaderCheck.addEventListener('click', () => {\n const allSelected = latestGroups.length > 0 && latestGroups.every((group) => selectedGroupSelectors.has(group.selector));\n if (allSelected) {\n clearSelection();\n return;\n }\n selectedGroupSelectors.clear();\n for (const group of latestGroups) selectedGroupSelectors.add(group.selector);\n selectionAnchorSelector = null;\n scheduleRender();\n });\n listShowButton.addEventListener('click', () => {\n for (const group of getBulkActionGroups()) mutedGroupSelectors.delete(group.selector);\n scheduleRender();\n });\n listHideButton.addEventListener('click', () => {\n for (const group of getBulkActionGroups()) mutedGroupSelectors.add(group.selector);\n scheduleRender();\n });\n const body = h('div', { className: 'sdt-hm-body' }, status, listHeader, list);\n const details = h('div', { className: 'sdt-hm-details' }, head, body);\n\n function getGroups(): ClickmapClickGroup[] {\n const byKey = new Map<string, ClickmapClickGroup>();\n if (serverClickmap.path !== currentPath) {\n return [];\n }\n\n const searchQuery = filters.elementSearch.trim().toLowerCase();\n const matchesSearch = (entry: ServerClickmapElement): boolean => {\n if (searchQuery === '') return true;\n const haystacks = [entry.elementsText, entry.tagName, entry.href ?? '', entry.elementsChain];\n return haystacks.some((value) => value.toLowerCase().includes(searchQuery));\n };\n\n // Prefer the elements-chain inference path (PostHog-style).\n if (serverClickmap.elements.length > 0) {\n ensureDomIndex();\n for (const elementEntry of serverClickmap.elements) {\n if (!matchesSearch(elementEntry)) continue;\n const chain = parseElementsChain(elementEntry.elementsChain);\n let element = chain.length > 0 ? inferElementFromChain(chain) : null;\n if (element == null && elementEntry.href != null && elementEntry.href !== '' && elementEntry.tagName.toLowerCase() === 'a') {\n element = queryUniqueBySelector(`a[href=\"${cssEscapeAttrValue(elementEntry.href)}\"]`);\n }\n if (element == null) continue;\n // Group by the trimmed click target, not the raw chain: span-leaf and\n // button-leaf rows for the same control land in one group.\n const { target, key } = resolveClickTarget(element);\n const existing = byKey.get(key);\n if (existing != null) {\n existing.count += elementEntry.clicks;\n existing.deadCount += elementEntry.deadClicks;\n continue;\n }\n byKey.set(key, {\n selector: key,\n label: getReadableElementLabel(target),\n count: elementEntry.clicks,\n deadCount: elementEntry.deadClicks,\n element: target,\n rect: target.getBoundingClientRect(),\n });\n }\n }\n\n // Legacy selectors fallback (older backends or unresolved chains).\n if (byKey.size === 0) {\n for (const selectorClickmap of serverClickmap.selectors) {\n if (searchQuery !== '' && !selectorClickmap.selector.toLowerCase().includes(searchQuery)) continue;\n const element = getElementFromSelector(selectorClickmap.selector);\n if (element == null) continue;\n const { target, key } = resolveClickTarget(element);\n const existing = byKey.get(key);\n if (existing != null) {\n existing.count += selectorClickmap.clicks;\n continue;\n }\n byKey.set(key, {\n selector: key,\n label: getReadableElementLabel(target),\n count: selectorClickmap.clicks,\n // Legacy selector rows have no dead-click aggregation.\n deadCount: 0,\n element: target,\n rect: target.getBoundingClientRect(),\n });\n }\n }\n\n let groups = Array.from(byKey.values());\n if (!filters.showDead) {\n // Dead clicks are hidden by default: an element whose clicks were all\n // dead has nothing left to display.\n groups = groups.filter((group) => getGroupDisplayCount(group) > 0);\n }\n return groups.sort((a, b) => getGroupDisplayCount(b) - getGroupDisplayCount(a) || stringCompare(a.selector, b.selector));\n }\n\n // Displayed numbers follow the toggle: alive clicks only by default, full\n // totals (alive + dead) when dead clicks are shown. The clamp guards\n // against sampling-scaled dead counts rounding above the scaled total.\n function getGroupDisplayCount(group: ClickmapClickGroup): number {\n return filters.showDead ? group.count : Math.max(0, group.count - group.deadCount);\n }\n\n function getDeadClickPercentage(group: ClickmapClickGroup): number {\n if (group.count <= 0) return 100;\n return Math.min(100, Math.round((group.deadCount / group.count) * 100));\n }\n\n function scheduleRender() {\n cancelAnimationFrame(renderFrame);\n renderFrame = requestAnimationFrame(render);\n }\n\n function clearClickmapOverlayElements() {\n groupOverlayElements.clear();\n overlayRoot.replaceChildren(overlayHighlight);\n overlayHighlight.classList.remove('sdt-hm-highlight-visible', 'sdt-hm-highlight-animating');\n highlightRenderedSelector = null;\n }\n\n function clearClickmapListElements() {\n listRowElements.clear();\n list.replaceChildren();\n }\n\n function getClickmapViewportSize(): { width: number, height: number } {\n const visualViewport = window.visualViewport;\n if (visualViewport != null) {\n return { width: visualViewport.width, height: visualViewport.height };\n }\n return { width: window.innerWidth, height: window.innerHeight };\n }\n\n function shouldShowElements(): boolean {\n return overlayVisible;\n }\n\n function toggleMutedGroup(selector: string) {\n if (mutedGroupSelectors.has(selector)) {\n mutedGroupSelectors.delete(selector);\n } else {\n mutedGroupSelectors.add(selector);\n }\n scheduleRender();\n }\n\n function clearSelection() {\n if (selectedGroupSelectors.size === 0 && highlightedGroupSelector == null) return;\n selectedGroupSelectors.clear();\n selectionAnchorSelector = null;\n highlightedGroupSelector = null;\n scheduleRender();\n }\n\n function toggleSelectedGroup(selector: string) {\n if (selectedGroupSelectors.has(selector)) {\n selectedGroupSelectors.delete(selector);\n if (highlightedGroupSelector === selector) highlightedGroupSelector = null;\n } else {\n selectedGroupSelectors.add(selector);\n highlightedGroupSelector = selector;\n }\n selectionAnchorSelector = selector;\n scheduleRender();\n }\n\n // Datagrid click semantics on list rows: plain click selects just that row\n // (clicking the only selected row clears the selection again), ctrl/cmd\n // toggles membership, shift extends a contiguous range from the anchor in\n // list order. The most recently clicked row becomes the highlighted lead,\n // which drives the page's glide-highlight box.\n function selectGroupFromEvent(group: ClickmapClickGroup, event: { shiftKey: boolean, ctrlKey: boolean, metaKey: boolean }) {\n const toggle = event.ctrlKey || event.metaKey;\n if (event.shiftKey && selectionAnchorSelector != null) {\n const order = latestGroups.map((candidate) => candidate.selector);\n const anchorIndex = order.indexOf(selectionAnchorSelector);\n const targetIndex = order.indexOf(group.selector);\n if (anchorIndex !== -1 && targetIndex !== -1) {\n if (!toggle) selectedGroupSelectors.clear();\n const [start, end] = anchorIndex <= targetIndex ? [anchorIndex, targetIndex] : [targetIndex, anchorIndex];\n for (const selector of order.slice(start, end + 1)) {\n selectedGroupSelectors.add(selector);\n }\n highlightedGroupSelector = group.selector;\n scheduleRender();\n return;\n }\n }\n if (toggle) {\n toggleSelectedGroup(group.selector);\n return;\n }\n selectionAnchorSelector = group.selector;\n if (selectedGroupSelectors.size === 1 && selectedGroupSelectors.has(group.selector)) {\n selectedGroupSelectors.delete(group.selector);\n highlightedGroupSelector = null;\n } else {\n selectedGroupSelectors.clear();\n selectedGroupSelectors.add(group.selector);\n highlightedGroupSelector = group.selector;\n }\n scheduleRender();\n }\n\n // Targets for the header's bulk show/hide: the selection when there is one,\n // otherwise every listed element.\n function getBulkActionGroups(): ClickmapClickGroup[] {\n if (selectedGroupSelectors.size > 0) {\n return latestGroups.filter((group) => selectedGroupSelectors.has(group.selector));\n }\n return latestGroups;\n }\n\n function setHoveredGroup(selector: string | null) {\n if (hoveredGroupSelector === selector) return;\n hoveredGroupSelector = selector;\n scheduleRender();\n }\n\n const checkIconSvg = '<svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>';\n const dashIconSvg = '<svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/></svg>';\n\n function createListRowElement(selector: string): ClickmapListRowElement {\n const count = h('span', { className: 'sdt-hm-row-count' });\n const label = h('span', { className: 'sdt-hm-row-label' });\n const dead = h('span', { className: 'sdt-hm-row-dead' });\n const selectorText = h('span', { className: 'sdt-hm-row-selector' });\n const check = h('button', { className: 'sdt-hm-row-check', type: 'button', role: 'checkbox', 'aria-checked': 'false' }) as HTMLButtonElement;\n const eye = h('button', { className: 'sdt-hm-row-eye', type: 'button' }) as HTMLButtonElement;\n const row = h('div', {\n className: 'sdt-hm-row',\n role: 'button',\n tabindex: '0',\n },\n check,\n count,\n h('span', { className: 'sdt-hm-row-meta' },\n h('span', { className: 'sdt-hm-row-label-row' }, label, dead),\n selectorText,\n ),\n eye,\n );\n const rowElement: ClickmapListRowElement = { row, count, check, eye, label, dead, selector: selectorText, group: null, renderedEyeIcon: '', renderedCheckIcon: '' };\n check.addEventListener('click', (event) => {\n event.preventDefault();\n event.stopPropagation();\n if (rowElement.group == null) return;\n // The checkbox always toggles membership (no modifier needed), like a\n // datagrid checkbox column; shift still extends an additive range.\n if (event.shiftKey && selectionAnchorSelector != null) {\n selectGroupFromEvent(rowElement.group, { shiftKey: true, ctrlKey: true, metaKey: false });\n return;\n }\n toggleSelectedGroup(rowElement.group.selector);\n });\n eye.addEventListener('click', (event) => {\n event.preventDefault();\n event.stopPropagation();\n toggleMutedGroup(selector);\n });\n row.addEventListener('click', (event) => {\n if (rowElement.group == null) return;\n selectGroupFromEvent(rowElement.group, event);\n });\n row.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n if (rowElement.group == null) return;\n selectGroupFromEvent(rowElement.group, event);\n });\n return rowElement;\n }\n\n function updateListRowElement(rowElement: ClickmapListRowElement, group: ClickmapClickGroup) {\n const muted = mutedGroupSelectors.has(group.selector);\n const highlighted = highlightedGroupSelector === group.selector;\n const selected = selectedGroupSelectors.has(group.selector);\n rowElement.group = group;\n rowElement.row.classList.toggle('sdt-hm-row-muted', muted);\n rowElement.row.classList.toggle('sdt-hm-row-highlighted', highlighted);\n rowElement.row.classList.toggle('sdt-hm-row-selected', selected);\n rowElement.check.setAttribute('aria-checked', String(selected));\n rowElement.check.setAttribute('aria-label', selected ? `Deselect ${group.label}` : `Select ${group.label}`);\n // Same dead-spot hazard as syncExpandIcon: only rewrite the SVG when the\n // selected state actually flips.\n const checkIcon = selected ? checkIconSvg : '';\n if (rowElement.renderedCheckIcon !== checkIcon) {\n rowElement.renderedCheckIcon = checkIcon;\n setHtml(rowElement.check, checkIcon);\n }\n rowElement.count.textContent = formatClickmapCount(getGroupDisplayCount(group));\n rowElement.eye.setAttribute('aria-pressed', String(muted));\n rowElement.eye.setAttribute('aria-label', muted ? `Unmute ${group.label}` : `Mute ${group.label}`);\n rowElement.eye.title = muted ? 'Unmute element' : 'Mute element';\n // Same dead-spot hazard as syncExpandIcon: only rewrite the SVG when the\n // muted state actually flips, or clicks land on a detached icon.\n const eyeIcon = muted ? eyeOffIconSvg : eyeIconSvg;\n if (rowElement.renderedEyeIcon !== eyeIcon) {\n rowElement.renderedEyeIcon = eyeIcon;\n setHtml(rowElement.eye, eyeIcon);\n }\n rowElement.label.textContent = group.label;\n if (filters.showDead && group.deadCount > 0) {\n const deadPct = getDeadClickPercentage(group);\n rowElement.dead.textContent = `${deadPct}% dead`;\n rowElement.dead.title = `${formatClickmapCount(group.deadCount)} of ${formatClickmapCount(group.count)} clicks had no visible effect`;\n rowElement.dead.classList.add('sdt-hm-row-dead-visible');\n } else {\n rowElement.dead.textContent = '';\n rowElement.dead.title = '';\n rowElement.dead.classList.remove('sdt-hm-row-dead-visible');\n }\n rowElement.selector.textContent = group.selector;\n }\n\n function renderOverlay(groups: ClickmapClickGroup[]) {\n const nextMode = shouldShowElements() ? 'elements' : 'hidden';\n if (overlayMode !== nextMode) {\n overlayMode = nextMode;\n clearClickmapOverlayElements();\n }\n if (!shouldShowElements()) {\n return;\n }\n\n const visibleGroupKeys = new Set<string>();\n const maxCount = Math.max(1, ...groups.map(getGroupDisplayCount));\n for (const group of groups) {\n if (group.rect == null || group.rect.width <= 0 || group.rect.height <= 0) {\n continue;\n }\n visibleGroupKeys.add(group.selector);\n const displayCount = getGroupDisplayCount(group);\n const hue = getClickmapHue(displayCount, maxCount);\n const muted = mutedGroupSelectors.has(group.selector);\n // Every selected row reads as highlighted on the page, so a multi-row\n // selection lights up all of its outlines at once; the glide box still\n // follows only the lead (highlightedGroupSelector).\n const highlighted = highlightedGroupSelector === group.selector || selectedGroupSelectors.has(group.selector);\n let overlayElement = groupOverlayElements.get(group.selector);\n if (overlayElement == null) {\n const marker = h('button', { className: 'sdt-hm-marker', type: 'button', tabindex: '-1' });\n marker.addEventListener('click', (event) => {\n event.preventDefault();\n event.stopPropagation();\n toggleMutedGroup(group.selector);\n });\n marker.addEventListener('pointerenter', () => setHoveredGroup(group.selector));\n marker.addEventListener('pointerleave', () => {\n if (hoveredGroupSelector === group.selector) setHoveredGroup(null);\n });\n overlayElement = {\n marker,\n outline: h('div', { className: 'sdt-hm-outline' }),\n };\n groupOverlayElements.set(group.selector, overlayElement);\n overlayRoot.append(overlayElement.outline, overlayElement.marker);\n }\n const { marker, outline } = overlayElement;\n const deadSuffix = filters.showDead && group.deadCount > 0 && group.count > 0\n ? ` (${getDeadClickPercentage(group)}% dead)`\n : '';\n marker.title = muted ? `Unmute ${group.selector}` : `Mute ${displayCount} clicks${deadSuffix} on ${group.selector}`;\n marker.setAttribute('aria-label', marker.title);\n marker.style.left = `${Math.round(group.rect.left + group.rect.width / 2)}px`;\n marker.style.top = `${Math.round(group.rect.top + group.rect.height / 2)}px`;\n marker.style.background = `hsla(${hue}, 96%, 58%, 0.94)`;\n marker.style.boxShadow = `0 0 0 1px hsla(${hue}, 96%, 22%, 0.35), 0 8px 24px hsla(${hue}, 96%, 45%, 0.32)`;\n marker.textContent = formatClickmapCount(displayCount);\n marker.classList.toggle('sdt-hm-marker-muted', muted);\n marker.classList.toggle('sdt-hm-marker-highlighted', highlighted);\n\n outline.style.left = `${group.rect.left}px`;\n outline.style.top = `${group.rect.top}px`;\n outline.style.width = `${group.rect.width}px`;\n outline.style.height = `${group.rect.height}px`;\n outline.style.borderColor = `hsla(${hue}, 96%, 58%, 0.5)`;\n // Hover fills the box with a faint wash of its own border color; the\n // empty string falls back to the stylesheet's neutral background.\n outline.style.background = hoveredGroupSelector === group.selector ? `hsla(${hue}, 96%, 58%, 0.16)` : '';\n outline.classList.toggle('sdt-hm-outline-muted', muted);\n outline.classList.toggle('sdt-hm-outline-highlighted', highlighted);\n }\n for (const [key, overlayElement] of groupOverlayElements) {\n if (!visibleGroupKeys.has(key)) {\n overlayElement.marker.remove();\n overlayElement.outline.remove();\n groupOverlayElements.delete(key);\n }\n }\n renderHighlightBox(groups);\n }\n\n function renderHighlightBox(groups: ClickmapClickGroup[]) {\n const group = highlightedGroupSelector == null\n ? null\n : groups.find((candidate) => candidate.selector === highlightedGroupSelector) ?? null;\n const rect = group?.rect ?? null;\n if (group == null || rect == null || rect.width <= 0 || rect.height <= 0) {\n if (highlightSettleTimer != null) {\n window.clearTimeout(highlightSettleTimer);\n highlightSettleTimer = null;\n }\n overlayHighlight.classList.remove('sdt-hm-highlight-visible', 'sdt-hm-highlight-animating');\n highlightRenderedSelector = null;\n return;\n }\n const wasVisible = overlayHighlight.classList.contains('sdt-hm-highlight-visible');\n if (wasVisible && highlightRenderedSelector !== group.selector) {\n // Geometry transitions stay on briefly after retargeting so the box can\n // glide between visible elements, then come off so manual scrolling\n // tracks the element exactly instead of lagging behind.\n overlayHighlight.classList.add('sdt-hm-highlight-animating');\n if (highlightSettleTimer != null) window.clearTimeout(highlightSettleTimer);\n highlightSettleTimer = window.setTimeout(() => {\n overlayHighlight.classList.remove('sdt-hm-highlight-animating');\n highlightSettleTimer = null;\n }, 700);\n }\n highlightRenderedSelector = group.selector;\n overlayHighlight.style.left = `${rect.left}px`;\n overlayHighlight.style.top = `${rect.top}px`;\n overlayHighlight.style.width = `${rect.width}px`;\n overlayHighlight.style.height = `${rect.height}px`;\n overlayHighlight.classList.add('sdt-hm-highlight-visible');\n }\n\n function renderList(groups: ClickmapClickGroup[]) {\n if (groups.length === 0) {\n clearClickmapListElements();\n list.appendChild(empty);\n return;\n }\n const previousScrollTop = body.scrollTop;\n empty.remove();\n const renderedKeys = new Set<string>();\n let nextRowNode: ChildNode | null = list.firstChild;\n for (const group of groups.slice(0, 30)) {\n renderedKeys.add(group.selector);\n let rowElement = listRowElements.get(group.selector);\n if (rowElement == null) {\n rowElement = createListRowElement(group.selector);\n listRowElements.set(group.selector, rowElement);\n }\n updateListRowElement(rowElement, group);\n if (rowElement.row !== nextRowNode) {\n list.insertBefore(rowElement.row, nextRowNode);\n }\n nextRowNode = rowElement.row.nextSibling;\n }\n for (const [selector, rowElement] of listRowElements) {\n if (renderedKeys.has(selector)) continue;\n rowElement.row.remove();\n listRowElements.delete(selector);\n }\n body.scrollTop = previousScrollTop;\n }\n\n // Same dead-spot hazard as syncExpandIcon: only rewrite the master\n // checkbox's SVG when its tri-state actually changes.\n let renderedHeaderCheckIcon = '';\n function syncListHeader(groups: ClickmapClickGroup[]) {\n // The header stays visible while a search is filtering everything out —\n // the search box lives here, so hiding it would leave no way to clear\n // the query. It only disappears in the true empty state (no data).\n const visible = groups.length > 0 || filters.elementSearch.trim() !== '';\n listHeader.classList.toggle('sdt-hm-list-header-visible', visible);\n if (!visible) return;\n const selectedCount = selectedGroupSelectors.size;\n const allSelected = selectedCount > 0 && groups.every((group) => selectedGroupSelectors.has(group.selector));\n listHeaderCheck.setAttribute('aria-checked', allSelected ? 'true' : selectedCount > 0 ? 'mixed' : 'false');\n listHeaderCheck.setAttribute('aria-label', allSelected ? 'Clear selection' : 'Select all elements');\n const headerCheckIcon = allSelected ? checkIconSvg : selectedCount > 0 ? dashIconSvg : '';\n if (renderedHeaderCheckIcon !== headerCheckIcon) {\n renderedHeaderCheckIcon = headerCheckIcon;\n setHtml(listHeaderCheck, headerCheckIcon);\n }\n listHeaderSummary.textContent = selectedCount > 0\n ? `${formatClickmapCount(selectedCount)} of ${formatClickmapCount(groups.length)} selected`\n : `${formatClickmapCount(groups.length)} element${groups.length === 1 ? '' : 's'}`;\n const bulkTargets = getBulkActionGroups();\n const bulkScope = selectedCount > 0 ? 'selected' : 'all';\n listShowButton.textContent = `Show ${bulkScope}`;\n listHideButton.textContent = `Hide ${bulkScope}`;\n // Disabled whenever the action would be a no-op on its targets.\n listShowButton.disabled = bulkTargets.every((group) => !mutedGroupSelectors.has(group.selector));\n listHideButton.disabled = bulkTargets.every((group) => mutedGroupSelectors.has(group.selector));\n }\n\n function render() {\n if (currentPath !== window.location.pathname) {\n currentPath = window.location.pathname;\n serverClickmap = { path: currentPath, totalClicks: 0, selectors: [], elements: [] };\n serverClickmapError = null;\n clearClickmapListElements();\n syncAutoUrlPattern();\n runAsynchronously(loadServerClickmap());\n }\n const groups = getGroups();\n latestGroups = groups;\n const groupKeys = new Set(groups.map((group) => group.selector));\n for (const mutedGroupSelector of mutedGroupSelectors) {\n if (!groupKeys.has(mutedGroupSelector)) mutedGroupSelectors.delete(mutedGroupSelector);\n }\n for (const selectedGroupSelector of selectedGroupSelectors) {\n if (!groupKeys.has(selectedGroupSelector)) selectedGroupSelectors.delete(selectedGroupSelector);\n }\n if (selectionAnchorSelector != null && !groupKeys.has(selectionAnchorSelector)) {\n selectionAnchorSelector = null;\n }\n if (highlightedGroupSelector != null && !groupKeys.has(highlightedGroupSelector)) {\n highlightedGroupSelector = null;\n }\n if (hoveredGroupSelector != null && !groupKeys.has(hoveredGroupSelector)) {\n hoveredGroupSelector = null;\n }\n // Clicks mapped to an element that actually exists in the current DOM (what\n // the overlay can draw) vs. the true aggregate the filter matched server-side.\n // Follows the dead-clicks toggle so the message matches the drawn numbers.\n const mappedClicks = groups.reduce((sum, group) => sum + getGroupDisplayCount(group), 0);\n const aggregateClicks = serverClickmap.path === currentPath ? serverClickmap.totalClicks : 0;\n const viewport = getClickmapViewportSize();\n const roundedViewportWidth = Math.round(viewport.width);\n const roundedViewportHeight = Math.round(viewport.height);\n const selectedViewportBucket = getClickmapViewportBucket(filters.device);\n const viewportFilterMatches = selectedViewportBucket == null || isClickmapViewportWidthInBucket(roundedViewportWidth, selectedViewportBucket);\n statsCount.textContent = formatClickmapCount(aggregateClicks);\n selectorCount.textContent = formatClickmapCount(groups.length);\n viewportValue.textContent = `${roundedViewportWidth}x${roundedViewportHeight}`;\n overlayToggle.textContent = overlayVisible ? 'Hide overlay' : 'Show overlay';\n syncOverlayMiniToggle();\n viewportWarning.classList.toggle('sdt-hm-viewport-warning-visible', !viewportFilterMatches);\n if (selectedViewportBucket != null && !viewportFilterMatches) {\n const recommendedWidth = getClickmapRecommendedViewportWidth(selectedViewportBucket);\n const recommendedHeight = Math.max(1, roundedViewportHeight);\n viewportWarningTitle.textContent = 'Viewport filter mismatch';\n viewportWarningBody.textContent = `This page is ${roundedViewportWidth}px wide, but ${filters.device} is ${formatClickmapViewportBucket(selectedViewportBucket)}. Resize the window or use the DevTools device toolbar before comparing this clickmap.`;\n viewportWarningWidthValue.textContent = String(recommendedWidth);\n viewportWarningHeightValue.textContent = String(recommendedHeight);\n }\n const effectiveUrlPattern = getEffectiveUrlPattern();\n const urlPatternMatchesPath = patternMatchesPath(effectiveUrlPattern, currentPath);\n // Re-evaluated here too so route changes (which move the auto pattern under\n // a custom one) keep the revert affordance in sync.\n syncUrlPatternResetVisibility();\n const token = getClickmapTokenFromStorage();\n const tokenOrigin = getClickmapOriginFromStorage();\n if (token == null) {\n status.textContent = serverClickmapError ?? 'No clickmap token in sessionStorage. Paste one from the dashboard to load this page.';\n } else if (tokenOrigin != null && tokenOrigin !== window.location.origin) {\n status.textContent = `Token was minted for ${tokenOrigin}, but this page is ${window.location.origin}. Generate a token for this exact origin.`;\n } else if (loadingServerClickmap) {\n status.textContent = 'Loading aggregate clickmap...';\n } else if (serverClickmapError != null) {\n status.textContent = serverClickmapError;\n } else {\n const scope = effectiveUrlPattern !== '' && effectiveUrlPattern !== currentPath ? effectiveUrlPattern : currentPath;\n let message = `Loaded ${formatClickmapCount(aggregateClicks)} aggregate clicks for ${scope}.`;\n if (aggregateClicks === 0) {\n message = `No clicks recorded for ${scope} in this range.`;\n } else if (!urlPatternMatchesPath) {\n // The overlay is bound to the page you're viewing; off-pattern pages\n // can't render it. This is the \"* / shows 0 dots\" case made explicit.\n message += ' This page isn’t covered by the pattern — reset it or open a matching page to see the overlay.';\n } else if (groups.length === 0) {\n message += ' No matching elements found on this page yet.';\n } else if (mappedClicks < aggregateClicks) {\n message += ` ${formatClickmapCount(mappedClicks)} mapped to elements on this page.`;\n }\n status.textContent = message;\n }\n status.classList.toggle('sdt-hm-token-status-error', serverClickmapError != null || (token != null && tokenOrigin != null && tokenOrigin !== window.location.origin));\n miniClicks.textContent = formatClickmapCount(aggregateClicks);\n miniElements.textContent = formatClickmapCount(groups.length);\n container.classList.toggle('sdt-hm-expanded', expanded);\n expandButton.setAttribute('aria-expanded', String(expanded));\n expandButton.setAttribute('aria-label', expanded ? 'Collapse clickmap options' : 'Expand clickmap options');\n expandButton.setAttribute('data-sdt-tip', expanded ? 'Collapse clickmap options' : 'Expand clickmap options');\n syncExpandIcon();\n // Keep the viewport switcher's sliding thumb aligned once the panel is laid\n // out (expand, resize-driven re-render); it no-ops while collapsed.\n positionDeviceThumb();\n renderOverlay(groups);\n syncListHeader(groups);\n renderList(groups);\n }\n\n async function loadServerClickmap() {\n const requestId = serverClickmapRequestId + 1;\n serverClickmapRequestId = requestId;\n const isLatestRequest = () => requestId === serverClickmapRequestId;\n const token = getClickmapTokenFromStorage();\n if (token == null) {\n serverClickmap = { path: currentPath, totalClicks: 0, selectors: [], elements: [] };\n serverClickmapError = null;\n loadingServerClickmap = false;\n render();\n return;\n }\n const tokenOrigin = getClickmapOriginFromStorage();\n if (tokenOrigin != null && tokenOrigin !== window.location.origin) {\n serverClickmap = { path: currentPath, totalClicks: 0, selectors: [], elements: [] };\n serverClickmapError = null;\n loadingServerClickmap = false;\n render();\n return;\n }\n\n loadingServerClickmap = true;\n serverClickmapError = null;\n render();\n try {\n const until = new Date();\n const since = new Date(until.getTime() - CLICKMAP_RANGE_MS[filters.range]);\n const requestedPath = window.location.pathname;\n const effectiveUrlPattern = getEffectiveUrlPattern();\n const body: Record<string, unknown> = {\n clickmap_token: token,\n origin: window.location.origin,\n since: since.toISOString(),\n until: until.toISOString(),\n };\n if (effectiveUrlPattern !== '') {\n body.url_pattern = effectiveUrlPattern;\n } else {\n body.route_path = requestedPath;\n }\n if (filters.device !== 'all') {\n body.device = filters.device;\n }\n const response = await app[hexclaveAppInternalsSymbol].sendRequest(\"/analytics/clickmap\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n }, \"client\");\n if (!response.ok) {\n throw new Error(`Clickmap request failed with HTTP ${response.status}`);\n }\n const responseBody: unknown = await response.json();\n if (!isLatestRequest()) {\n return;\n }\n serverClickmap = parseServerClickmapResponse(responseBody, requestedPath);\n } catch (error) {\n if (!isLatestRequest()) {\n return;\n }\n serverClickmap = { path: currentPath, totalClicks: 0, selectors: [], elements: [] };\n if (error instanceof Error && error.message.includes('Clickmap token does not belong to this project')) {\n clearClickmapTokenStorage();\n serverClickmapError = 'The stored clickmap token belongs to another project. Generate a fresh token for this project.';\n } else {\n serverClickmapError = error instanceof Error ? error.message : 'Failed to load clickmap data';\n }\n } finally {\n if (isLatestRequest()) {\n loadingServerClickmap = false;\n render();\n }\n }\n }\n\n // The clickmap overlay leaves the page fully interactive. When the user\n // navigates away with a token loaded, drop a sentinel so the dev tool on the\n // next page can auto-reopen straight back into the clickmap tab.\n const onBeforeUnloadResume = () => {\n const token = getClickmapTokenFromStorage();\n const tokenOrigin = getClickmapOriginFromStorage();\n if (token == null || (tokenOrigin != null && tokenOrigin !== window.location.origin)) {\n return;\n }\n try {\n sessionStorage.setItem(CLICKMAP_OVERLAY_RESUME_STORAGE_KEY, '1');\n } catch {\n // ignore (private mode, etc.)\n }\n };\n\n // render() fires constantly while the overlay is open (route poll, scroll,\n // host-page mutations), so the toolbar can be rewritten or reflowed between\n // pointerdown and pointerup. If that churn replaces the node the press\n // started on, or shifts the button out from under the cursor, the browser\n // never synthesizes the click and the press is silently dropped. Capturing\n // the pointer pins the rest of the press — pointerup and the resulting\n // click included — to the button itself, so mid-press churn can't eat it.\n const pinPressToButton = (button: HTMLButtonElement) => {\n button.addEventListener('pointerdown', (event) => {\n try {\n button.setPointerCapture(event.pointerId);\n } catch {\n // The pointer may already be gone (e.g. pen lifted); a plain click\n // still works in that case.\n }\n });\n };\n pinPressToButton(overlayToggle);\n pinPressToButton(closeButton);\n pinPressToButton(expandButton);\n pinPressToButton(showDeadMiniToggle);\n pinPressToButton(showDeadToggle);\n pinPressToButton(overlayMiniToggle);\n pinPressToButton(listHeaderCheck);\n pinPressToButton(listShowButton);\n pinPressToButton(listHideButton);\n overlayToggle.addEventListener('click', () => {\n overlayVisible = !overlayVisible;\n render();\n });\n closeButton.addEventListener('click', onClose);\n expandButton.addEventListener('click', () => {\n expanded = !expanded;\n render();\n });\n const onTokenUpdated = () => {\n runAsynchronously(loadServerClickmap());\n };\n const routePollInterval = window.setInterval(scheduleRender, 500);\n // Mutations the overlay/dev-tool cause themselves must not drive a re-render:\n // `renderOverlay` rewrites marker/outline inline styles into `overlayRoot` on\n // every paint, so observing them would re-arm scheduleRender → paint → mutate\n // → … a permanent render loop while the tab is open. Ignore records whose\n // targets all sit inside our own overlay/panel roots or the dev tool's root.\n const isSelfMutationTarget = (target: Node | null): boolean => {\n const element = target instanceof Element ? target : target?.parentElement ?? null;\n if (element == null) return false;\n return overlayRoot.contains(element) || element.closest(`#${cssEscapeIdent(CLICKMAP_ROOT_ID)}, #${cssEscapeIdent(DEV_TOOL_ROOT_ID)}`) != null;\n };\n const mutationObserver = new MutationObserver((mutations) => {\n if (mutations.every((mutation) => isSelfMutationTarget(mutation.target))) {\n return;\n }\n scheduleDomIndexInvalidation();\n scheduleRender();\n });\n const visualViewport = window.visualViewport;\n mutationObserver.observe(document.body, { attributes: true, childList: true, subtree: true });\n\n // Mounted inside the clickmap root (not document.body) so everything that\n // ignores Hexclave UI by root id — most importantly the SDK's dead-click\n // MutationObserver — also ignores the overlay's constant marker/outline\n // rewrites instead of reading them as the page reacting to a click. The\n // overlay root is position:fixed, so the unstyled parent changes nothing\n // visually.\n (document.getElementById(CLICKMAP_ROOT_ID) ?? document.body).appendChild(overlayRoot);\n rebuildDomIndex();\n scheduleRender();\n window.addEventListener('beforeunload', onBeforeUnloadResume);\n const onWindowResize = () => {\n scheduleRender();\n };\n document.addEventListener('scroll', scheduleRender, true);\n window.addEventListener('resize', onWindowResize);\n visualViewport?.addEventListener('resize', scheduleRender);\n visualViewport?.addEventListener('scroll', scheduleRender);\n window.addEventListener(CLICKMAP_OVERLAY_TOKEN_UPDATED_EVENT, onTokenUpdated);\n // Dismiss the URL-pattern help popover on an outside click or Escape.\n const onDocumentPointerDown = (event: MouseEvent) => {\n if (!urlHelpOpen) return;\n if (event.target instanceof Node && urlPatternHelp.contains(event.target)) return;\n if (event.target instanceof Node && urlPatternInfo.contains(event.target)) return;\n setUrlHelpOpen(false);\n };\n const onDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n if (urlHelpOpen) {\n setUrlHelpOpen(false);\n return;\n }\n clearSelection();\n };\n document.addEventListener('mousedown', onDocumentPointerDown, true);\n document.addEventListener('keydown', onDocumentKeyDown, true);\n render();\n runAsynchronously(loadServerClickmap());\n\n container.append(details, toolbar);\n return {\n element: container,\n cleanup: () => {\n cancelAnimationFrame(renderFrame);\n if (domIndexDebounce !== 0) window.clearTimeout(domIndexDebounce);\n if (filterReloadDebounce !== 0) window.clearTimeout(filterReloadDebounce);\n if (elementSearchDebounce !== 0) window.clearTimeout(elementSearchDebounce);\n window.clearInterval(routePollInterval);\n mutationObserver.disconnect();\n clearClickmapOverlayElements();\n domIndex.clear();\n window.removeEventListener('beforeunload', onBeforeUnloadResume);\n document.removeEventListener('scroll', scheduleRender, true);\n window.removeEventListener('resize', onWindowResize);\n visualViewport?.removeEventListener('resize', scheduleRender);\n visualViewport?.removeEventListener('scroll', scheduleRender);\n window.removeEventListener(CLICKMAP_OVERLAY_TOKEN_UPDATED_EVENT, onTokenUpdated);\n document.removeEventListener('mousedown', onDocumentPointerDown, true);\n document.removeEventListener('keydown', onDocumentKeyDown, true);\n overlayRoot.remove();\n },\n };\n}\n\n// ===========================================================================================\n// Mount\n// ===========================================================================================\n\nconst GLOBAL_INSTANCE_KEY = '__hexclave-clickmap-instance';\n\n/**\n * Opens the clickmap overlay: mounts its own root element, injects its own\n * styles, and shows the bottom-centered panel.\n *\n * Returns a cleanup that tears everything down. `onClosed` fires exactly once,\n * when the overlay is closed (by the user or via the returned cleanup), so the\n * caller can let a later token event reopen it.\n */\nexport function openClickmapOverlay(app: StackClientApp<true>, onClosed: () => void): () => void {\n if (typeof document === 'undefined' || typeof document.createElement !== 'function') {\n return () => {};\n }\n const body = Reflect.get(document, 'body');\n if (!hasAppendChild(body)) return () => {};\n\n getGlobalUiInstance(GLOBAL_INSTANCE_KEY)?.cleanup();\n let existingRoot = document.getElementById(CLICKMAP_ROOT_ID);\n while (existingRoot !== null) {\n existingRoot.remove();\n existingRoot = document.getElementById(CLICKMAP_ROOT_ID);\n }\n\n const root = document.createElement('div');\n root.id = CLICKMAP_ROOT_ID;\n body.appendChild(root);\n\n const wrapper = h('div', { className: 'hexclave-clickmap' });\n root.appendChild(wrapper);\n\n const style = document.createElement('style');\n style.textContent = clickmapCSS;\n wrapper.appendChild(style);\n\n const panel = createClickmapPanel(app, () => instance.cleanup());\n wrapper.appendChild(\n h('div', { className: 'sdt-hm-panel' },\n h('div', { className: 'sdt-hm-panel-inner' }, panel.element),\n ),\n );\n\n let didCleanup = false;\n const instance: UiGlobalInstance = {\n cleanup: () => {\n if (didCleanup) return;\n didCleanup = true;\n if (getGlobalUiInstance(GLOBAL_INSTANCE_KEY) === instance) {\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, null);\n }\n panel.cleanup?.();\n if (root.parentNode) {\n root.parentNode.removeChild(root);\n }\n onClosed();\n },\n };\n setGlobalUiInstance(GLOBAL_INSTANCE_KEY, instance);\n\n return () => {\n instance.cleanup();\n };\n}\n\n"],"mappings":";;;;;;;;;;;;AA8DA,MAAM,+BAA+B;AAuBrC,MAAM,2BAA4C;CAChD,OAAO;CACP,QAAQ;CACR,YAAY;CACZ,eAAe;CACf,UAAU;CACX;AAED,MAAM,oBAAsD;CAC1D,OAAO,OAAU,KAAK;CACtB,MAAM,QAAc,KAAK;CACzB,OAAO,MAAU,KAAK,KAAK;CAC5B;AAED,MAAM,4BAA+F;CACnG,QAAQ;EAAE,KAAK;EAAG,KAAK;EAAK;CAC5B,QAAQ;EAAE,KAAK;EAAK,KAAK;EAAM;CAC/B,QAAQ;EAAE,KAAK;EAAM,KAAK;EAAM;CAChC,SAAS;EAAE,KAAK;EAAM,KAAK;EAAM;CACjC,YAAY;EAAE,KAAK;EAAM,KAAK;EAAM;CACpC,IAAI;EAAE,KAAK;EAAM,KAAK;EAAM;CAC7B;AAED,SAAS,0BAA0B,QAA0D;AAC3F,KAAI,WAAW,MAAO,QAAO;AAC7B,QAAO,0BAA0B;;AAGnC,SAAS,gCAAgC,OAAe,QAAyC;AAC/F,QAAO,SAAS,OAAO,QAAQ,OAAO,OAAO,QAAQ,SAAS,OAAO;;AAGvE,SAAS,oCAAoC,QAAwC;AACnF,KAAI,OAAO,OAAO,KAAM,QAAO,OAAO;AACtC,QAAO,KAAK,OAAO,OAAO,MAAM,OAAO,OAAO,EAAE;;AAGlD,SAAS,6BAA6B,QAAwC;AAC5E,KAAI,OAAO,OAAO,KAAM,QAAO,GAAG,OAAO,IAAI;AAC7C,QAAO,GAAG,OAAO,IAAI,GAAG,OAAO,IAAI;;AAGrC,SAAS,mBAAmB,OAA2C;AACrE,QAAO,UAAU,SAAS,UAAU,QAAQ,UAAU;;AAExD,SAAS,oBAAoB,OAA4C;AACvE,QAAO,UAAU,SAAS,UAAU,YAAY,UAAU,YAAY,UAAU,YAAY,UAAU,aAAa,UAAU,gBAAgB,UAAU;;AAEzJ,MAAM,iCAAiC;AA2BvC,SAAS,mBAAmB,OAAuB;AACjD,QAAO,MAAM,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,OAAM;;AAG1D,SAAS,cAAc,SAA+B,MAAsB;AAC1E,KAAI,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,OAAO,KAAK,CAAE,QAAO;CACvE,MAAM,QAAQ,QAAQ,MAAM;AAC5B,QAAO,OAAO,UAAU,WAAW,QAAQ;;AAO7C,SAAS,oBAAoB,OAAuB;CAClD,IAAI,SAAS;CACb,IAAI,SAAS;AACb,MAAK,MAAM,cAAc;EAAC;EAAK;EAAK;EAAI,EAAE;AAGxC,MAAI,SAAS,OAAQ;AACrB,YAAU;AACV,WAAS;;AAEX,KAAI,WAAW,GAAI,QAAO,OAAO,KAAK,MAAM,OAAO,CAAC;AACpD,QAAO,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG,KAAK;;AAG3C,SAAS,eAAe,OAAe,UAA0B;AAC/D,KAAI,YAAY,EAAG,QAAO;CAC1B,MAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,SAAS;AAC/C,QAAO,MAAM,KAAK,MAAM,YAAY,IAAI;;AAI1C,SAAS,wBAAwB,SAA0B;CACzD,MAAM,YAAY,QAAQ,aAAa,aAAa;AACpD,KAAI,aAAa,QAAQ,UAAU,MAAM,KAAK,GAC5C,QAAO,UAAU,MAAM,CAAC,MAAM,GAAG,GAAG;CAEtC,MAAM,QAAQ,QAAQ,aAAa,QAAQ;AAC3C,KAAI,SAAS,QAAQ,MAAM,MAAM,KAAK,GACpC,QAAO,MAAM,MAAM,CAAC,MAAM,GAAG,GAAG;CAElC,MAAM,OAAO,QAAQ,YAAY,MAAM,CAAC,QAAQ,QAAQ,IAAI;AAC5D,KAAI,SAAS,GACX,QAAO,KAAK,MAAM,GAAG,GAAG;AAE1B,QAAO,QAAQ,QAAQ,aAAa;;AAGtC,SAAS,4BAA4B,SAA2B;AAG9D,KAAI,QAAQ,QAAQ,IAAI,eAAe,iBAAiB,CAAC,KAAK,eAAe,iBAAiB,GAAG,IAAI,KACnG,QAAO;AAET,KAAI,QAAQ,QAAQ,4CAA0C,IAAI,KAChE,QAAO;CAET,MAAM,OAAO,QAAQ,uBAAuB;AAC5C,KAAI,KAAK,SAAS,KAAK,KAAK,UAAU,EACpC,QAAO;CAET,MAAM,QAAQ,OAAO,iBAAiB,QAAQ;AAC9C,KAAI,MAAM,YAAY,UAAU,MAAM,eAAe,YAAY,MAAM,YAAY,IACjF,QAAO;AAET,QAAO;;AAGT,SAAS,uBAAuB,UAAkC;AAChE,KAAI;AAEF,SADiB,MAAM,KAAK,SAAS,iBAAiB,SAAS,CAAC,CAChD,KAAK,4BAA4B,IAAI;SAC/C;AACN,SAAO;;;AAIX,SAAS,wBAAwB,KAA4B;AAC3D,KAAI;EACF,MAAM,QAAQ,eAAe,QAAQ,IAAI;AACzC,SAAO,SAAS,QAAQ,MAAM,MAAM,KAAK,KAAK,OAAO;SAC/C;AACN,SAAO;;;AAIX,SAAS,yBAAyB,KAAmB;AACnD,KAAI;AACF,iBAAe,WAAW,IAAI;SACxB;;AAWV,SAAS,mBAAmB,OAAe,OAA8B;CACvE,MAAM,aAAa,MAAM,MAAM,IAAI;AACnC,KAAI,WAAW,SAAS,KAAK,WAAW,OAAO,GAC7C,QAAO;AAET,KAAI;EAEF,MAAM,aADc,WAAW,GACA,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI;EACpE,MAAM,SAAS,WAAW,OAAO,KAAK,KAAK,WAAW,SAAS,EAAE,GAAG,GAAG,IAAI;EAC3E,MAAM,UAAmB,KAAK,MAAM,KAAK,OAAO,CAAC;AACjD,MAAI,OAAO,YAAY,YAAY,YAAY,KAC7C,QAAO;EAET,MAAM,QAAQ,QAAQ,IAAI,SAAS,MAAM;AACzC,SAAO,OAAO,UAAU,WAAW,QAAQ;SACrC;AACN,SAAO;;;AAIX,SAAS,8BAA6C;AACpD,QAAO,wBAAwB,mCAAmC;;AAGpE,SAAS,+BAA8C;CACrD,MAAM,QAAQ,6BAA6B;AAC3C,QAAO,SAAS,OAAO,OAAO,mBAAmB,OAAO,SAAS;;AAGnE,SAAS,4BAAkC;AACzC,0BAAyB,mCAAmC;;AAG9D,SAAS,4BAA4B,OAAgB,MAA8B;CACjF,IAAI;AACJ,KAAI;AAIF,WAAS,oCAAoC,aAAa,MAAM;SAC1D;AACN,SAAO;GAAE;GAAM,aAAa;GAAG,WAAW,EAAE;GAAE,UAAU,EAAE;GAAE;;AAE9D,QAAO;EACL;EAGA,aAAa,OAAO,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM,QAAQ,EAAE;EACxE,WAAW,OAAO,UAAU,KAAK,cAAc;GAAE,UAAU,SAAS;GAAU,QAAQ,SAAS;GAAQ,EAAE;EACzG,UAAU,OAAO,SAAS,KAAK,aAAa;GAC1C,eAAe,QAAQ;GACvB,cAAc,QAAQ;GACtB,SAAS,QAAQ;GACjB,MAAM,QAAQ;GACd,QAAQ,QAAQ;GAChB,YAAY,QAAQ;GACrB,EAAE;EACJ;;AAOH,SAAS,qBAAqB,SAA0B;AACtD,KAAI,YAAY,GAAI,QAAO;CAC3B,IAAI,UAAU;AACd,KAAI;AACF,YAAU,mBAAmB,QAAQ;SAC/B;AAGR,KAAI,kEAAkE,KAAK,QAAQ,CAAE,QAAO;AAC5F,KAAI,kBAAkB,KAAK,QAAQ,CAAE,QAAO;AAC5C,KAAI,kBAAkB,KAAK,QAAQ,CAAE,QAAO;AAC5C,KAAI,4BAA4B,KAAK,QAAQ,CAAE,QAAO;AACtD,KAAI,QAAQ,KAAK,QAAQ,CAAE,QAAO;AAClC,QAAO;;AAMT,SAAS,oBAAoB,UAA0B;CACrD,MAAM,gBAAgB,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI;CAEnE,MAAM,SADW,SAAS,MAAM,IAAI,CAAC,KAAK,YAAa,qBAAqB,QAAQ,GAAG,MAAM,QAAS,CAC9E,KAAK,IAAI;AACjC,QAAO,gBAAgB,GAAG,OAAO,KAAK;;AAKxC,SAAS,kBAAkB,MAAsB;AAC/C,QAAO,KACJ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,QAAQ,uBAAuB,OAAO,CAAC,CAC1D,KAAK,KAAK;;AAOf,SAAS,mBAAmB,SAAiB,MAAuB;AAClE,KAAI,YAAY,GAAI,QAAO;AAC3B,KAAI;AACF,SAAO,IAAI,OAAO,IAAI,kBAAkB,QAAQ,CAAC,GAAG,CAAC,KAAK,KAAK;SACzD;AACN,SAAO;;;AAIX,SAAS,oBAAoB,KAA2B,SAA0C;CAChG,MAAM,YAAY,EAAE,OAAO,EAAE,WAAW,UAAU,CAAC;CACnD,MAAM,mBAAmB,EAAE,OAAO,EAAE,WAAW,oBAAoB,CAAC;CACpE,MAAM,cAAc,EAAE,OAAO;EAAE,WAAW;EAAuB,eAAe;EAAQ,EAAE,iBAAiB;CAC3G,MAAM,aAAa,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,IAAI;CACpE,MAAM,gBAAgB,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,IAAI;CACvE,MAAM,gBAAgB,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,GAAG,OAAO,WAAW,GAAG,OAAO,cAAc;CAChH,MAAM,OAAO,EAAE,OAAO,EAAE,WAAW,eAAe,CAAC;CACnD,MAAM,QAAQ,EAAE,OAAO,EAAE,WAAW,gBAAgB,EAAE,6FAA6F;CACnJ,MAAM,SAAS,EAAE,OAAO,EAAE,WAAW,uBAAuB,CAAC;CAC7D,MAAM,uBAAuB,EAAE,OAAO,EAAE,WAAW,iCAAiC,CAAC;CACrF,MAAM,sBAAsB,EAAE,OAAO,EAAE,WAAW,gCAAgC,CAAC;CACnF,MAAM,4BAA4B,EAAE,QAAQ,EAAE,WAAW,gCAAgC,CAAC;CAC1F,MAAM,6BAA6B,EAAE,QAAQ,EAAE,WAAW,gCAAgC,CAAC;CAC3F,MAAM,2BAA2B,EAAE,UAAU;EAAE,WAAW;EAAmB,MAAM;EAAU,CAAC;CAC9F,MAAM,4BAA4B,EAAE,UAAU;EAAE,WAAW;EAAmB,MAAM;EAAU,CAAC;CAC/F,MAAM,kBAAkB,EAAE,OAAO;EAAE,WAAW;EAA2B,MAAM;EAAU,EACvF,sBACA,qBACA,EAAE,OAAO,EAAE,WAAW,mCAAmC,EACvD,EAAE,QAAQ,EAAE,WAAW,kCAAkC,EACvD,EAAE,QAAQ,EAAE,WAAW,iCAAiC,EAAE,QAAQ,EAClE,2BACA,yBACD,EACD,EAAE,QAAQ,EAAE,WAAW,kCAAkC,EACvD,EAAE,QAAQ,EAAE,WAAW,iCAAiC,EAAE,SAAS,EACnE,4BACA,0BACD,CACF,CACF;CACD,MAAM,gBAAgB,EAAE,UAAU,EAAE,WAAW,iCAAiC,EAAE,OAAO;CACzF,MAAM,eAAe,EAAE,UAAU;EAAE,WAAW;EAAmB,cAAc;EAA2B,gBAAgB;EAA2B,CAAC;CACtJ,MAAM,cAAc,EAAE,UAAU;EAAE,WAAW;EAAmB,cAAc;EAAkB,gBAAgB;EAAkB,CAAC;CACnI,MAAM,aAAa,EAAE,QAAQ,EAAE,WAAW,+BAA+B,EAAE,IAAI;CAC/E,MAAM,eAAe,EAAE,QAAQ,EAAE,WAAW,+BAA+B,EAAE,IAAI;CAEjF,SAAS,oBAAqC;AAC5C,MAAI;GACF,MAAM,MAAM,eAAe,QAAQ,6BAA6B;AAChE,OAAI,OAAO,KAAM,QAAO,EAAE,GAAG,0BAA0B;GACvD,MAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,OAAI,UAAU,QAAQ,OAAO,WAAW,SAAU,QAAO,EAAE,GAAG,0BAA0B;GACxF,MAAM,MAAM;AACZ,UAAO;IACL,OAAO,mBAAmB,IAAI,MAAM,GAAG,IAAI,QAAQ,yBAAyB;IAC5E,QAAQ,oBAAoB,IAAI,OAAO,GAAG,IAAI,SAAS,yBAAyB;IAChF,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa,yBAAyB;IAC3F,eAAe,OAAO,IAAI,kBAAkB,WAAW,IAAI,gBAAgB,yBAAyB;IACpG,UAAU,OAAO,IAAI,aAAa,YAAY,IAAI,WAAW,yBAAyB;IACvF;UACK;AACN,UAAO,EAAE,GAAG,0BAA0B;;;CAG1C,SAAS,eAAe,MAAuB;AAC7C,MAAI;AACF,kBAAe,QAAQ,8BAA8B,KAAK,UAAU,KAAK,CAAC;UACpE;;CAKV,IAAI,cAAc,OAAO,SAAS;CAClC,IAAI,iBAAiC;EAAE,MAAM;EAAa,aAAa;EAAG,WAAW,EAAE;EAAE,UAAU,EAAE;EAAE;CACvG,IAAI,wBAAwB;CAC5B,IAAI,sBAAqC;CACzC,IAAI,0BAA0B;CAC9B,IAAI,iBAAiB;CACrB,IAAI,WAAW;CACf,IAAI,cAAc;CAClB,IAAI,cAAqC;CACzC,IAAI,2BAA0C;CAC9C,IAAI,4BAA2C;CAC/C,IAAI,uBAAsC;CAI1C,IAAI,uBAAsC;CAC1C,MAAM,sCAAsB,IAAI,KAAa;CAK7C,MAAM,yCAAyB,IAAI,KAAa;CAChD,IAAI,0BAAyC;CAG7C,IAAI,eAAqC,EAAE;CAC3C,MAAM,uCAAuB,IAAI,KAA0C;CAC3E,MAAM,kCAAkB,IAAI,KAAqC;CAEjE,SAAS,gBAAgB,QAAqB,OAAe;AAC3D,SAAO,cAAc;;CAGvB,SAAS,0BAA0B,QAAqB,OAAe,OAAe;AACpF,oBAAkB,YAAY;AAC5B,OAAI;AACF,UAAM,UAAU,UAAU,UAAU,MAAM;AAC1C,WAAO,cAAc;AACrB,WAAO,iBAAiB,gBAAgB,QAAQ,MAAM,EAAE,KAAK;WACvD;AACN,WAAO,cAAc;AACrB,WAAO,iBAAiB,gBAAgB,QAAQ,MAAM,EAAE,KAAK;;IAE/D;;CAIJ,MAAM,2BAAW,IAAI,KAAwB;CAC7C,IAAI,gBAAgB;CACpB,IAAI,mBAAmB;CACvB,SAAS,kBAAkB;AACzB,WAAS,OAAO;AAChB,oCAAkB,IAAI,SAAS;EAC/B,MAAM,MAAM,SAAS,iBAAiB,IAAI;AAC1C,OAAK,MAAM,MAAM,KAAK;AACpB,OAAI,CAAC,4BAA4B,GAAG,CAAE;GACtC,MAAM,MAAM,GAAG,QAAQ,aAAa;GACpC,MAAM,SAAS,SAAS,IAAI,IAAI,IAAI,EAAE;AACtC,UAAO,KAAK,GAAG;AACf,YAAS,IAAI,KAAK,OAAO;;AAE3B,kBAAgB;;CAYlB,MAAM,gCAAgC;CACtC,MAAM,yBAAyB;CAI/B,IAAI,kCAAkB,IAAI,SAAoD;CAC9E,SAAS,mBAAmB,OAAkD;EAC5E,MAAM,SAAS,gBAAgB,IAAI,MAAM;AACzC,MAAI,UAAU,KAAM,QAAO;EAC3B,IAAI,SAAS;EACb,IAAI,UAA0B;AAC9B,OAAK,IAAI,OAAO,GAAG,WAAW,QAAQ,YAAY,SAAS,QAAQ,YAAY,SAAS,mBAAmB,OAAO,wBAAwB,QAAQ;AAChJ,OAAI,QAAQ,QAAQ,8BAA8B,EAAE;AAClD,aAAS;AACT;;GAEF,MAAM,SAAyB,QAAQ;AACvC,OAAI,OAAO,iBAAiB,QAAQ,CAAC,WAAW,cAAc,UAAU,QAAQ,OAAO,iBAAiB,OAAO,CAAC,WAAW,YAAY;AACrI,aAAS;AACT;;AAEF,aAAU;;EAEZ,MAAM,WAAW;GAAE;GAAQ,KAAK,mBAAmB,OAAO;GAAE;AAC5D,kBAAgB,IAAI,OAAO,SAAS;AACpC,SAAO;;CAET,SAAS,iBAAiB;AACxB,MAAI,cAAe,kBAAiB;;CAEtC,SAAS,qBAAqB;AAC5B,kBAAgB;;CAElB,SAAS,+BAA+B;AACtC,MAAI,qBAAqB,EACvB,QAAO,aAAa,iBAAiB;AAEvC,qBAAmB,OAAO,iBAAiB;AACzC,sBAAmB;AACnB,uBAAoB;AACpB,mBAAgB;KACf,+BAA+B;;CAGpC,SAAS,8BAA8B,SAAoC;EACzE,MAAM,UAAU,QAAQ,OAAO,4BAA4B;AAC3D,SAAO,QAAQ,WAAW,IAAI,QAAQ,KAAK;;CAG7C,SAAS,sBAAsB,UAAkC;AAC/D,MAAI;AAEF,UAAO,8BADK,MAAM,KAAK,SAAS,iBAAiB,SAAS,CAAC,CAClB;UACnC;AACN,UAAO;;;CAIX,SAAS,sBAAsB,SAAkB,SAA+B,YAA8B;AAC5G,MAAI,QAAQ,QAAQ,aAAa,KAAK,QAAQ,IAAK,QAAO;AAC1D,MAAI,YACF;QAAK,MAAM,OAAO,QAAQ,QACxB,KAAI,CAAC,QAAQ,UAAU,SAAS,IAAI,CAAE,QAAO;;AAGjD,SAAO;;CAGT,SAAS,qBAAqB,MAAe,OAA+B,YAAqB,cAAuB,aAA+B;EACrJ,IAAI,SAAyB;AAC7B,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,OAAI,UAAU,KAAM,QAAO;GAC3B,MAAM,UAAU,MAAM;AACtB,OAAI,CAAC,sBAAsB,QAAQ,SAAS,WAAW,CAAE,QAAO;AAChE,OAAI,gBAAgB,QAAQ,aAAa,MACvC;QAAI,iBAAiB,OAAO,KAAK,QAAQ,UAAW,QAAO;;AAE7D,OAAI,eAAe,QAAQ,YAAY,MACrC;QAAI,gBAAgB,OAAO,KAAK,QAAQ,SAAU,QAAO;;AAE3D,YAAS,OAAO;;AAElB,SAAO;;CAGT,SAAS,iBAAiB,IAAqB;EAC7C,IAAI,IAAI;EACR,IAAI,MAAM,GAAG;EACb,MAAM,MAAM,GAAG;AACf,SAAO,OAAO,MAAM;AAClB,OAAI,IAAI,YAAY,IAAK,MAAK;AAC9B,SAAM,IAAI;;AAEZ,SAAO;;CAGT,SAAS,gBAAgB,IAAqB;EAC5C,IAAI,IAAI;EACR,IAAI,MAAM,GAAG;AACb,SAAO,OAAO,MAAM;AAClB,QAAK;AACL,SAAM,IAAI;;AAEZ,SAAO;;CAGT,SAAS,sBAAsB,OAA+C;AAC5E,MAAI,MAAM,WAAW,EAAG,QAAO;EAC/B,MAAM,OAAO,MAAM;AASnB,OAAK,MAAM,EAAE,UANqD;GAChE,EAAE,MAAM,oBAAoB;GAC5B,EAAE,MAAM,eAAe;GACvB,EAAE,MAAM,gBAAgB;GACxB,EAAE,MAAM,QAAQ;GACjB,EACuC;GACtC,MAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,OAAI,UAAU,GAAI;GAElB,MAAM,QAAwB,sBADlB,IAAI,KAAK,IAAI,mBAAmB,MAAM,CAAC,IACK;AACxD,OAAI,MAAO,QAAO;;EAEpB,MAAM,KAAK,cAAc,MAAM,KAAK;AACpC,MAAI,OAAO,IAAI;GACb,MAAM,QAAwB,sBAAsB,IAAI,eAAe,GAAG,GAAG;AAC7E,OAAI,MAAO,QAAO;;AAEpB,MAAI,KAAK,QAAQ,QAAQ,KAAK,SAAS,MAAM,KAAK,QAAQ,KAAK;GAC7D,MAAM,QAAwB,sBAAsB,WAAW,mBAAmB,KAAK,KAAK,CAAC,IAAI;AACjG,OAAI,MAAO,QAAO;;AAKpB,OAAK,MAAM,QADc;GAAC;GAAc;GAAQ;GAAe;GAAS;GAAO,EAC1C;GACnC,MAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,OAAI,UAAU,GAAI;GAElB,MAAM,QAAwB,sBADlB,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,mBAAmB,MAAM,CAAC,IACN;AACxD,OAAI,MAAO,QAAO;;AAIpB,kBAAgB;EAChB,MAAM,aAAa,SAAS,IAAI,KAAK,IAAI,IAAI,EAAE;AAC/C,MAAI,WAAW,WAAW,EAAG,QAAO;EAGpC,MAAM,KAAgB,EAAE;AACxB,OAAK,MAAM,aAAa,WACtB,KAAI,qBAAqB,WAAW,OAAO,MAAM,OAAO,MAAM,CAAE,IAAG,KAAK,UAAU;EAEpF,MAAM,KAAK,8BAA8B,GAAG;AAC5C,MAAI,MAAM,KAAM,QAAO;EAGvB,MAAM,KAAgB,EAAE;AACxB,OAAK,MAAM,aAAa,WACtB,KAAI,qBAAqB,WAAW,OAAO,MAAM,MAAM,MAAM,CAAE,IAAG,KAAK,UAAU;EAEnF,MAAM,KAAK,8BAA8B,GAAG;AAC5C,MAAI,MAAM,KAAM,QAAO;EAGvB,MAAM,KAAgB,EAAE;AACxB,OAAK,MAAM,aAAa,WACtB,KAAI,qBAAqB,WAAW,OAAO,MAAM,MAAM,KAAK,CAAE,IAAG,KAAK,UAAU;EAElF,MAAM,KAAK,8BAA8B,GAAG;AAC5C,MAAI,MAAM,KAAM,QAAO;AAEvB,SAAO;;AAGT,SAAQ,aAAa,6NAAyM;CAC9N,MAAM,eAAe;CACrB,MAAM,iBAAiB;CACvB,MAAM,gBAAgB;CACtB,MAAM,kBAAkB;CACxB,MAAM,aAAa;CACnB,MAAM,gBAAgB;CAMtB,IAAI,qBAAqB;CACzB,SAAS,iBAAiB;EACxB,MAAM,OAAO,WAAW,iBAAiB;AACzC,MAAI,uBAAuB,KAAM;AACjC,uBAAqB;AACrB,UAAQ,cAAc,KAAK;;AAE7B,iBAAgB;AAChB,iBAAgB,0BAA0B,aAAa;AACvD,iBAAgB,2BAA2B,cAAc;AACzD,0BAAyB,iBAAiB,eAAe;AACvD,4BAA0B,0BAA0B,0BAA0B,aAAa,aAAa;GACxG;AACF,2BAA0B,iBAAiB,eAAe;AACxD,4BAA0B,2BAA2B,2BAA2B,aAAa,cAAc;GAC3G;CAEF,MAAM,QAAQ,EAAE,OAAO,EAAE,WAAW,gBAAgB,EAClD,EAAE,OAAO,EAAE,WAAW,eAAe,EAAE,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAC1G,EAAE,OAAO,EAAE,WAAW,eAAe,EAAE,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,WAAW,EAAE,cAAc,EAC/G,EAAE,OAAO,EAAE,WAAW,eAAe,EAAE,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,WAAW,EAAE,cAAc,CAChH;CAED,IAAI,UAA2B,mBAAmB;CAClD,IAAI,uBAAuB;CAK3B,IAAI,uBAAuB,QAAQ,WAAW,MAAM,KAAK;CAEzD,SAAS,yBAAiC;AACxC,MAAI,qBAAsB,QAAO,QAAQ,WAAW,MAAM;AAC1D,SAAO,oBAAoB,OAAO,SAAS,SAAS;;CAItD,SAAS,qBAAqB;AAC5B,MAAI,qBAAsB;EAC1B,MAAM,OAAO,oBAAoB,OAAO,SAAS,SAAS;AAC1D,MAAI,gBAAgB,UAAU,KAC5B,iBAAgB,QAAQ;;CAI5B,SAAS,iBAAiB,SAAkC,OAAkC;EAC5F,MAAM,KAAK,EAAE,UAAU,EAAE,WAAW,uBAAuB,CAAC;AAC5D,OAAK,MAAM,CAAC,UAAU,UAAU,SAAS;GACvC,MAAM,MAAM,EAAE,UAAU,EAAE,OAAO,UAAU,EAAE,MAAM;AACnD,MAAG,YAAY,IAAI;;AAErB,KAAG,QAAQ;AACX,SAAO;;CAGT,MAAM,cAAc,iBAAiB;EACnC,CAAC,OAAO,WAAW;EACnB,CAAC,MAAM,cAAc;EACrB,CAAC,OAAO,eAAe;EACxB,EAAE,QAAQ,MAAM;CAKjB,MAAM,gBAA+C;EACnD,CAAC,OAAO,MAAM;EACd,CAAC,UAAU,SAAS;EACpB,CAAC,UAAU,SAAS;EACpB,CAAC,UAAU,SAAS;EACpB,CAAC,WAAW,UAAU;EACtB,CAAC,cAAc,OAAO;EACtB,CAAC,MAAM,KAAK;EACb;CACD,MAAM,cAAc,EAAE,QAAQ;EAAE,WAAW;EAAoB,eAAe;EAAQ,CAAC;CACvF,MAAM,iBAAiB,EAAE,OAAO;EAC9B,WAAW;EACX,MAAM;EACN,cAAc;EACf,EAAE,YAAY;CACf,MAAM,gCAAgB,IAAI,KAA2C;CAGrE,IAAI,oBAAoB;CACxB,SAAS,sBAAsB;EAC7B,MAAM,SAAS,cAAc,IAAI,QAAQ,OAAO;AAGhD,MAAI,UAAU,QAAQ,OAAO,gBAAgB,EAAG;AAChD,MAAI,CAAC,kBACH,aAAY,MAAM,aAAa;AAEjC,cAAY,MAAM,YAAY,cAAc,OAAO,WAAW;AAC9D,cAAY,MAAM,QAAQ,GAAG,OAAO,YAAY;AAChD,MAAI,CAAC,mBAAmB;AAGtB,GAAK,YAAY;AACjB,eAAY,MAAM,aAAa;AAC/B,uBAAoB;;;AAGxB,MAAK,MAAM,CAAC,KAAK,UAAU,eAAe;EACxC,MAAM,MAAM,EAAE,UAAU;GACtB,WAAW;GACX,MAAM;GACN,MAAM;GACP,EAAE,MAAM;AACT,MAAI,aAAa,gBAAgB,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAChE,MAAI,iBAAiB,eAAe;AAClC,OAAI,QAAQ,WAAW,IAAK;AAC5B,iBAAc,EAAE,QAAQ,KAAK,CAAC;AAC9B,QAAK,MAAM,CAAC,GAAG,MAAM,cACnB,GAAE,aAAa,gBAAgB,OAAO,MAAM,IAAI,CAAC;AAEnD,wBAAqB;IACrB;AACF,gBAAc,IAAI,KAAK,IAAI;AAC3B,iBAAe,YAAY,IAAI;;CAEjC,MAAM,kBAAkB,EAAE,SAAS;EACjC,WAAW;EACX,MAAM;EACN,aAAa;EACb,YAAY;EACZ,cAAc;EACd,gBAAgB;EACjB,CAAC;AACF,iBAAgB,QAAQ,wBAAwB;CAGhD,MAAM,kBAAkB,EAAE,UAAU;EAClC,WAAW;EACX,MAAM;EACN,cAAc;EACd,gBAAgB;EACjB,CAAC;AACF,SAAQ,iBAAiB,8QAA0P;CAMnR,SAAS,gCAAgC;EACvC,MAAM,OAAO,oBAAoB,OAAO,SAAS,SAAS;EAC1D,MAAM,YAAY,wBAAwB,QAAQ,WAAW,MAAM,KAAK;AACxE,kBAAgB,UAAU,OAAO,+BAA+B,UAAU;;CAM5E,MAAM,iBAAiB,EAAE,UAAU;EACjC,WAAW;EACX,MAAM;EACN,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EACjB,CAAC;AACF,SAAQ,gBAAgB,+PAAqO;CAE7P,SAAS,eAAe,SAAiB,aAAkC;AACzE,SAAO,EAAE,OAAO,EAAE,WAAW,uBAAuB,EAClD,EAAE,QAAQ,EAAE,WAAW,wBAAwB,EAAE,QAAQ,EACzD,EAAE,QAAQ,EAAE,WAAW,wBAAwB,EAAE,YAAY,CAC9D;;CAEH,SAAS,SAAS,MAA2B;AAC3C,SAAO,EAAE,QAAQ,EAAE,WAAW,wBAAwB,EAAE,KAAK;;CAE/D,MAAM,eAAe,EAAE,OAAO,EAAE,WAAW,yBAAyB,CAAC;CACrE,MAAM,cAAc,EAAE,OAAO,EAAE,WAAW,wBAAwB,CAAC;CACnE,MAAM,cAAc,EAAE,OAAO,EAAE,WAAW,wBAAwB,CAAC;CACnE,SAAS,gBAAgB;AACvB,eAAa,cAAc;AAC3B,cAAY,gBACV,2HACA,SAAS,IAAI,EACb,sEACA,SAAS,IAAI,EACb,2CACD;AACD,cAAY,gBACV,eAAe,YAAY,kBAAkB,EAC7C,eAAe,eAAe,4BAA4B,EAC1D,eAAe,oBAAoB,mCAAmC,EACtE,eAAe,cAAc,+BAA+B,EAC5D,eAAe,KAAK,aAAa,EACjC,eAAe,WAAW,uCAAuC,CAClE;;CAEH,MAAM,iBAAiB,EAAE,OAAO;EAAE,WAAW;EAAmB,MAAM;EAAU,cAAc;EAAoB,EAChH,cACA,aACA,YACD;CAED,IAAI,cAAc;CAClB,SAAS,eAAe,MAAe;AACrC,gBAAc;AACd,iBAAe,UAAU,OAAO,wBAAwB,KAAK;AAC7D,iBAAe,aAAa,iBAAiB,OAAO,KAAK,CAAC;;AAE5D,gBAAe,iBAAiB,UAAU,UAAU;AAClD,QAAM,iBAAiB;AACvB,iBAAe,CAAC,YAAY;GAC5B;AACF,gBAAe,iBAAiB,UAAU,UAAU;AAClD,QAAM,iBAAiB;GACvB;AACF,gBAAe;CAEf,MAAM,qBAAqB,EAAE,SAAS;EACpC,WAAW;EACX,MAAM;EACN,aAAa;EACb,cAAc;EACd,YAAY;EACZ,cAAc;EACd,gBAAgB;EACjB,CAAC;AACF,oBAAmB,QAAQ,QAAQ;CAEnC,SAAS,gBAAgB,OAAe,OAAoB,QAAmC;EAC7F,MAAM,WAAW,EAAE,QAAQ,EAAE,WAAW,2BAA2B,EACjE,EAAE,QAAQ,EAAE,WAAW,uBAAuB,EAAE,MAAM,CACvD;AACD,MAAI,UAAU,KACZ,UAAS,YAAY,OAAO;AAE9B,SAAO,EAAE,SAAS,EAAE,WAAW,uBAAuB,EACpD,UACA,MACD;;CAOH,MAAM,aAAa,EAAE,QAAQ,EAAE,WAAW,8BAA8B,CAAC;CACzE,MAAM,eAAe,EAAE,QAAQ,EAAE,WAAW,8BAA8B,CAAC;AAC3E,SAAQ,YAAY,cAAc;AAClC,SAAQ,cAAc,gBAAgB;CAUtC,MAAM,kBAAkB;CACxB,MAAM,qBAAqB,EAAE,UAAU;EACrC,WAAW;EACX,MAAM;EACN,gBAAgB;EAChB,cAAc;EACd,gBAAgB;EACjB,CAAC;AACF,SAAQ,oBAAoB,gBAAgB;CAC5C,MAAM,qBAAqB,EAAE,QAAQ,EAAE,WAAW,2BAA2B,CAAC;AAC9E,SAAQ,oBAAoB,gBAAgB;CAC5C,MAAM,iBAAiB,EAAE,UAAU;EACjC,WAAW;EACX,MAAM;EACN,gBAAgB;EAChB,gBAAgB;EACjB,EAAE,oBAAoB,cAAc;CAErC,SAAS,sBAAsB;AAC7B,OAAK,MAAM,UAAU,CAAC,oBAAoB,eAAe,EAAE;AACzD,UAAO,aAAa,gBAAgB,OAAO,QAAQ,SAAS,CAAC;AAC7D,UAAO,UAAU,OAAO,6BAA6B,QAAQ,SAAS;;;CAG1E,SAAS,YAAY,MAAe;AAClC,MAAI,QAAQ,aAAa,KAAM;AAC/B,YAAU;GAAE,GAAG;GAAS,UAAU;GAAM;AACxC,iBAAe,QAAQ;AACvB,uBAAqB;AACrB,kBAAgB;;AAElB,oBAAmB,iBAAiB,eAAe,YAAY,CAAC,QAAQ,SAAS,CAAC;AAClF,gBAAe,iBAAiB,eAAe,YAAY,CAAC,QAAQ,SAAS,CAAC;AAC9E,sBAAqB;CAMrB,MAAM,oBAAoB,EAAE,UAAU;EACpC,WAAW;EACX,MAAM;EACN,gBAAgB;EAChB,cAAc;EACd,gBAAgB;EACjB,CAAC;CACF,IAAI,0BAA0B;CAC9B,SAAS,wBAAwB;AAC/B,oBAAkB,aAAa,gBAAgB,OAAO,CAAC,eAAe,CAAC;EACvE,MAAM,QAAQ,iBAAiB,iBAAiB;AAChD,oBAAkB,aAAa,cAAc,MAAM;AACnD,oBAAkB,aAAa,gBAAgB,MAAM;AACrD,oBAAkB,UAAU,OAAO,2BAA2B,CAAC,eAAe;EAC9E,MAAM,OAAO,iBAAiB,aAAa;AAC3C,MAAI,4BAA4B,MAAM;AACpC,6BAA0B;AAC1B,WAAQ,mBAAmB,KAAK;;;AAGpC,mBAAkB,iBAAiB,eAAe;AAChD,mBAAiB,CAAC;AAClB,UAAQ;GACR;AACF,wBAAuB;CACvB,MAAM,UAAU,EAAE,OAAO,EAAE,WAAW,kBAAkB,EACtD,aACA,EAAE,OAAO,EAAE,WAAW,wBAAwB,EAAE,WAAW,EAC3D,EAAE,OAAO,EAAE,WAAW,0BAA0B,EAC9C,aACA,EAAE,OAAO,EAAE,WAAW,sBAAsB,EAAE,iBAAiB,iBAAiB,gBAAgB,eAAe,CAChH,EACD,EAAE,OAAO,EAAE,WAAW,0BAA0B,EAC9C,EAAE,QAAQ;EAAE,WAAW;EAAyB,gBAAgB;EAAoB,EAAE,YAAY,WAAW,EAC7G,EAAE,QAAQ;EAAE,WAAW;EAAyB,gBAAgB;EAAmB,EAAE,cAAc,aAAa,CACjH,EACD,oBACA,mBACA,aACD;CAQD,MAAM,YAAY,EAAE,OAAO,EAAE,WAAW,kBAAkB,EACxD,gBAAgB,YAAY,eAAe,EAC3C,gBACD;CAED,SAAS,uBAAuB;AAC9B,MAAI,yBAAyB,EAC3B,QAAO,aAAa,qBAAqB;AAE3C,yBAAuB,OAAO,iBAAiB;AAC7C,0BAAuB;AACvB,qBAAkB,oBAAoB,CAAC;KACtC,IAAI;;CAGT,SAAS,cAAc,MAAgC;AACrD,YAAU;GAAE,GAAG;GAAS,GAAG;GAAM;AACjC,iBAAe,QAAQ;AACvB,wBAAsB;;CAGxB,IAAI,wBAAwB;CAC5B,SAAS,oBAAoB,OAAe;AAC1C,YAAU;GAAE,GAAG;GAAS,eAAe;GAAO;AAC9C,iBAAe,QAAQ;AACvB,MAAI,0BAA0B,EAC5B,QAAO,aAAa,sBAAsB;AAE5C,0BAAwB,OAAO,iBAAiB;AAC9C,2BAAwB;AACxB,mBAAgB;KACf,IAAI;;AAGT,aAAY,iBAAiB,gBAAgB;AAC3C,MAAI,mBAAmB,YAAY,MAAM,CAAE,eAAc,EAAE,OAAO,YAAY,OAAO,CAAC;GACtF;AACF,iBAAgB,iBAAiB,eAAe;EAC9C,MAAM,QAAQ,gBAAgB;AAE9B,yBAAuB,MAAM,MAAM,KAAK;AACxC,gBAAc,EAAE,YAAY,OAAO,CAAC;AACpC,iCAA+B;GAC/B;AACF,iBAAgB,iBAAiB,eAAe;AAG9C,yBAAuB;AACvB,kBAAgB,QAAQ,oBAAoB,OAAO,SAAS,SAAS;AACrE,gBAAc,EAAE,YAAY,IAAI,CAAC;AACjC,iCAA+B;GAC/B;AACF,oBAAmB,iBAAiB,eAAe;AACjD,sBAAoB,mBAAmB,MAAM;GAC7C;CAUF,MAAM,OAAO,EAAE,OAAO,EAAE,WAAW,eAAe,EAChD,WAFc,EAAE,OAAO,EAAE,WAAW,kBAAkB,EAAE,OAAO,gBAAgB,cAAc,CAI9F;CAID,MAAM,kBAAkB,EAAE,UAAU;EAClC,WAAW;EACX,MAAM;EACN,MAAM;EACN,gBAAgB;EAChB,cAAc;EACf,CAAC;CACF,MAAM,oBAAoB,EAAE,QAAQ,EAAE,WAAW,8BAA8B,CAAC;CAChF,MAAM,iBAAiB,EAAE,UAAU;EAAE,WAAW;EAA4B,MAAM;EAAU,EAAE,WAAW;CACzG,MAAM,iBAAiB,EAAE,UAAU;EAAE,WAAW;EAA4B,MAAM;EAAU,EAAE,WAAW;CACzG,MAAM,aAAa,EAAE,OAAO,EAAE,WAAW,sBAAsB,EAC7D,iBACA,mBACA,oBACA,gBACA,eACD;AACD,iBAAgB,iBAAiB,eAAe;AAE9C,MADoB,aAAa,SAAS,KAAK,aAAa,OAAO,UAAU,uBAAuB,IAAI,MAAM,SAAS,CAAC,EACvG;AACf,mBAAgB;AAChB;;AAEF,yBAAuB,OAAO;AAC9B,OAAK,MAAM,SAAS,aAAc,wBAAuB,IAAI,MAAM,SAAS;AAC5E,4BAA0B;AAC1B,kBAAgB;GAChB;AACF,gBAAe,iBAAiB,eAAe;AAC7C,OAAK,MAAM,SAAS,qBAAqB,CAAE,qBAAoB,OAAO,MAAM,SAAS;AACrF,kBAAgB;GAChB;AACF,gBAAe,iBAAiB,eAAe;AAC7C,OAAK,MAAM,SAAS,qBAAqB,CAAE,qBAAoB,IAAI,MAAM,SAAS;AAClF,kBAAgB;GAChB;CACF,MAAM,OAAO,EAAE,OAAO,EAAE,WAAW,eAAe,EAAE,QAAQ,YAAY,KAAK;CAC7E,MAAM,UAAU,EAAE,OAAO,EAAE,WAAW,kBAAkB,EAAE,MAAM,KAAK;CAErE,SAAS,YAAkC;EACzC,MAAM,wBAAQ,IAAI,KAAiC;AACnD,MAAI,eAAe,SAAS,YAC1B,QAAO,EAAE;EAGX,MAAM,cAAc,QAAQ,cAAc,MAAM,CAAC,aAAa;EAC9D,MAAM,iBAAiB,UAA0C;AAC/D,OAAI,gBAAgB,GAAI,QAAO;AAE/B,UADkB;IAAC,MAAM;IAAc,MAAM;IAAS,MAAM,QAAQ;IAAI,MAAM;IAAc,CAC3E,MAAM,UAAU,MAAM,aAAa,CAAC,SAAS,YAAY,CAAC;;AAI7E,MAAI,eAAe,SAAS,SAAS,GAAG;AACtC,mBAAgB;AAChB,QAAK,MAAM,gBAAgB,eAAe,UAAU;AAClD,QAAI,CAAC,cAAc,aAAa,CAAE;IAClC,MAAM,QAAQ,mBAAmB,aAAa,cAAc;IAC5D,IAAI,UAAU,MAAM,SAAS,IAAI,sBAAsB,MAAM,GAAG;AAChE,QAAI,WAAW,QAAQ,aAAa,QAAQ,QAAQ,aAAa,SAAS,MAAM,aAAa,QAAQ,aAAa,KAAK,IACrH,WAAU,sBAAsB,WAAW,mBAAmB,aAAa,KAAK,CAAC,IAAI;AAEvF,QAAI,WAAW,KAAM;IAGrB,MAAM,EAAE,QAAQ,QAAQ,mBAAmB,QAAQ;IACnD,MAAM,WAAW,MAAM,IAAI,IAAI;AAC/B,QAAI,YAAY,MAAM;AACpB,cAAS,SAAS,aAAa;AAC/B,cAAS,aAAa,aAAa;AACnC;;AAEF,UAAM,IAAI,KAAK;KACb,UAAU;KACV,OAAO,wBAAwB,OAAO;KACtC,OAAO,aAAa;KACpB,WAAW,aAAa;KACxB,SAAS;KACT,MAAM,OAAO,uBAAuB;KACrC,CAAC;;;AAKN,MAAI,MAAM,SAAS,EACjB,MAAK,MAAM,oBAAoB,eAAe,WAAW;AACvD,OAAI,gBAAgB,MAAM,CAAC,iBAAiB,SAAS,aAAa,CAAC,SAAS,YAAY,CAAE;GAC1F,MAAM,UAAU,uBAAuB,iBAAiB,SAAS;AACjE,OAAI,WAAW,KAAM;GACrB,MAAM,EAAE,QAAQ,QAAQ,mBAAmB,QAAQ;GACnD,MAAM,WAAW,MAAM,IAAI,IAAI;AAC/B,OAAI,YAAY,MAAM;AACpB,aAAS,SAAS,iBAAiB;AACnC;;AAEF,SAAM,IAAI,KAAK;IACb,UAAU;IACV,OAAO,wBAAwB,OAAO;IACtC,OAAO,iBAAiB;IAExB,WAAW;IACX,SAAS;IACT,MAAM,OAAO,uBAAuB;IACrC,CAAC;;EAIN,IAAI,SAAS,MAAM,KAAK,MAAM,QAAQ,CAAC;AACvC,MAAI,CAAC,QAAQ,SAGX,UAAS,OAAO,QAAQ,UAAU,qBAAqB,MAAM,GAAG,EAAE;AAEpE,SAAO,OAAO,MAAM,GAAG,MAAM,qBAAqB,EAAE,GAAG,qBAAqB,EAAE,IAAI,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC;;CAM1H,SAAS,qBAAqB,OAAmC;AAC/D,SAAO,QAAQ,WAAW,MAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,QAAQ,MAAM,UAAU;;CAGpF,SAAS,uBAAuB,OAAmC;AACjE,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,SAAO,KAAK,IAAI,KAAK,KAAK,MAAO,MAAM,YAAY,MAAM,QAAS,IAAI,CAAC;;CAGzE,SAAS,iBAAiB;AACxB,uBAAqB,YAAY;AACjC,gBAAc,sBAAsB,OAAO;;CAG7C,SAAS,+BAA+B;AACtC,uBAAqB,OAAO;AAC5B,cAAY,gBAAgB,iBAAiB;AAC7C,mBAAiB,UAAU,OAAO,4BAA4B,6BAA6B;AAC3F,8BAA4B;;CAG9B,SAAS,4BAA4B;AACnC,kBAAgB,OAAO;AACvB,OAAK,iBAAiB;;CAGxB,SAAS,0BAA6D;EACpE,MAAM,iBAAiB,OAAO;AAC9B,MAAI,kBAAkB,KACpB,QAAO;GAAE,OAAO,eAAe;GAAO,QAAQ,eAAe;GAAQ;AAEvE,SAAO;GAAE,OAAO,OAAO;GAAY,QAAQ,OAAO;GAAa;;CAGjE,SAAS,qBAA8B;AACrC,SAAO;;CAGT,SAAS,iBAAiB,UAAkB;AAC1C,MAAI,oBAAoB,IAAI,SAAS,CACnC,qBAAoB,OAAO,SAAS;MAEpC,qBAAoB,IAAI,SAAS;AAEnC,kBAAgB;;CAGlB,SAAS,iBAAiB;AACxB,MAAI,uBAAuB,SAAS,KAAK,4BAA4B,KAAM;AAC3E,yBAAuB,OAAO;AAC9B,4BAA0B;AAC1B,6BAA2B;AAC3B,kBAAgB;;CAGlB,SAAS,oBAAoB,UAAkB;AAC7C,MAAI,uBAAuB,IAAI,SAAS,EAAE;AACxC,0BAAuB,OAAO,SAAS;AACvC,OAAI,6BAA6B,SAAU,4BAA2B;SACjE;AACL,0BAAuB,IAAI,SAAS;AACpC,8BAA2B;;AAE7B,4BAA0B;AAC1B,kBAAgB;;CAQlB,SAAS,qBAAqB,OAA2B,OAAkE;EACzH,MAAM,SAAS,MAAM,WAAW,MAAM;AACtC,MAAI,MAAM,YAAY,2BAA2B,MAAM;GACrD,MAAM,QAAQ,aAAa,KAAK,cAAc,UAAU,SAAS;GACjE,MAAM,cAAc,MAAM,QAAQ,wBAAwB;GAC1D,MAAM,cAAc,MAAM,QAAQ,MAAM,SAAS;AACjD,OAAI,gBAAgB,MAAM,gBAAgB,IAAI;AAC5C,QAAI,CAAC,OAAQ,wBAAuB,OAAO;IAC3C,MAAM,CAAC,OAAO,OAAO,eAAe,cAAc,CAAC,aAAa,YAAY,GAAG,CAAC,aAAa,YAAY;AACzG,SAAK,MAAM,YAAY,MAAM,MAAM,OAAO,MAAM,EAAE,CAChD,wBAAuB,IAAI,SAAS;AAEtC,+BAA2B,MAAM;AACjC,oBAAgB;AAChB;;;AAGJ,MAAI,QAAQ;AACV,uBAAoB,MAAM,SAAS;AACnC;;AAEF,4BAA0B,MAAM;AAChC,MAAI,uBAAuB,SAAS,KAAK,uBAAuB,IAAI,MAAM,SAAS,EAAE;AACnF,0BAAuB,OAAO,MAAM,SAAS;AAC7C,8BAA2B;SACtB;AACL,0BAAuB,OAAO;AAC9B,0BAAuB,IAAI,MAAM,SAAS;AAC1C,8BAA2B,MAAM;;AAEnC,kBAAgB;;CAKlB,SAAS,sBAA4C;AACnD,MAAI,uBAAuB,OAAO,EAChC,QAAO,aAAa,QAAQ,UAAU,uBAAuB,IAAI,MAAM,SAAS,CAAC;AAEnF,SAAO;;CAGT,SAAS,gBAAgB,UAAyB;AAChD,MAAI,yBAAyB,SAAU;AACvC,yBAAuB;AACvB,kBAAgB;;CAGlB,MAAM,eAAe;CACrB,MAAM,cAAc;CAEpB,SAAS,qBAAqB,UAA0C;EACtE,MAAM,QAAQ,EAAE,QAAQ,EAAE,WAAW,oBAAoB,CAAC;EAC1D,MAAM,QAAQ,EAAE,QAAQ,EAAE,WAAW,oBAAoB,CAAC;EAC1D,MAAM,OAAO,EAAE,QAAQ,EAAE,WAAW,mBAAmB,CAAC;EACxD,MAAM,eAAe,EAAE,QAAQ,EAAE,WAAW,uBAAuB,CAAC;EACpE,MAAM,QAAQ,EAAE,UAAU;GAAE,WAAW;GAAoB,MAAM;GAAU,MAAM;GAAY,gBAAgB;GAAS,CAAC;EACvH,MAAM,MAAM,EAAE,UAAU;GAAE,WAAW;GAAkB,MAAM;GAAU,CAAC;EACxE,MAAM,MAAM,EAAE,OAAO;GACnB,WAAW;GACX,MAAM;GACN,UAAU;GACX,EACC,OACA,OACA,EAAE,QAAQ,EAAE,WAAW,mBAAmB,EACxC,EAAE,QAAQ,EAAE,WAAW,wBAAwB,EAAE,OAAO,KAAK,EAC7D,aACD,EACD,IACD;EACD,MAAM,aAAqC;GAAE;GAAK;GAAO;GAAO;GAAK;GAAO;GAAM,UAAU;GAAc,OAAO;GAAM,iBAAiB;GAAI,mBAAmB;GAAI;AACnK,QAAM,iBAAiB,UAAU,UAAU;AACzC,SAAM,gBAAgB;AACtB,SAAM,iBAAiB;AACvB,OAAI,WAAW,SAAS,KAAM;AAG9B,OAAI,MAAM,YAAY,2BAA2B,MAAM;AACrD,yBAAqB,WAAW,OAAO;KAAE,UAAU;KAAM,SAAS;KAAM,SAAS;KAAO,CAAC;AACzF;;AAEF,uBAAoB,WAAW,MAAM,SAAS;IAC9C;AACF,MAAI,iBAAiB,UAAU,UAAU;AACvC,SAAM,gBAAgB;AACtB,SAAM,iBAAiB;AACvB,oBAAiB,SAAS;IAC1B;AACF,MAAI,iBAAiB,UAAU,UAAU;AACvC,OAAI,WAAW,SAAS,KAAM;AAC9B,wBAAqB,WAAW,OAAO,MAAM;IAC7C;AACF,MAAI,iBAAiB,YAAY,UAAU;AACzC,OAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,IAAK;AAChD,SAAM,gBAAgB;AACtB,OAAI,WAAW,SAAS,KAAM;AAC9B,wBAAqB,WAAW,OAAO,MAAM;IAC7C;AACF,SAAO;;CAGT,SAAS,qBAAqB,YAAoC,OAA2B;EAC3F,MAAM,QAAQ,oBAAoB,IAAI,MAAM,SAAS;EACrD,MAAM,cAAc,6BAA6B,MAAM;EACvD,MAAM,WAAW,uBAAuB,IAAI,MAAM,SAAS;AAC3D,aAAW,QAAQ;AACnB,aAAW,IAAI,UAAU,OAAO,oBAAoB,MAAM;AAC1D,aAAW,IAAI,UAAU,OAAO,0BAA0B,YAAY;AACtE,aAAW,IAAI,UAAU,OAAO,uBAAuB,SAAS;AAChE,aAAW,MAAM,aAAa,gBAAgB,OAAO,SAAS,CAAC;AAC/D,aAAW,MAAM,aAAa,cAAc,WAAW,YAAY,MAAM,UAAU,UAAU,MAAM,QAAQ;EAG3G,MAAM,YAAY,WAAW,eAAe;AAC5C,MAAI,WAAW,sBAAsB,WAAW;AAC9C,cAAW,oBAAoB;AAC/B,WAAQ,WAAW,OAAO,UAAU;;AAEtC,aAAW,MAAM,cAAc,oBAAoB,qBAAqB,MAAM,CAAC;AAC/E,aAAW,IAAI,aAAa,gBAAgB,OAAO,MAAM,CAAC;AAC1D,aAAW,IAAI,aAAa,cAAc,QAAQ,UAAU,MAAM,UAAU,QAAQ,MAAM,QAAQ;AAClG,aAAW,IAAI,QAAQ,QAAQ,mBAAmB;EAGlD,MAAM,UAAU,QAAQ,gBAAgB;AACxC,MAAI,WAAW,oBAAoB,SAAS;AAC1C,cAAW,kBAAkB;AAC7B,WAAQ,WAAW,KAAK,QAAQ;;AAElC,aAAW,MAAM,cAAc,MAAM;AACrC,MAAI,QAAQ,YAAY,MAAM,YAAY,GAAG;GAC3C,MAAM,UAAU,uBAAuB,MAAM;AAC7C,cAAW,KAAK,cAAc,GAAG,QAAQ;AACzC,cAAW,KAAK,QAAQ,GAAG,oBAAoB,MAAM,UAAU,CAAC,MAAM,oBAAoB,MAAM,MAAM,CAAC;AACvG,cAAW,KAAK,UAAU,IAAI,0BAA0B;SACnD;AACL,cAAW,KAAK,cAAc;AAC9B,cAAW,KAAK,QAAQ;AACxB,cAAW,KAAK,UAAU,OAAO,0BAA0B;;AAE7D,aAAW,SAAS,cAAc,MAAM;;CAG1C,SAAS,cAAc,QAA8B;EACnD,MAAM,WAAW,oBAAoB,GAAG,aAAa;AACrD,MAAI,gBAAgB,UAAU;AAC5B,iBAAc;AACd,iCAA8B;;AAEhC,MAAI,CAAC,oBAAoB,CACvB;EAGF,MAAM,mCAAmB,IAAI,KAAa;EAC1C,MAAM,WAAW,KAAK,IAAI,GAAG,GAAG,OAAO,IAAI,qBAAqB,CAAC;AACjE,OAAK,MAAM,SAAS,QAAQ;AAC1B,OAAI,MAAM,QAAQ,QAAQ,MAAM,KAAK,SAAS,KAAK,MAAM,KAAK,UAAU,EACtE;AAEF,oBAAiB,IAAI,MAAM,SAAS;GACpC,MAAM,eAAe,qBAAqB,MAAM;GAChD,MAAM,MAAM,eAAe,cAAc,SAAS;GAClD,MAAM,QAAQ,oBAAoB,IAAI,MAAM,SAAS;GAIrD,MAAM,cAAc,6BAA6B,MAAM,YAAY,uBAAuB,IAAI,MAAM,SAAS;GAC7G,IAAI,iBAAiB,qBAAqB,IAAI,MAAM,SAAS;AAC7D,OAAI,kBAAkB,MAAM;IAC1B,MAAM,SAAS,EAAE,UAAU;KAAE,WAAW;KAAiB,MAAM;KAAU,UAAU;KAAM,CAAC;AAC1F,WAAO,iBAAiB,UAAU,UAAU;AAC1C,WAAM,gBAAgB;AACtB,WAAM,iBAAiB;AACvB,sBAAiB,MAAM,SAAS;MAChC;AACF,WAAO,iBAAiB,sBAAsB,gBAAgB,MAAM,SAAS,CAAC;AAC9E,WAAO,iBAAiB,sBAAsB;AAC5C,SAAI,yBAAyB,MAAM,SAAU,iBAAgB,KAAK;MAClE;AACF,qBAAiB;KACf;KACA,SAAS,EAAE,OAAO,EAAE,WAAW,kBAAkB,CAAC;KACnD;AACD,yBAAqB,IAAI,MAAM,UAAU,eAAe;AACxD,gBAAY,OAAO,eAAe,SAAS,eAAe,OAAO;;GAEnE,MAAM,EAAE,QAAQ,YAAY;GAC5B,MAAM,aAAa,QAAQ,YAAY,MAAM,YAAY,KAAK,MAAM,QAAQ,IACxE,KAAK,uBAAuB,MAAM,CAAC,WACnC;AACJ,UAAO,QAAQ,QAAQ,UAAU,MAAM,aAAa,QAAQ,aAAa,SAAS,WAAW,MAAM,MAAM;AACzG,UAAO,aAAa,cAAc,OAAO,MAAM;AAC/C,UAAO,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,KAAK,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;AAC1E,UAAO,MAAM,MAAM,GAAG,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,KAAK,SAAS,EAAE,CAAC;AACzE,UAAO,MAAM,aAAa,QAAQ,IAAI;AACtC,UAAO,MAAM,YAAY,kBAAkB,IAAI,qCAAqC,IAAI;AACxF,UAAO,cAAc,oBAAoB,aAAa;AACtD,UAAO,UAAU,OAAO,uBAAuB,MAAM;AACrD,UAAO,UAAU,OAAO,6BAA6B,YAAY;AAEjE,WAAQ,MAAM,OAAO,GAAG,MAAM,KAAK,KAAK;AACxC,WAAQ,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI;AACtC,WAAQ,MAAM,QAAQ,GAAG,MAAM,KAAK,MAAM;AAC1C,WAAQ,MAAM,SAAS,GAAG,MAAM,KAAK,OAAO;AAC5C,WAAQ,MAAM,cAAc,QAAQ,IAAI;AAGxC,WAAQ,MAAM,aAAa,yBAAyB,MAAM,WAAW,QAAQ,IAAI,qBAAqB;AACtG,WAAQ,UAAU,OAAO,wBAAwB,MAAM;AACvD,WAAQ,UAAU,OAAO,8BAA8B,YAAY;;AAErE,OAAK,MAAM,CAAC,KAAK,mBAAmB,qBAClC,KAAI,CAAC,iBAAiB,IAAI,IAAI,EAAE;AAC9B,kBAAe,OAAO,QAAQ;AAC9B,kBAAe,QAAQ,QAAQ;AAC/B,wBAAqB,OAAO,IAAI;;AAGpC,qBAAmB,OAAO;;CAG5B,SAAS,mBAAmB,QAA8B;EACxD,MAAM,QAAQ,4BAA4B,OACtC,OACA,OAAO,MAAM,cAAc,UAAU,aAAa,yBAAyB,IAAI;EACnF,MAAM,OAAO,OAAO,QAAQ;AAC5B,MAAI,SAAS,QAAQ,QAAQ,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAU,GAAG;AACxE,OAAI,wBAAwB,MAAM;AAChC,WAAO,aAAa,qBAAqB;AACzC,2BAAuB;;AAEzB,oBAAiB,UAAU,OAAO,4BAA4B,6BAA6B;AAC3F,+BAA4B;AAC5B;;AAGF,MADmB,iBAAiB,UAAU,SAAS,2BAA2B,IAChE,8BAA8B,MAAM,UAAU;AAI9D,oBAAiB,UAAU,IAAI,6BAA6B;AAC5D,OAAI,wBAAwB,KAAM,QAAO,aAAa,qBAAqB;AAC3E,0BAAuB,OAAO,iBAAiB;AAC7C,qBAAiB,UAAU,OAAO,6BAA6B;AAC/D,2BAAuB;MACtB,IAAI;;AAET,8BAA4B,MAAM;AAClC,mBAAiB,MAAM,OAAO,GAAG,KAAK,KAAK;AAC3C,mBAAiB,MAAM,MAAM,GAAG,KAAK,IAAI;AACzC,mBAAiB,MAAM,QAAQ,GAAG,KAAK,MAAM;AAC7C,mBAAiB,MAAM,SAAS,GAAG,KAAK,OAAO;AAC/C,mBAAiB,UAAU,IAAI,2BAA2B;;CAG5D,SAAS,WAAW,QAA8B;AAChD,MAAI,OAAO,WAAW,GAAG;AACvB,8BAA2B;AAC3B,QAAK,YAAY,MAAM;AACvB;;EAEF,MAAM,oBAAoB,KAAK;AAC/B,QAAM,QAAQ;EACd,MAAM,+BAAe,IAAI,KAAa;EACtC,IAAI,cAAgC,KAAK;AACzC,OAAK,MAAM,SAAS,OAAO,MAAM,GAAG,GAAG,EAAE;AACvC,gBAAa,IAAI,MAAM,SAAS;GAChC,IAAI,aAAa,gBAAgB,IAAI,MAAM,SAAS;AACpD,OAAI,cAAc,MAAM;AACtB,iBAAa,qBAAqB,MAAM,SAAS;AACjD,oBAAgB,IAAI,MAAM,UAAU,WAAW;;AAEjD,wBAAqB,YAAY,MAAM;AACvC,OAAI,WAAW,QAAQ,YACrB,MAAK,aAAa,WAAW,KAAK,YAAY;AAEhD,iBAAc,WAAW,IAAI;;AAE/B,OAAK,MAAM,CAAC,UAAU,eAAe,iBAAiB;AACpD,OAAI,aAAa,IAAI,SAAS,CAAE;AAChC,cAAW,IAAI,QAAQ;AACvB,mBAAgB,OAAO,SAAS;;AAElC,OAAK,YAAY;;CAKnB,IAAI,0BAA0B;CAC9B,SAAS,eAAe,QAA8B;EAIpD,MAAM,UAAU,OAAO,SAAS,KAAK,QAAQ,cAAc,MAAM,KAAK;AACtE,aAAW,UAAU,OAAO,8BAA8B,QAAQ;AAClE,MAAI,CAAC,QAAS;EACd,MAAM,gBAAgB,uBAAuB;EAC7C,MAAM,cAAc,gBAAgB,KAAK,OAAO,OAAO,UAAU,uBAAuB,IAAI,MAAM,SAAS,CAAC;AAC5G,kBAAgB,aAAa,gBAAgB,cAAc,SAAS,gBAAgB,IAAI,UAAU,QAAQ;AAC1G,kBAAgB,aAAa,cAAc,cAAc,oBAAoB,sBAAsB;EACnG,MAAM,kBAAkB,cAAc,eAAe,gBAAgB,IAAI,cAAc;AACvF,MAAI,4BAA4B,iBAAiB;AAC/C,6BAA0B;AAC1B,WAAQ,iBAAiB,gBAAgB;;AAE3C,oBAAkB,cAAc,gBAAgB,IAC5C,GAAG,oBAAoB,cAAc,CAAC,MAAM,oBAAoB,OAAO,OAAO,CAAC,aAC/E,GAAG,oBAAoB,OAAO,OAAO,CAAC,UAAU,OAAO,WAAW,IAAI,KAAK;EAC/E,MAAM,cAAc,qBAAqB;EACzC,MAAM,YAAY,gBAAgB,IAAI,aAAa;AACnD,iBAAe,cAAc,QAAQ;AACrC,iBAAe,cAAc,QAAQ;AAErC,iBAAe,WAAW,YAAY,OAAO,UAAU,CAAC,oBAAoB,IAAI,MAAM,SAAS,CAAC;AAChG,iBAAe,WAAW,YAAY,OAAO,UAAU,oBAAoB,IAAI,MAAM,SAAS,CAAC;;CAGjG,SAAS,SAAS;AAChB,MAAI,gBAAgB,OAAO,SAAS,UAAU;AAC5C,iBAAc,OAAO,SAAS;AAC9B,oBAAiB;IAAE,MAAM;IAAa,aAAa;IAAG,WAAW,EAAE;IAAE,UAAU,EAAE;IAAE;AACnF,yBAAsB;AACtB,8BAA2B;AAC3B,uBAAoB;AACpB,qBAAkB,oBAAoB,CAAC;;EAEzC,MAAM,SAAS,WAAW;AAC1B,iBAAe;EACf,MAAM,YAAY,IAAI,IAAI,OAAO,KAAK,UAAU,MAAM,SAAS,CAAC;AAChE,OAAK,MAAM,sBAAsB,oBAC/B,KAAI,CAAC,UAAU,IAAI,mBAAmB,CAAE,qBAAoB,OAAO,mBAAmB;AAExF,OAAK,MAAM,yBAAyB,uBAClC,KAAI,CAAC,UAAU,IAAI,sBAAsB,CAAE,wBAAuB,OAAO,sBAAsB;AAEjG,MAAI,2BAA2B,QAAQ,CAAC,UAAU,IAAI,wBAAwB,CAC5E,2BAA0B;AAE5B,MAAI,4BAA4B,QAAQ,CAAC,UAAU,IAAI,yBAAyB,CAC9E,4BAA2B;AAE7B,MAAI,wBAAwB,QAAQ,CAAC,UAAU,IAAI,qBAAqB,CACtE,wBAAuB;EAKzB,MAAM,eAAe,OAAO,QAAQ,KAAK,UAAU,MAAM,qBAAqB,MAAM,EAAE,EAAE;EACxF,MAAM,kBAAkB,eAAe,SAAS,cAAc,eAAe,cAAc;EAC3F,MAAM,WAAW,yBAAyB;EAC1C,MAAM,uBAAuB,KAAK,MAAM,SAAS,MAAM;EACvD,MAAM,wBAAwB,KAAK,MAAM,SAAS,OAAO;EACzD,MAAM,yBAAyB,0BAA0B,QAAQ,OAAO;EACxE,MAAM,wBAAwB,0BAA0B,QAAQ,gCAAgC,sBAAsB,uBAAuB;AAC7I,aAAW,cAAc,oBAAoB,gBAAgB;AAC7D,gBAAc,cAAc,oBAAoB,OAAO,OAAO;AAC9D,gBAAc,cAAc,GAAG,qBAAqB,GAAG;AACvD,gBAAc,cAAc,iBAAiB,iBAAiB;AAC9D,yBAAuB;AACvB,kBAAgB,UAAU,OAAO,mCAAmC,CAAC,sBAAsB;AAC3F,MAAI,0BAA0B,QAAQ,CAAC,uBAAuB;GAC5D,MAAM,mBAAmB,oCAAoC,uBAAuB;GACpF,MAAM,oBAAoB,KAAK,IAAI,GAAG,sBAAsB;AAC5D,wBAAqB,cAAc;AACnC,uBAAoB,cAAc,gBAAgB,qBAAqB,eAAe,QAAQ,OAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAChK,6BAA0B,cAAc,OAAO,iBAAiB;AAChE,8BAA2B,cAAc,OAAO,kBAAkB;;EAEpE,MAAM,sBAAsB,wBAAwB;EACpD,MAAM,wBAAwB,mBAAmB,qBAAqB,YAAY;AAGlF,iCAA+B;EAC/B,MAAM,QAAQ,6BAA6B;EAC3C,MAAM,cAAc,8BAA8B;AAClD,MAAI,SAAS,KACX,QAAO,cAAc,uBAAuB;WACnC,eAAe,QAAQ,gBAAgB,OAAO,SAAS,OAChE,QAAO,cAAc,wBAAwB,YAAY,qBAAqB,OAAO,SAAS,OAAO;WAC5F,sBACT,QAAO,cAAc;WACZ,uBAAuB,KAChC,QAAO,cAAc;OAChB;GACL,MAAM,QAAQ,wBAAwB,MAAM,wBAAwB,cAAc,sBAAsB;GACxG,IAAI,UAAU,UAAU,oBAAoB,gBAAgB,CAAC,wBAAwB,MAAM;AAC3F,OAAI,oBAAoB,EACtB,WAAU,0BAA0B,MAAM;YACjC,CAAC,sBAGV,YAAW;YACF,OAAO,WAAW,EAC3B,YAAW;YACF,eAAe,gBACxB,YAAW,IAAI,oBAAoB,aAAa,CAAC;AAEnD,UAAO,cAAc;;AAEvB,SAAO,UAAU,OAAO,6BAA6B,uBAAuB,QAAS,SAAS,QAAQ,eAAe,QAAQ,gBAAgB,OAAO,SAAS,OAAQ;AACrK,aAAW,cAAc,oBAAoB,gBAAgB;AAC7D,eAAa,cAAc,oBAAoB,OAAO,OAAO;AAC7D,YAAU,UAAU,OAAO,mBAAmB,SAAS;AACvD,eAAa,aAAa,iBAAiB,OAAO,SAAS,CAAC;AAC5D,eAAa,aAAa,cAAc,WAAW,8BAA8B,0BAA0B;AAC3G,eAAa,aAAa,gBAAgB,WAAW,8BAA8B,0BAA0B;AAC7G,kBAAgB;AAGhB,uBAAqB;AACrB,gBAAc,OAAO;AACrB,iBAAe,OAAO;AACtB,aAAW,OAAO;;CAGpB,eAAe,qBAAqB;EAClC,MAAM,YAAY,0BAA0B;AAC5C,4BAA0B;EAC1B,MAAM,wBAAwB,cAAc;EAC5C,MAAM,QAAQ,6BAA6B;AAC3C,MAAI,SAAS,MAAM;AACjB,oBAAiB;IAAE,MAAM;IAAa,aAAa;IAAG,WAAW,EAAE;IAAE,UAAU,EAAE;IAAE;AACnF,yBAAsB;AACtB,2BAAwB;AACxB,WAAQ;AACR;;EAEF,MAAM,cAAc,8BAA8B;AAClD,MAAI,eAAe,QAAQ,gBAAgB,OAAO,SAAS,QAAQ;AACjE,oBAAiB;IAAE,MAAM;IAAa,aAAa;IAAG,WAAW,EAAE;IAAE,UAAU,EAAE;IAAE;AACnF,yBAAsB;AACtB,2BAAwB;AACxB,WAAQ;AACR;;AAGF,0BAAwB;AACxB,wBAAsB;AACtB,UAAQ;AACR,MAAI;GACF,MAAM,wBAAQ,IAAI,MAAM;GACxB,MAAM,QAAQ,IAAI,KAAK,MAAM,SAAS,GAAG,kBAAkB,QAAQ,OAAO;GAC1E,MAAM,gBAAgB,OAAO,SAAS;GACtC,MAAM,sBAAsB,wBAAwB;GACpD,MAAM,OAAgC;IACpC,gBAAgB;IAChB,QAAQ,OAAO,SAAS;IACxB,OAAO,MAAM,aAAa;IAC1B,OAAO,MAAM,aAAa;IAC3B;AACD,OAAI,wBAAwB,GAC1B,MAAK,cAAc;OAEnB,MAAK,aAAa;AAEpB,OAAI,QAAQ,WAAW,MACrB,MAAK,SAAS,QAAQ;GAExB,MAAM,WAAW,MAAM,IAAI,4BAA4B,YAAY,uBAAuB;IACxF,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM,KAAK,UAAU,KAAK;IAC3B,EAAE,SAAS;AACZ,OAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,qCAAqC,SAAS,SAAS;GAEzE,MAAM,eAAwB,MAAM,SAAS,MAAM;AACnD,OAAI,CAAC,iBAAiB,CACpB;AAEF,oBAAiB,4BAA4B,cAAc,cAAc;WAClE,OAAO;AACd,OAAI,CAAC,iBAAiB,CACpB;AAEF,oBAAiB;IAAE,MAAM;IAAa,aAAa;IAAG,WAAW,EAAE;IAAE,UAAU,EAAE;IAAE;AACnF,OAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,iDAAiD,EAAE;AACtG,+BAA2B;AAC3B,0BAAsB;SAEtB,uBAAsB,iBAAiB,QAAQ,MAAM,UAAU;YAEzD;AACR,OAAI,iBAAiB,EAAE;AACrB,4BAAwB;AACxB,YAAQ;;;;CAQd,MAAM,6BAA6B;EACjC,MAAM,QAAQ,6BAA6B;EAC3C,MAAM,cAAc,8BAA8B;AAClD,MAAI,SAAS,QAAS,eAAe,QAAQ,gBAAgB,OAAO,SAAS,OAC3E;AAEF,MAAI;AACF,kBAAe,QAAQ,qCAAqC,IAAI;UAC1D;;CAYV,MAAM,oBAAoB,WAA8B;AACtD,SAAO,iBAAiB,gBAAgB,UAAU;AAChD,OAAI;AACF,WAAO,kBAAkB,MAAM,UAAU;WACnC;IAIR;;AAEJ,kBAAiB,cAAc;AAC/B,kBAAiB,YAAY;AAC7B,kBAAiB,aAAa;AAC9B,kBAAiB,mBAAmB;AACpC,kBAAiB,eAAe;AAChC,kBAAiB,kBAAkB;AACnC,kBAAiB,gBAAgB;AACjC,kBAAiB,eAAe;AAChC,kBAAiB,eAAe;AAChC,eAAc,iBAAiB,eAAe;AAC5C,mBAAiB,CAAC;AAClB,UAAQ;GACR;AACF,aAAY,iBAAiB,SAAS,QAAQ;AAC9C,cAAa,iBAAiB,eAAe;AAC3C,aAAW,CAAC;AACZ,UAAQ;GACR;CACF,MAAM,uBAAuB;AAC3B,oBAAkB,oBAAoB,CAAC;;CAEzC,MAAM,oBAAoB,OAAO,YAAY,gBAAgB,IAAI;CAMjE,MAAM,wBAAwB,WAAiC;EAC7D,MAAM,UAAU,kBAAkB,UAAU,SAAS,QAAQ,iBAAiB;AAC9E,MAAI,WAAW,KAAM,QAAO;AAC5B,SAAO,YAAY,SAAS,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe,iBAAiB,CAAC,KAAK,eAAe,iBAAiB,GAAG,IAAI;;CAE3I,MAAM,mBAAmB,IAAI,kBAAkB,cAAc;AAC3D,MAAI,UAAU,OAAO,aAAa,qBAAqB,SAAS,OAAO,CAAC,CACtE;AAEF,gCAA8B;AAC9B,kBAAgB;GAChB;CACF,MAAM,iBAAiB,OAAO;AAC9B,kBAAiB,QAAQ,SAAS,MAAM;EAAE,YAAY;EAAM,WAAW;EAAM,SAAS;EAAM,CAAC;AAQ7F,EAAC,SAAS,eAAe,iBAAiB,IAAI,SAAS,MAAM,YAAY,YAAY;AACrF,kBAAiB;AACjB,iBAAgB;AAChB,QAAO,iBAAiB,gBAAgB,qBAAqB;CAC7D,MAAM,uBAAuB;AAC3B,kBAAgB;;AAElB,UAAS,iBAAiB,UAAU,gBAAgB,KAAK;AACzD,QAAO,iBAAiB,UAAU,eAAe;AACjD,iBAAgB,iBAAiB,UAAU,eAAe;AAC1D,iBAAgB,iBAAiB,UAAU,eAAe;AAC1D,QAAO,iBAAiB,sCAAsC,eAAe;CAE7E,MAAM,yBAAyB,UAAsB;AACnD,MAAI,CAAC,YAAa;AAClB,MAAI,MAAM,kBAAkB,QAAQ,eAAe,SAAS,MAAM,OAAO,CAAE;AAC3E,MAAI,MAAM,kBAAkB,QAAQ,eAAe,SAAS,MAAM,OAAO,CAAE;AAC3E,iBAAe,MAAM;;CAEvB,MAAM,qBAAqB,UAAyB;AAClD,MAAI,MAAM,QAAQ,SAAU;AAC5B,MAAI,aAAa;AACf,kBAAe,MAAM;AACrB;;AAEF,kBAAgB;;AAElB,UAAS,iBAAiB,aAAa,uBAAuB,KAAK;AACnE,UAAS,iBAAiB,WAAW,mBAAmB,KAAK;AAC7D,SAAQ;AACR,mBAAkB,oBAAoB,CAAC;AAEvC,WAAU,OAAO,SAAS,QAAQ;AAClC,QAAO;EACL,SAAS;EACT,eAAe;AACb,wBAAqB,YAAY;AACjC,OAAI,qBAAqB,EAAG,QAAO,aAAa,iBAAiB;AACjE,OAAI,yBAAyB,EAAG,QAAO,aAAa,qBAAqB;AACzE,OAAI,0BAA0B,EAAG,QAAO,aAAa,sBAAsB;AAC3E,UAAO,cAAc,kBAAkB;AACvC,oBAAiB,YAAY;AAC7B,iCAA8B;AAC9B,YAAS,OAAO;AAChB,UAAO,oBAAoB,gBAAgB,qBAAqB;AAChE,YAAS,oBAAoB,UAAU,gBAAgB,KAAK;AAC5D,UAAO,oBAAoB,UAAU,eAAe;AACpD,mBAAgB,oBAAoB,UAAU,eAAe;AAC7D,mBAAgB,oBAAoB,UAAU,eAAe;AAC7D,UAAO,oBAAoB,sCAAsC,eAAe;AAChF,YAAS,oBAAoB,aAAa,uBAAuB,KAAK;AACtE,YAAS,oBAAoB,WAAW,mBAAmB,KAAK;AAChE,eAAY,QAAQ;;EAEvB;;AAOH,MAAM,sBAAsB;;;;;;;;;AAU5B,SAAgB,oBAAoB,KAA2B,UAAkC;AAC/F,KAAI,OAAO,aAAa,eAAe,OAAO,SAAS,kBAAkB,WACvE,cAAa;CAEf,MAAM,OAAO,QAAQ,IAAI,UAAU,OAAO;AAC1C,KAAI,CAAC,eAAe,KAAK,CAAE,cAAa;AAExC,qBAAoB,oBAAoB,EAAE,SAAS;CACnD,IAAI,eAAe,SAAS,eAAe,iBAAiB;AAC5D,QAAO,iBAAiB,MAAM;AAC5B,eAAa,QAAQ;AACrB,iBAAe,SAAS,eAAe,iBAAiB;;CAG1D,MAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,MAAK,KAAK;AACV,MAAK,YAAY,KAAK;CAEtB,MAAM,UAAU,EAAE,OAAO,EAAE,WAAW,qBAAqB,CAAC;AAC5D,MAAK,YAAY,QAAQ;CAEzB,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,cAAc;AACpB,SAAQ,YAAY,MAAM;CAE1B,MAAM,QAAQ,oBAAoB,WAAW,SAAS,SAAS,CAAC;AAChE,SAAQ,YACN,EAAE,OAAO,EAAE,WAAW,gBAAgB,EACpC,EAAE,OAAO,EAAE,WAAW,sBAAsB,EAAE,MAAM,QAAQ,CAC7D,CACF;CAED,IAAI,aAAa;CACjB,MAAM,WAA6B,EACjC,eAAe;AACb,MAAI,WAAY;AAChB,eAAa;AACb,MAAI,oBAAoB,oBAAoB,KAAK,SAC/C,qBAAoB,qBAAqB,KAAK;AAEhD,QAAM,WAAW;AACjB,MAAI,KAAK,WACP,MAAK,WAAW,YAAY,KAAK;AAEnC,YAAU;IAEb;AACD,qBAAoB,qBAAqB,SAAS;AAElD,cAAa;AACX,WAAS,SAAS"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickmap-styles.d.ts","names":[],"sources":["../../../src/clickmap/clickmap-styles.ts"],"mappings":";cAgBa,WAAA"}
|