@seatlayer/core 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{de-HLJXYBWA.js → de-KPTY7UOT.js} +6 -2
- package/dist/{de-HLJXYBWA.js.map → de-KPTY7UOT.js.map} +1 -1
- package/dist/{es-LDI3FESI.js → es-ALPR5FBB.js} +6 -2
- package/dist/{es-LDI3FESI.js.map → es-ALPR5FBB.js.map} +1 -1
- package/dist/{fr-H4KTK4F5.js → fr-HVQLQD2N.js} +6 -2
- package/dist/{fr-H4KTK4F5.js.map → fr-HVQLQD2N.js.map} +1 -1
- package/dist/index.cjs +67 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -6
- package/dist/index.d.ts +26 -6
- package/dist/index.js +48 -7
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/i18n/locales/es.ts","../src/i18n/locales/de.ts","../src/i18n/locales/fr.ts","../src/index.ts","../src/core/types.ts","../src/core/complexGeometry.ts","../src/core/sectionPath.ts","../src/core/layout.ts","../src/core/ga.ts","../src/core/sections.ts","../src/engine/SeatmapRenderer.ts","../src/core/chartRenderRules.ts","../src/lib/money.ts","../src/i18n/locales/en.ts","../src/i18n/index.ts","../src/core/orphans.ts","../src/picker/PickerController.ts","../src/view/generatePanorama.ts","../src/i18n/bundles.ts"],"sourcesContent":["/**\n * Spanish (es) bundle — neutral/international Spanish translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const es: Dict = {\n // shared\n 'common.cancel': 'Cancelar',\n 'common.close': 'Cerrar',\n 'common.done': 'Listo',\n 'common.copied': '✓ Copiado',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Retener asientos y comprar',\n 'picker.completeBooking': 'Completar reserva',\n 'picker.seatsHeld': 'Asientos retenidos — {time}',\n 'picker.holdExpired': 'Tu retención expiró — los asientos fueron liberados. Elige de nuevo.',\n 'picker.seatTaken': 'El asiento {label} fue tomado por otro comprador.',\n 'picker.poweredBy': 'Con la tecnología de SeatLayer',\n 'picker.testMode': 'MODO DE PRUEBA',\n 'picker.colorblind': 'Colores aptos para daltonismo',\n 'picker.orphanHint': 'Esto deja un asiento aislado — considera desplazarte un asiento.',\n 'picker.seats.one': '{count} asiento',\n 'picker.seats.other': '{count} asientos',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.statusHeld': 'En espera',\n 'map.statusTaken': 'Ocupado',\n 'map.fromPrice': 'DESDE {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Idioma',\n 'picker.zoomToFit': 'Ajustar zoom',\n 'picker.seatCountLabel': 'asientos',\n 'picker.capacity': 'capacidad',\n 'picker.viewMode': 'Modo de vista',\n 'picker.floor': 'Piso',\n 'picker.zoomLevel': 'Nivel de zoom',\n 'picker.rungTip.zones': 'Vista general — grupos de secciones como Grada norte o VIP',\n 'picker.rungTip.sections': 'Bloques de sección — mezcla de categorías + matiz de disponibilidad',\n 'picker.rungTip.seats': 'Asientos individuales — los bloques se convierten en puntos',\n 'picker.rungLabel.zones': 'ZONAS',\n 'picker.rungLabel.sections': 'SECCIONES',\n 'picker.rungLabel.seats': 'ASIENTOS',\n 'picker.sectionSummaryAria': 'Resumen de sección {label}',\n 'picker.closeSectionSummary': 'Cerrar resumen de sección',\n 'picker.seatsLeftInSection.one': '{count} asiento disponible',\n 'picker.seatsLeftInSection.other': '{count} asientos disponibles',\n 'picker.overview': 'Descripción general',\n 'picker.tapSeatHint': 'Toca cualquier asiento para ver su vista',\n 'picker.chartSize': 'Tamaño del gráfico',\n 'picker.custom': 'Personalizado',\n 'picker.categories': 'Categorías',\n 'picker.accessibility': 'Accesibilidad',\n 'picker.showAnyAccessible': 'Mostrar cualquier asiento accesible',\n 'picker.any': 'Cualquiera',\n 'picker.yourSeats': 'Tus asientos',\n 'picker.emptySeats': 'Toca asientos en el mapa',\n 'picker.emptySeatsWithGa': 'Toca asientos en el mapa · toca un área de pie para entradas de entrada general',\n 'picker.oneFewer': 'Uno menos',\n 'picker.oneMore': 'Uno más',\n 'picker.remove': 'Eliminar {label}',\n 'picker.ticketTierFor': 'Categoría de entrada para {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'Vista desde el asiento {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VISTA PREVIA',\n 'picker.open360': 'Abrir vista de 360°',\n 'picker.sightline': '≈ {m} m al escenario · visión despejada',\n 'picker.bookedDemo': '¡Reservado! (demostración)',\n 'picker.bookButton.one': 'Reservar {count} entrada — {amount}',\n 'picker.bookButton.other': 'Reservar {count} entradas — {amount}',\n 'picker.simulateCrowd': 'Simular multitud: {state}',\n 'picker.on': 'ACTIVADO',\n 'picker.off': 'DESACTIVADO',\n 'picker.panorama360': 'Foto de 360° del lugar',\n 'picker.illustrationCaption': 'ilustración · ≈ {m} m del escenario',\n};\n","/**\n * German bundle — native-quality translations of the English reference dictionary.\n * Keys are identical to en.ts; values are translated to German (de).\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const de: Dict = {\n // shared\n 'common.cancel': 'Abbrechen',\n 'common.close': 'Schließen',\n 'common.done': 'Fertig',\n 'common.copied': '✓ Kopiert',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Plätze reservieren & Kasse',\n 'picker.completeBooking': 'Buchung abschließen',\n 'picker.seatsHeld': 'Plätze reserviert — {time}',\n 'picker.holdExpired': 'Ihre Reservierung ist abgelaufen — die Plätze wurden freigegeben. Bitte erneut auswählen.',\n 'picker.seatTaken': 'Platz {label} wurde gerade von einem anderen Käufer gebucht.',\n 'picker.poweredBy': 'Bereitgestellt von SeatLayer',\n 'picker.testMode': 'TESTMODUS',\n 'picker.colorblind': 'Farbenblind-freundliche Farben',\n 'picker.orphanHint': 'Dadurch bleibt ein einzelner Platz übrig — rücken Sie ggf. einen Platz weiter.',\n 'picker.seats.one': '{count} Platz',\n 'picker.seats.other': '{count} Plätze',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Sitzplan. Mit Pfeiltasten zwischen Plätzen navigieren, Eingabe zum Auswählen.',\n 'map.seatsLeft': '{count} FREI',\n 'map.statusHeld': 'Reserviert',\n 'map.statusTaken': 'Vergeben',\n 'map.fromPrice': 'AB {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Sprache',\n 'picker.zoomToFit': 'Auf Größe anpassen',\n 'picker.seatCountLabel': 'Plätze',\n 'picker.capacity': 'Kapazität',\n 'picker.viewMode': 'Ansichtsmodus',\n 'picker.floor': 'Etage',\n 'picker.zoomLevel': 'Zoomstufe',\n 'picker.rungTip.zones': 'Übersicht — Bereichsgruppen wie Nordtribüne oder VIP',\n 'picker.rungTip.sections': 'Bereichs-Blöcke — Kategoriesortierung + Verfügbarkeitstönung',\n 'picker.rungTip.seats': 'Einzelne Plätze — Blöcke lösen sich zu Punkten auf',\n 'picker.rungLabel.zones': 'ZONEN',\n 'picker.rungLabel.sections': 'BEREICHE',\n 'picker.rungLabel.seats': 'PLÄTZE',\n 'picker.sectionSummaryAria': 'Bereichszusammenfassung {label}',\n 'picker.closeSectionSummary': 'Bereichszusammenfassung schließen',\n 'picker.seatsLeftInSection.one': '{count} Platz verfügbar',\n 'picker.seatsLeftInSection.other': '{count} Plätze verfügbar',\n 'picker.overview': 'Übersicht',\n 'picker.tapSeatHint': 'Tippen Sie auf einen Platz, um die Ansicht zu prüfen',\n 'picker.chartSize': 'Kartengröße',\n 'picker.custom': 'Benutzerdefiniert',\n 'picker.categories': 'Kategorien',\n 'picker.accessibility': 'Barrierefreiheit',\n 'picker.showAnyAccessible': 'Jeden barrierefreien Platz anzeigen',\n 'picker.any': 'Beliebig',\n 'picker.yourSeats': 'Ihre Plätze',\n 'picker.emptySeats': 'Tippen Sie auf die Plätze auf der Karte',\n 'picker.emptySeatsWithGa': 'Tippen Sie auf die Plätze auf der Karte · tippen Sie auf einen Stehbereich für Stehplatztickets',\n 'picker.oneFewer': 'Einen weniger',\n 'picker.oneMore': 'Einen mehr',\n 'picker.remove': '{label} entfernen',\n 'picker.ticketTierFor': 'Ticketklasse für {label}',\n 'picker.total': 'Gesamt: {amount}',\n 'picker.viewFromSeat': 'Ansicht von Platz {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VORSCHAU',\n 'picker.open360': 'Öffnen Sie die 360°-Ansicht',\n 'picker.sightline': '≈ {m} m zur Bühne · freie Sicht',\n 'picker.bookedDemo': 'Gebucht! (Demo)',\n 'picker.bookButton.one': '{count} Ticket buchen — {amount}',\n 'picker.bookButton.other': '{count} Tickets buchen — {amount}',\n 'picker.simulateCrowd': 'Menschenmenge simulieren: {state}',\n 'picker.on': 'AN',\n 'picker.off': 'AUS',\n 'picker.panorama360': '360°-Veranstaltungsfotos',\n 'picker.illustrationCaption': 'Illustration · ≈ {m} m von der Bühne',\n};\n","/**\n * French (fr) bundle — native French translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const fr: Dict = {\n // shared\n 'common.cancel': 'Annuler',\n 'common.close': 'Fermer',\n 'common.done': 'Terminé',\n 'common.copied': '✓ Copié',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Réserver les sièges et valider',\n 'picker.completeBooking': 'Terminer la réservation',\n 'picker.seatsHeld': 'Sièges réservés — {time}',\n 'picker.holdExpired': 'Votre réservation a expiré — les sièges ont été libérés. Sélectionnez à nouveau.',\n 'picker.seatTaken': 'Le siège {label} vient d\\'être réservé par un autre acheteur.',\n 'picker.poweredBy': 'Propulsé par SeatLayer',\n 'picker.testMode': 'MODE TEST',\n 'picker.colorblind': 'Couleurs adaptées au daltonisme',\n 'picker.orphanHint': \"Cela laisse un siège isolé — pensez à vous décaler d'un siège.\",\n 'picker.seats.one': '{count} siège',\n 'picker.seats.other': '{count} sièges',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Plan de salle. Utilisez les flèches pour naviguer entre les sièges, Entrée pour sélectionner.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.statusHeld': 'En attente',\n 'map.statusTaken': 'Pris',\n 'map.fromPrice': 'DÈS {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Langue',\n 'picker.zoomToFit': 'Ajuster le zoom',\n 'picker.seatCountLabel': 'sièges',\n 'picker.capacity': 'capacité',\n 'picker.viewMode': 'Mode d\\'affichage',\n 'picker.floor': 'Étage',\n 'picker.zoomLevel': 'Niveau de zoom',\n 'picker.rungTip.zones': 'Vue générale — groupes de sections comme Tribune nord ou VIP',\n 'picker.rungTip.sections': 'Blocs de sections — mélange de catégories + teinte de disponibilité',\n 'picker.rungTip.seats': 'Sièges individuels — les blocs se transforment en points',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SIÈGES',\n 'picker.sectionSummaryAria': 'Résumé de la section {label}',\n 'picker.closeSectionSummary': 'Fermer le résumé de la section',\n 'picker.seatsLeftInSection.one': '{count} siège restant',\n 'picker.seatsLeftInSection.other': '{count} sièges restants',\n 'picker.overview': 'Vue d\\'ensemble',\n 'picker.tapSeatHint': 'Appuyez sur un siège pour vérifier sa vue',\n 'picker.chartSize': 'Taille du plan',\n 'picker.custom': 'Personnalisé',\n 'picker.categories': 'Catégories',\n 'picker.accessibility': 'Accessibilité',\n 'picker.showAnyAccessible': 'Afficher un siège accessible',\n 'picker.any': 'N\\'importe quel',\n 'picker.yourSeats': 'Vos sièges',\n 'picker.emptySeats': 'Appuyez sur les sièges sur le plan',\n 'picker.emptySeatsWithGa': 'Appuyez sur les sièges sur le plan · appuyez sur une zone debout pour les billets GA',\n 'picker.oneFewer': 'Un de moins',\n 'picker.oneMore': 'Un de plus',\n 'picker.remove': 'Supprimer {label}',\n 'picker.ticketTierFor': 'Catégorie de billet pour {label}',\n 'picker.total': 'Total : {amount}',\n 'picker.viewFromSeat': 'Vue depuis le siège {label}',\n 'picker.real360': 'VRAI 360°',\n 'picker.preview': 'APERÇU',\n 'picker.open360': 'Ouvrir la vue à 360°',\n 'picker.sightline': '≈ {m} m de la scène · vue dégagée',\n 'picker.bookedDemo': 'Réservé ! (démo)',\n 'picker.bookButton.one': 'Réserver {count} billet — {amount}',\n 'picker.bookButton.other': 'Réserver {count} billets — {amount}',\n 'picker.simulateCrowd': 'Simuler la foule : {state}',\n 'picker.on': 'ACTIVÉ',\n 'picker.off': 'DÉSACTIVÉ',\n 'picker.panorama360': 'Photo panoramique 360° du lieu',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m de la scène',\n};\n","/**\n * @seatlayer/core — the shared, framework-agnostic seat-rendering engine.\n *\n * Pure TypeScript + Konva (HTML canvas). No React, no framework. This is the\n * brain shared by the SeatLayer dashboard and every SDK wrapper. It is synced\n * byte-for-byte from the main app via `scripts/sync-core.mjs` until the app\n * migrates to consume this package directly.\n */\nexport * from './core/types';\nexport * from './core/layout';\nexport * from './core/ga';\nexport * from './core/sections';\nexport * from './engine/SeatmapRenderer';\nexport * from './picker/PickerController';\nexport * from './view/generatePanorama';\nexport * from './i18n';\nexport * from './i18n/bundles';\nexport * from './lib/money';\n","/**\n * SeatMap chart document — the single source of truth shared by the\n * Designer (authoring) and the Renderer (buyer picker).\n *\n * Mirrors docs/seatmap-build-spec.md §5. Coordinates are abstract units\n * (roughly \"pixels at scale 1\"); the renderer fits the chart to its container.\n * Rows are PARAMETRIC (origin + count + spacing + curve + rotation) — never\n * store per-seat coordinates in the document; expansion happens in layout.ts.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface CubicPath {\n start: Point;\n control1: Point;\n control2: Point;\n end: Point;\n}\n\n/** A real closed section boundary. `outline` remains its sampled collision and\n * persistence fallback; this path is the smooth authoring/buyer paint source. */\nexport type SectionPathSegment =\n | { kind: 'line'; end: Point }\n | { kind: 'arc'; center: Point; radius: number; clockwise: boolean; end: Point }\n | { kind: 'bezier'; control1: Point; control2: Point; end: Point };\n\nexport interface SectionOutlinePath {\n version: 1;\n closed: true;\n start: Point;\n segments: SectionPathSegment[];\n}\n\nexport interface Category {\n key: string;\n label: string;\n color: string;\n /** Base price — used when the category has no explicit tiers. */\n price?: number;\n /** Durable evidence for semantic/display facts proposed while converting a\n * private reference into sellable inventory. */\n referenceCategorySource?: ReferenceCategorySource;\n /**\n * Ticket tiers (Adult / Child / Senior…). When present, a buyer picks a tier\n * per seat in this category and the tier's price applies; the first tier is the\n * default. Per-category (not per-seat) pricing — see Batch 3.5. Empty/absent =\n * a single price (the `price` above).\n */\n tiers?: CategoryTier[];\n}\n\nexport interface ReferenceCategorySource {\n assetId: string;\n /** Original sampled section color. `Category.color` is the approved output\n * color and may differ only with separately recorded evidence. */\n sourceColor: string;\n /** Every exact sampled color normalized into the same original 4-bit/channel\n * segmentation class. Older documents may contain only `sourceColor`. */\n sourceColors?: string[];\n /** Logical sections whose generated inventory uses this category. */\n logicalSectionIds?: string[];\n /** Source-color grouping is deterministic; a semantic regrouping needs its\n * own confirmed assignment evidence. */\n assignmentDerivation?: 'source-color-class' | 'confirmed-logical-sections';\n assignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription?: string;\n /** Optional legend/commercial swatch stated by the source. This remains\n * immutable provenance when the approved accessible output color differs. */\n sourcePaletteColor?: string;\n sourcePaletteColorEvidence?: 'user-confirmed' | 'authoritative-source';\n sourcePaletteColorSourceDescription?: string;\n labelEvidence: 'user-confirmed' | 'authoritative-source';\n labelSourceDescription: string;\n priceEvidence: 'user-confirmed' | 'authoritative-source';\n priceSourceDescription: string;\n outputColorEvidence?: 'user-confirmed' | 'authoritative-source';\n outputColorSourceDescription?: string;\n}\n\n/** One ticket tier within a category: a named price (Adult, Child, Senior…). */\nexport interface CategoryTier {\n id: string;\n name: string;\n price: number;\n}\n\n/**\n * Accessibility accommodations a seat can carry. Mirrors the taxonomy real\n * venues (and seats.io) expose so buyers can filter for exactly what they need\n * and organizers can mark seats precisely. `wheelchair` is the legacy default.\n */\nexport type AccessibilityType =\n | 'wheelchair'\n | 'companion'\n | 'semi-ambulatory'\n | 'hearing'\n | 'sign-language'\n | 'plus-size'\n | 'lift-armrest';\n\nexport interface AccessibilityMeta {\n key: AccessibilityType;\n /** Full descriptive label (designer checkbox, picker legend). */\n label: string;\n /** Compact label for chips/badges. */\n short: string;\n /** Single-glyph badge shown on seat chips + filter chips. */\n icon: string;\n}\n\n/** Ordered taxonomy — drives the designer seat panel and the picker filters. */\nexport const ACCESSIBILITY_TYPES: AccessibilityMeta[] = [\n { key: 'wheelchair', label: 'Wheelchair space', short: 'Wheelchair', icon: '♿' },\n { key: 'companion', label: 'Companion seat', short: 'Companion', icon: '🧑🤝🧑' },\n { key: 'semi-ambulatory', label: 'Semi-ambulatory (limited mobility)', short: 'Limited mobility', icon: '🦯' },\n { key: 'hearing', label: 'Assistive listening', short: 'Hearing', icon: '🦻' },\n { key: 'sign-language', label: 'Sign-language view', short: 'Sign language', icon: '🤟' },\n { key: 'plus-size', label: 'Plus-size seat', short: 'Plus-size', icon: '💺' },\n { key: 'lift-armrest', label: 'Lift-up armrest', short: 'Lift armrest', icon: '↕️' },\n];\n\nconst ACCESSIBILITY_LABEL = new Map(ACCESSIBILITY_TYPES.map((a) => [a.key, a]));\n\n/** Metadata for one accessibility key (undefined for unknown keys). */\nexport function accessibilityMeta(key: AccessibilityType): AccessibilityMeta | undefined {\n return ACCESSIBILITY_LABEL.get(key);\n}\n\n/**\n * Outer-ring colour per accommodation. Shared by the buyer picker and the\n * designer canvas so an accessible seat reads with the same hue in both — the\n * seat's first-listed type wins. `wheelchair` blue is the default fallback.\n */\nexport const ACCESSIBILITY_RING_COLOR: Record<AccessibilityType, string> = {\n wheelchair: '#3b82f6',\n companion: '#8b5cf6',\n 'semi-ambulatory': '#0ea5e9',\n hearing: '#14b8a6',\n 'sign-language': '#f59e0b',\n 'plus-size': '#ec4899',\n 'lift-armrest': '#22c55e',\n};\n\n/** Ring colour for a seat's accessibility set (first-listed type wins). */\nexport function accessibilityRingColor(types: AccessibilityType[] | undefined): string {\n const primary = types?.[0];\n return (primary && ACCESSIBILITY_RING_COLOR[primary]) || '#3b82f6';\n}\n\nexport interface SeatOverride {\n /** 0-based seat index within the row. */\n index: number;\n /** Physical seat absent (pillar, sound desk) — numbering gap preserved. */\n skip?: boolean;\n /** Position nudge in chart units. */\n dx?: number;\n dy?: number;\n /** Replace the computed label entirely. */\n label?: string;\n /** Buyer-facing copy only. Booking/API identity remains row id + slot index\n * internally and the legacy `label` externally for backwards compatibility. */\n displayLabel?: string;\n categoryKey?: string;\n /** @deprecated legacy flag — read as `['wheelchair']`; write `accessibility`. */\n accessible?: boolean;\n /** Accessibility accommodations of this seat (empty/absent = none). */\n accessibility?: AccessibilityType[];\n /** Commercial selling/view attributes are deliberately not accessibility. */\n commercial?: SeatCommercialAttributes;\n /** Seat-specific view photo; falls back to the row photo. */\n viewFromSeatUrl?: string;\n /** Per-seat label size/color override; falls back to the row/theme default.\n * Size is clamped to LABEL_STYLE_MIN_SIZE..MAX_SIZE; color is passed through\n * the shared auto-contrast rule at paint time (see {@link LabelStyle}). */\n labelStyle?: LabelStyle;\n}\n\nexport interface SeatCommercialAttributes {\n restrictedView?: boolean;\n obstructedView?: boolean;\n premium?: boolean;\n note?: string;\n}\n\n/**\n * Per-object label ink + size overrides layered on top of the chart-wide Theme\n * defaults (rowLabelColor / textColor for rows, the section-name ink for\n * sections). Both fields are optional: an absent field means \"inherit the theme\n * default\". `color` is a preferred hex — renderers still pass it through the\n * shared auto-contrast rule (`stateAwareBookableLabelInk`), so a choice that\n * would be illegible over the seat/section background is switched to black or\n * white at paint time. `size` is a font size in chart units, clamped to\n * LABEL_STYLE_MIN_SIZE..LABEL_STYLE_MAX_SIZE by the shared ops.\n */\nexport interface LabelStyle {\n size?: number;\n color?: string;\n}\n\n/** Clamp bounds for a per-object label `size`, shared by ops, MCP, and UI. */\nexport const LABEL_STYLE_MIN_SIZE = 8;\nexport const LABEL_STYLE_MAX_SIZE = 24;\n\nexport interface LabelPresentation {\n visible?: boolean;\n /** Exact Designer-owned label anchor; public semantic MCP schemas omit it. */\n position?: Point;\n rotation?: number;\n style?: 'plain' | 'pill';\n /** Per-object size/color override for this row's or section's label. */\n labelStyle?: LabelStyle;\n}\n\n/** Brand/venue theming — applied by the renderer in both designer and picker. */\nexport interface ChartTheme {\n /** Canvas background color (default dark: #0e1117-ish radial). */\n background?: string;\n /** Preferred text color for the numbers inside seat markers. */\n seatLabelColor?: string;\n /** Preferred color for row identifiers such as A, B, C. Falls back to textColor. */\n rowLabelColor?: string;\n /** Selection ring / accent color (default white ring + brand accent). */\n selectionColor?: string;\n /** Décor (stage/shape) default fill. */\n decorFill?: string;\n /** Free-text color default. */\n textColor?: string;\n /** Font family (CSS stack) for all rendered text — row labels, seat numbers, sections, décor text. */\n fontFamily?: string;\n /** Seat size multiplier on the base radius (0.7–1.6, default 1) — bigger seats fit longer labels. */\n seatScale?: number;\n // ---- White-label branding (applied by the buyer picker chrome) ----\n /** Brand accent color — recolors buttons, links, the hold pill, selection UI. */\n accent?: string;\n /** Ink color for text on the accent (e.g. button labels). Default light. */\n accentInk?: string;\n /** Organizer logo shown in the picker header (data/R2 URL). Falls back to the name. */\n logoUrl?: string;\n /** Brand/venue name shown in the picker header when no event name is set. */\n brandName?: string;\n /** Paid-tier flag: hide the \"Powered by SeatMap\" badge. */\n hideBadge?: boolean;\n}\n\nexport interface RowObject {\n type: 'row';\n id: string;\n /** Row label, e.g. \"A\". Seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing row name. `label` remains the legacy inventory prefix. */\n displayLabel?: string;\n labelPresentation?: LabelPresentation;\n /** Position of the FIRST seat. */\n origin: Point;\n /** Degrees, clockwise. 0 = seats laid out along +x. */\n rotation: number;\n /**\n * Total arc sweep in degrees across the whole row. 0 = straight.\n * Positive bends away from +y (concave toward the focal point when the\n * row faces it). Typical theatre rows: 10–40.\n */\n curve: number;\n seatCount: number;\n /** Distance between adjacent seat centers, in chart units. */\n seatSpacing: number;\n /** Optional exact cubic centreline. Normal code owns these coordinates and\n * distributes seats by arc length; MCP/model inputs never submit them. */\n path?: CubicPath;\n categoryKey: string;\n /** Deterministic provenance for rows fitted from confirmed reference\n * inventory. It enables revision-safe replacement without touching manually\n * authored rows or accepting client coordinates. */\n referenceInventorySource?: ReferenceInventorySource;\n /** Semantic parameters for a row produced by the shared Arc/Fan operation.\n * Designer can reopen these parameters while every segment in the group\n * still carries the same generation signature. Public MCP tools never accept\n * the stored center/angles as arbitrary model-authored coordinates. */\n arcFanGeneration?: {\n kind: 'arc-fan-v1';\n groupId: string;\n center: Point;\n innerRadius: number;\n rowCount: number;\n rowGap: number;\n startAngle: number;\n endAngle: number;\n seatPitch: number;\n fit: 'seat-pitch' | 'fixed-count';\n seatsPerRow?: number;\n facing: 'inward' | 'outward';\n taperDegrees: number;\n skewDegrees: number;\n aisleGaps: { left: number; center: number; right: number };\n rowLabelStart: number;\n seatLabelStart: number;\n rowIndex: number;\n segmentIndex: number;\n };\n /** First seat number (default 1). */\n seatLabelStart?: number;\n /** Seat numbering within the row (default ltr, step 1). */\n seatNumbering?: {\n /** ltr / rtl number from an end; `center` numbers outward from the middle\n * (centre seat lowest — the premium-centre theatre convention). */\n direction: 'ltr' | 'rtl' | 'center';\n /** 2 = odd/even numbering (1,3,5… — start at 2 for evens). */\n step?: 1 | 2;\n };\n /**\n * Per-seat exceptions, keyed by seat index (0-based position in the row).\n * `skip` removes the physical seat but keeps the numbering gap (theatre\n * convention: a pillar eats A-3; A-4 stays A-4).\n */\n overrides?: SeatOverride[];\n /**\n * Organizer-supplied equirectangular 360 (or wide photo) shown as the\n * view-from-seat for every seat in this row. When absent, the picker\n * generates a synthetic panorama from chart geometry.\n */\n viewFromSeatUrl?: string;\n /** Default commercial attributes inherited by seats without an override. */\n commercial?: SeatCommercialAttributes;\n}\n\nexport interface GAAreaObject {\n type: 'gaArea';\n id: string;\n label: string;\n /** Closed polygon, in chart units. */\n points: Point[];\n /** Explicit aisles/pillars/cutouts excluded from the sellable GA surface. */\n holes?: Point[][];\n capacity: number;\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * Durable evidence link for sellable objects generated from a private reference.\n * The client supplies facts and stable logical-section ids, never coordinates.\n */\nexport interface ReferenceAccessibilitySource {\n placementDerivation: 'server-synthesized-row-edges';\n groupLogicalSectionIds: string[];\n assignmentEvidence: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription: string;\n counts: Array<{\n type: AccessibilityType;\n count: number;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n }>;\n}\n\nexport interface ReferenceInventorySource {\n assetId: string;\n logicalSectionId: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n /** Distinguishes directly supplied inventory from a user-approved server\n * distribution based only on an aggregate capacity. */\n derivation?: 'explicit-inventory' | 'server-synthesized-from-aggregate';\n /** Evidence for the aggregate figure; synthesized rows remain\n * `user-confirmed` and are never mislabeled as source-extracted. */\n aggregateEvidence?: 'user-confirmed' | 'authoritative-source';\n /** Separate evidence for assigning standing inventory to this logical\n * section. Aggregate evidence alone cannot prove section placement. */\n sectionAssignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n sectionAssignmentSourceDescription?: string;\n /** Aggregate row synthesis may propose numbering, but persistence requires\n * the applying user/agent to confirm that policy explicitly. */\n numberingEvidence?: 'user-confirmed';\n numberingSourceDescription?: string;\n /** Evidence and deterministic placement contract for synthesized accessible\n * units in this logical section. */\n accessibility?: ReferenceAccessibilitySource;\n}\n\n/** Durable evidence that a visible source-backed section shell intentionally\n * carries no generated sellable inventory in this reference configuration. */\nexport interface ReferenceInventoryExclusionSource {\n assetId: string;\n logicalSectionId: string;\n reason: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n}\n\n/** Non-bookable décor: stage, walls, exits. */\nexport interface ShapeObject {\n type: 'shape';\n id: string;\n kind: 'rect' | 'ellipse' | 'polygon';\n label?: string;\n /** For rect/ellipse: bounding box. For a stage polygon: the base (pre-shape) box, so its kind can be regenerated. */\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n /** For polygon. */\n points?: Point[];\n fill?: string;\n /** Degrees clockwise about the shape's center (default 0). Applied at render time. */\n rotation?: number;\n /**\n * Semantic tag driving special rendering. `'stage'` gets the gradient +\n * prominent uppercase label treatment; a décor landmark role (bar, exit…)\n * gets a quieter label. Loose string to avoid a circular import with\n * stage.ts / decor.ts (see StageKind / DecorRole there).\n */\n role?: string;\n /** For a stage: which `StageKind` its polygon was generated from. */\n stageKind?: string;\n}\n\n/** Seats arranged around a table; bookable per-seat or as a whole. */\nexport interface TableObject {\n type: 'table';\n id: string;\n /** e.g. \"T1\" — seat labels are `${label}-${n}`. */\n label: string;\n center: Point;\n shape: 'round' | 'rect';\n /** Seats around the perimeter (round) or along the enabled edges (rect). */\n seatCount: number;\n /** Rect tables: which edges get seats (default ['top','bottom']). */\n sides?: Array<'top' | 'bottom' | 'left' | 'right'>;\n rotation: number;\n /** Round tables. */\n radius?: number;\n /**\n * Round tables: the arc (in degrees) the seats occupy, default 360 (full\n * ring). Below 360 leaves an open side — e.g. a service gap for waiters, a\n * head table facing the room, or clearance against a wall. The opening is\n * centred on the `rotation` direction; seats spread across the rest.\n */\n seatArc?: number;\n /** Rect tables. */\n width?: number;\n height?: number;\n categoryKey: string;\n /** Whole-table booking: buyers get all seats or none (per-event override later). */\n bookAsWhole?: boolean;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/** A booth: one bookable unit rendered as a block (trade shows, VIP boxes). */\nexport interface BoothObject {\n type: 'booth';\n id: string;\n label: string;\n center: Point;\n width: number;\n height: number;\n rotation: number;\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * A named region of the venue (Balcony Left, Floor B…). Sections are outlines\n * only — objects belong to a section spatially (center inside the outline),\n * keeping the document flat (no nesting; simpler for tools and for AI edits).\n * Renderer: far zoom shows section shapes/labels instead of seats; clicking\n * a section zooms into it.\n */\nexport interface SectionObject {\n type: 'section';\n id: string;\n label: string;\n /** Buyer-facing section name; logical/id fields remain stable. */\n displayLabel?: string;\n labelPresentation?: LabelPresentation;\n /**\n * Stable management/inventory identity shared by disconnected visual\n * components of one logical section. When absent, `id` is the logical id.\n * Each component keeps its own `id` and reference provenance so rendering,\n * editing, measured diffs, and source restoration remain exact.\n */\n logicalSectionId?: string;\n /** Shared semantic Arc/Fan group wrapped by this section. The section id is\n * preserved when the fan parameters are reopened and regenerated. */\n arcFanGroupId?: string;\n /** Closed polygon, chart units. */\n outline: Point[];\n /** Optional true line/arc/cubic boundary. `outline` is a deterministic sample\n * of this path and remains authoritative for membership, validation, and\n * clients that predate curved section rendering. */\n outlinePath?: SectionOutlinePath;\n /** Explicit aisle/cutout polygons excluded from rendering, hit-testing, and membership. */\n holes?: Point[][];\n /** Durable opaque link to the private reference component. Unlike generator\n * provenance, this survives manual geometry edits so a measured diff can\n * report drift and server-owned code can restore the source contour. */\n referenceSource?: {\n assetId: string;\n regionId: string;\n };\n /** Evidence-backed reason this source section remains a visible shell without\n * synthesized sellable inventory (press, closed technical zone, etc.). */\n referenceInventoryExclusion?: ReferenceInventoryExclusionSource;\n /** Deterministic generator provenance for editable reference/parametric shells. */\n geometry?: {\n kind: 'rectangle' | 'tapered' | 'bezier' | 'contour';\n sourceRegionId?: string;\n contourMethod?: 'pixel-edge-loops-rdp' | 'shared-edge-vector-fit-v1';\n simplificationTolerancePx?: number;\n vectorFitErrorPx?: number;\n sharedEdgeCount?: number;\n };\n /** Optional tint override (defaults to a neutral fill / dominant category mix). */\n color?: string;\n /** Zone this section belongs to (id into `ChartDoc.zones`). Far-zoom nav + pricing group. */\n zone?: string;\n /**\n * Tier height. 0 = floor (default). Higher values lift the section in the\n * picker's isometric (\"3D\") view, drawn on extruded side faces. Same field a\n * future multi-floor mode reuses — authored in 2D, never drawn by the user.\n */\n elevation?: number;\n /** Uniform scale about the outline centroid (1 = as drawn). Scales members too. */\n scale?: number;\n /** 0–1: how strongly member-row curves are bent toward a common arc fitted to the outline. */\n smoothing?: number;\n /** Degrees clockwise about the outline centroid (default 0). Rotates members too. */\n rotation?: number;\n}\n\n/**\n * A group of sections (Lower Bowl, Upper Bowl, Floor…). One concept, three jobs:\n * the farthest-zoom navigation unit, a pricing group, and (Batch 3) a timed-\n * release unit. Kept as a flat list on the doc; sections point back by `zone` id.\n */\nexport interface ZoneDef {\n id: string;\n label: string;\n color?: string;\n}\n\n/**\n * Selection layer — a hit-test/dim filter in the designer, NOT z-order management.\n * Fixed set of four; derived from object type via `layerOf()` (no per-object field yet).\n */\nexport type SelectionLayer = 'interactive' | 'background' | 'foreground' | 'surroundings';\n\n/** Derive an object's selection layer from its type (design contract, HANDOFF §03). */\nexport function layerOf(obj: ChartObject): SelectionLayer {\n switch (obj.type) {\n case 'row':\n case 'table':\n case 'gaArea':\n case 'booth':\n case 'section':\n return 'interactive';\n // stage / décor live on 'shape'; free text + decor images are background furniture.\n case 'shape':\n case 'text':\n case 'decorImage':\n return 'background';\n default:\n return 'interactive';\n }\n}\n\n/** Free-standing text on the chart (aisle names, door labels…). */\nexport interface TextObject {\n type: 'text';\n id: string;\n text: string;\n position: Point;\n fontSize: number;\n rotation: number;\n color?: string;\n}\n\n/**\n * A raster/vector decor graphic drawn IN the chart, beneath the seats and\n * sections (ice rink, basketball court, stage art, pitch markings). Purely\n * visual venue context — never bookable, never hit-tested, so it never steals a\n * seat click. `href` is a self-contained data URL (image or SVG) produced by the\n * same client-side downscale used for row photos, so it travels with the doc and\n * caches as a single bitmap blit (zero per-frame cost). Placed by top-left\n * (x,y) + size, rotated about its centre — the same handles a shape rect uses.\n */\nexport interface DecorImageObject {\n type: 'decorImage';\n id: string;\n /** Image or SVG data URL. */\n href: string;\n x: number;\n y: number;\n width: number;\n height: number;\n /** Degrees clockwise about the image centre (default 0). */\n rotation?: number;\n /** 0–1 (default 1). Multiplied by any chart-theme dimming at render time. */\n opacity?: number;\n /** Optional caption for the designer inspector / accessibility (not drawn). */\n label?: string;\n}\n\nexport type ChartObject =\n | RowObject\n | GAAreaObject\n | ShapeObject\n | TableObject\n | BoothObject\n | TextObject\n | SectionObject\n | DecorImageObject;\n\n/**\n * One floor / level of a multi-floor venue (Batch 5). Each floor owns its own\n * geometry, stage focal point, and trace image; categories/zones/tiers stay\n * chart-global (one event, one inventory). A single-floor chart has NO `floors`\n * — its `objects[]` is the whole venue — so all existing charts are untouched.\n */\nexport interface Floor {\n id: string;\n name: string;\n objects: ChartObject[];\n focalPoint: Point;\n backgroundImage?: ChartDoc['backgroundImage'];\n}\n\nexport interface ReferenceCalibration {\n type: 'two-point';\n /** Points in immutable source-image pixels, selected by a human or trusted detector. */\n sourceA: Point;\n sourceB: Point;\n /** Verified real-world distance between the two source points. */\n distance: number;\n unit: 'm' | 'ft' | 'chart-unit';\n /** Derived and stored for deterministic geometry compilers. */\n pixelsPerUnit: number;\n}\n\n/** Coordinate-free physical scale derived by server code from a confirmed\n * semantic feature. Unlike manual two-point calibration, no source points pass\n * through an MCP client or language model. */\nexport interface ReferenceDerivedScale {\n method: 'confirmed-focal-axis-v1';\n feature: 'focal-long-axis' | 'focal-short-axis';\n distance: number;\n unit: 'm' | 'ft';\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n chartUnitsPerUnit: number;\n}\n\nexport interface ChartReferenceImage {\n /** Stable private reference asset. New cloud-authored charts use this. */\n assetId?: string;\n /** Legacy/self-contained source. Optional when assetId is present. */\n url?: string;\n center: Point;\n /** Rendered width in chart units (height follows the cropped image aspect). */\n width: number;\n opacity: number;\n rotation?: number;\n visible?: boolean;\n layer?: 'below' | 'above';\n locked?: boolean;\n /** Normalized source crop; defaults to the full image. */\n crop?: { x: number; y: number; width: number; height: number };\n calibration?: ReferenceCalibration;\n /** Server-derived semantic calibration without source-image coordinates. */\n derivedScale?: ReferenceDerivedScale;\n}\n\nexport interface ChartDoc {\n version: 1;\n name: string;\n venueType: 'SIMPLE' | 'MIXED';\n /** The stage / point every seat looks at. Anchors seat-view + sightlines.\n * Multi-floor: mirrors floor 0; each floor also carries its own focalPoint. */\n focalPoint: Point;\n categories: Category[];\n /** Section groupings for far-zoom navigation + pricing (optional; sections reference by id). */\n zones?: ZoneDef[];\n /** Multi-floor venues (Batch 5): present ⇒ floors[] is the source of truth;\n * absent ⇒ single-floor and `objects` below is the whole chart. `objects`\n * is kept mirroring floor 0 so single-floor readers never branch. */\n floors?: Floor[];\n objects: ChartObject[];\n /** Floor-plan photo the organizer traces over (designer-only aid, also rendered dimly in picker if kept). */\n backgroundImage?: ChartReferenceImage;\n /** Brand/venue theming (colors); categories carry their own colors separately. */\n theme?: ChartTheme;\n /** Parametric-template provenance: present ⇒ the chart came from a capacity-\n * adjustable template family, and the designer offers a capacity control that\n * regenerates it at a new target seat count (Batch 4 \"curated singles + resize\"). */\n template?: { family: string; targetSeats: number };\n}\n\n// ---------------------------------------------------------------------------\n// Expanded (render-time) model — produced by layout.ts, consumed by the engine\n// ---------------------------------------------------------------------------\n\nexport interface ExpandedSeat {\n /** Stable id: `${rowId}:${index}` */\n id: string;\n /** Public label: `${rowLabel}-${seatNumber}` */\n label: string;\n /** Buyer-facing copy; absent on legacy charts, where `label` is displayed. */\n displayLabel?: string;\n x: number;\n y: number;\n rowId: string;\n categoryKey: string;\n /** 'booth' units render as blocks (dimensions looked up via rowId = booth id). */\n kind?: 'seat' | 'booth';\n /** True when the seat has any accessibility accommodation — renderer rings/dims these. */\n accessible?: boolean;\n /** Specific accessibility accommodations (absent = none) — picker badges/filters these. */\n accessibility?: AccessibilityType[];\n commercial?: SeatCommercialAttributes;\n /** Organizer-supplied view-from-seat image (inherited from the row). */\n viewUrl?: string;\n /** Per-seat label size/color override; absent = inherit the row/theme default. */\n labelStyle?: LabelStyle;\n}\n\nexport type SeatStatus = 'free' | 'held' | 'booked' | 'not_for_sale';\n\n// ---------------------------------------------------------------------------\n// Renderer engine public API — implemented in src/engine/SeatmapRenderer.ts\n// ---------------------------------------------------------------------------\n\nexport interface RendererCallbacks {\n onSelect?: (seat: ExpandedSeat) => void;\n onDeselect?: (seat: ExpandedSeat) => void;\n /** Buyer tried to add a seat after the active selection cap was reached. */\n onSelectionLimit?: (maxSelection: number) => void;\n /** seat is null when the pointer leaves any seat. */\n onHover?: (seat: ExpandedSeat | null) => void;\n /** Keyboard focus moved to a seat (arrow-key navigation) — for screen-reader announcements. */\n onFocusSeat?: (seat: ExpandedSeat | null) => void;\n /** Called ~1×/sec with the measured frames-per-second. */\n onFps?: (fps: number) => void;\n /** Fired when a GA area is clicked (quantity picking is UI-side). */\n onGAClick?: (areaId: string) => void;\n /**\n * Fired when a tap lands on a section outline while seats are NOT the active\n * rung (i.e. zoomed out, section/zone LOD). The host glides in + shows a\n * section-summary card instead of trying to select a 4px seat (Slice 5).\n */\n onSectionTap?: (sectionId: string) => void;\n /**\n * Fired when a seat/deck is tapped in the 3D all-floors stacked overview — the\n * host drops back to the flat 2D map on that floor (\"tap a deck to enter\").\n */\n onDeckTap?: (floorId: string) => void;\n /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */\n onViewChange?: () => void;\n /**\n * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on\n * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,\n * with the FULL current selection (selectable seats only). The host toolbar\n * reads this to drive bulk block/unblock. Never fires when manageMode is off.\n */\n onMarquee?: (seats: ExpandedSeat[]) => void;\n}\n\n/** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */\nexport type LodRung = 'zones' | 'sections' | 'seats';\n\nexport interface RendererOptions extends RendererCallbacks {\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** Only these statuses are clickable (default ['free']). */\n selectableStatuses?: SeatStatus[];\n /**\n * Opt-in host behaviour flag — the renderer's own click/selection logic is\n * unchanged (it still selects + fires `onSelect` immediately, so the seat\n * highlights right away). When true, the host (e.g. PublicEventPage) treats\n * that `onSelect` as a pending candidate and shows a confirm card instead of\n * pushing straight into the cart; `deselect([seat.id])` on Cancel un-highlights.\n */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (\"FROM …\"); defaults to money.DEFAULT_CURRENCY.\n * Locale for grouping/symbol placement comes from the active i18n locale. */\n currency?: string;\n /**\n * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode\n * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /\n * pinch / tap and every existing code path are byte-identical when this is\n * false (every manage branch is gated on it). Default false.\n */\n manageMode?: boolean;\n /**\n * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung\n * draws a rubber-band marquee that bulk-selects the seats it covers (emitting\n * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger\n * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below\n * the seats rung (zoom in first). No effect unless `manageMode` is also set.\n */\n marqueeSelect?: boolean;\n}\n\nexport type RenderedLabelHiddenReason =\n | 'below-minimum-size'\n | 'outside-viewport'\n | 'dimmed-or-unavailable'\n | 'clutter-or-fit'\n | 'renderer-hidden';\n\n/** Browser-renderer evidence used by visual QA and catalog release gates. */\nexport interface RenderedBookableLabelEvidence {\n seatId: string;\n label: string;\n kind: 'seat' | 'booth';\n categoryKey: string;\n sectionId?: string;\n zoneId?: string;\n status: SeatStatus;\n selected: boolean;\n visible: boolean;\n renderedFontPx: number;\n fill: string;\n ink: string;\n opacity: number;\n /** Direct Konva shape bounds and the production near-miss rescue combined. */\n pointerTarget: {\n active: boolean;\n directWidthPx: number;\n directHeightPx: number;\n effectiveMinimumPx: number;\n };\n /** Centre of the painted unit, even when its text is intentionally hidden. */\n screenCenter: { x: number; y: number };\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: RenderedLabelHiddenReason;\n}\n\nexport interface RenderedHierarchyLabelEvidence {\n id: string;\n kind: 'section' | 'zone';\n role: 'name' | 'availability' | 'price';\n label: string;\n visible: boolean;\n renderedFontPx: number;\n opacity: number;\n fill: string;\n ink: string;\n /** Independent geometric containment check for section-owned text. */\n fitsContainer?: boolean;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RenderedFreeTextEvidence {\n objectId: string;\n kind: 'free-text' | 'stage' | 'table' | 'decor' | 'ga-label' | 'ga-capacity';\n text: string;\n visible: boolean;\n renderedFontPx: number;\n ink: string;\n background: string;\n opacity: number;\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden';\n}\n\nexport interface RenderedGAAreaEvidence {\n areaId: string;\n label: string;\n capacity: number;\n categoryKey: string;\n /** Owning logical section when the rendered GA surface is section-contained. */\n sectionId?: string;\n visible: boolean;\n interactive: boolean;\n opacity: number;\n fill: string;\n effectiveBackground: string;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RendererQualityEvidence {\n viewport: { width: number; height: number };\n canvasBackground: string;\n effectiveScale: number;\n rung: LodRung;\n minimumVisibleLabelPx: number;\n totalLabelledBookableUnits: number;\n visibleLabels: number;\n hiddenLabels: number;\n /** Seats/table-seats/booths plus the full GA capacity. */\n totalBookableUnits: number;\n selectionRingSeatIds: string[];\n selectionRingColor: string;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n /** Exact scene-graph proof for the clean section-first overview contract. */\n overviewStyle: {\n visibleSectionShells: number;\n categoryPaintedSectionShells: number;\n visibleCategoryDetailOutlines: number;\n visibleSectionRowHints: number;\n visibleSectionAvailabilityLabels: number;\n visibleSectionGADetails: number;\n };\n labels: RenderedBookableLabelEvidence[];\n gaAreas: RenderedGAAreaEvidence[];\n hierarchyLabels: RenderedHierarchyLabelEvidence[];\n freeTextLabels: RenderedFreeTextEvidence[];\n}\n\nexport interface ISeatmapRenderer {\n /** Replace the chart. Resets selection and statuses, zooms to fit.\n * `opts.floorId` picks which floor to render on a multi-floor chart (Batch 5). */\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void;\n /** Bulk status update; re-renders affected seats only. */\n setStatus(seatIds: string[], status: SeatStatus): void;\n /**\n * Mark the active buyer's own held seats. They remain server-status `held`,\n * but render with the buyer selection treatment instead of the anonymous\n * unavailable treatment used for another buyer's hold.\n */\n setOwnedHold?(seatIds: string[] | null): void;\n /**\n * Mark one selected seat as the buyer's pending confirmation candidate.\n * The candidate receives a strong focus halo while unrelated seats recede;\n * pass null after Select/Cancel. This is visual only and never mutates the\n * renderer selection.\n */\n setSelectionFocus?(seatId: string | null): void;\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()\n * (used by setStatus and friends) schedules the actual paint on the next rAF\n * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded\n * tabs — so a seat-status delta updates the scene graph but the pixels never\n * change until the tab is foregrounded again. forceDraw() paints the affected\n * layers immediately (Layer.draw() is synchronous) and flushes any pending\n * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in\n * always-live board) can guarantee the canvas reflects current state\n * regardless of tab visibility. No-op difference in the foreground.\n */\n forceDraw(): void;\n getStatus(seatId: string): SeatStatus;\n getSelection(): ExpandedSeat[];\n clearSelection(): void;\n /** Update the buyer selection cap without rebuilding the chart or camera. */\n setMaxSelection?(maxSelection: number): void;\n /**\n * Programmatically restore free seats (for example an Undo action). Added\n * seats respect the active cap and do not reopen a confirmation popover.\n */\n select?(seatIds: string[]): ExpandedSeat[];\n /**\n * Dynamically update organizer-only interaction without rebuilding the\n * renderer. No buyer surface calls this; every behavior remains gated by\n * `manageMode` exactly as it is at construction time.\n */\n setManageInteraction?(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void;\n /** Organizer-only section heat overlay. Values are normalized 0..1. */\n setSectionHeat?(scores: Record<string, number> | null): void;\n /**\n * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).\n * They select the matching SELECTABLE seats (respecting `selectableStatuses`\n * + closed sections), union with the current selection, and return the seats\n * they added — the SDK SeatManager expands category/row/section picks to\n * labels and drives one batched block/unblock from them.\n */\n selectAllSelectable?(): ExpandedSeat[];\n selectByLabels?(labels: string[]): ExpandedSeat[];\n /** Exact-render QA only: select one server-chosen unit without label ambiguity. */\n setEvidenceSelection?(seatId: string): boolean;\n /** Selectable seats belonging to a section OR zone id (no selection side-effect). */\n getSelectableInSection?(sectionId: string): ExpandedSeat[];\n /** Programmatic deselect of specific seats (e.g. chip × in the cart). */\n deselect(seatIds: string[]): void;\n /**\n * Brief attention pulse on a seat (a ring that expands + fades once) — used to\n * signal live activity, e.g. a seat \"just taken\" by another buyer via a WS\n * delta. Purely visual; no state change. `color` overrides the default.\n */\n flashSeat(seatId: string, color?: string): void;\n /**\n * Brief organizer attention pulse around a whole section. This is a visual\n * overlay only: it never changes section geometry, hit targets, selection, or\n * the active camera. Useful for grouped realtime operations at venue overview.\n */\n flashSection?(sectionId: string, color?: string): void;\n zoomToFit(): void;\n /** Zoom in one step about the viewport center, clamped to the usual zoom bounds. */\n zoomIn(): void;\n /** Zoom out one step about the viewport center, clamped to the usual zoom bounds. */\n zoomOut(): void;\n /** Individually status-managed seats/table-seats/booths; excludes GA capacity. */\n seatCount(): number;\n /** Seats/table-seats/booths plus the full capacity of rendered GA areas. */\n bookableCount(): number;\n /**\n * Maps a chart-space point (or a seat, by its x/y) to container-relative\n * screen pixels, using the current stage scale/position. Lets host UI anchor\n * DOM overlays (confirm card, tooltip) over a live seat and re-anchor them\n * on `onViewChange`.\n */\n worldToScreen(point: Point): { x: number; y: number };\n /** When on, dim non-accessible free seats so accessible seats stand out. */\n setAccessibleFilter(on: boolean): void;\n /**\n * Dim free seats that lack ANY of these accessibility types. `null` clears the\n * filter; `[]` means \"any accessible seat\" (same as setAccessibleFilter(true)).\n */\n setAccessibilityFilter(types: AccessibilityType[] | null): void;\n /** Legend hover-highlight: dim free seats of other categories (null clears). */\n setCategoryHighlight?(key: string | null): void;\n /** Price-band filter (F4): dim free seats whose category is NOT in `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter?(keys: string[] | null): void;\n /** Smoothly frame the currently available seats in these categories. `null`\n * returns to the full chart. Used after an explicit buyer price-filter action. */\n focusCategories?(keys: string[] | null): void;\n /** Dim the seats of these section/zone ids (organizer manager: held-back inventory). */\n setDimmedSections?(ids: string[] | null): void;\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, section stays rendered.\n * `null`/empty clears. (Distinct from the buyer's applyHidden seat-strip.)\n */\n setClosedSections?(ids: string[] | null): void;\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * behind this section, and glide the camera to frame it. Seat-picking is gated\n * until seats are large enough on screen (≥ LABEL_SCALE). Slice 5 / Phase 2 §4.\n */\n focusSection?(id: string): void;\n /** Clear an AXS section focus (restore full-bowl brightness + drop backdrop). */\n clearSectionFocus?(): void;\n /** The currently AXS-focused section id, or null. */\n getFocusedSection?(): string | null;\n /** World-space rect currently visible in the viewport (minimap viewport frame). */\n getVisibleWorldRect?(): { x: number; y: number; width: number; height: number };\n /** Axis-aligned world bounds of all seats + section outlines (minimap frame). */\n getWorldBounds?(): { x: number; y: number; width: number; height: number };\n /**\n * Colorblind-safe mode: category hues switch to an Okabe-Ito palette and\n * booked seats render hollow (a non-color cue), so seat state never relies\n * on hue alone. Off (the default) renders exactly as before.\n */\n setColorblindSafe?(on: boolean): void;\n /**\n * Switch the projection. `'flat'` = normal top-down; `'isometric'` = the \"3D\"\n * view (affine skew/rotate + elevation lift), hit-testing preserved in screen\n * space. Purely visual — the chart is authored flat. Animated unless reduced-motion.\n */\n setViewMode?(mode: 'flat' | 'isometric'): void;\n /** Current projection (defaults to 'flat' when unimplemented). */\n getViewMode?(): 'flat' | 'isometric';\n /** Multi-floor (Batch 5): switch the shown floor; list floors; read the active id. */\n setActiveFloor?(floorId: string): void;\n getFloors?(): { id: string; name: string }[];\n getActiveFloorId?(): string;\n /** Render all floors stacked (3D overview) vs the active floor. No-op single-floor. */\n setStacked?(on: boolean): void;\n isStacked?(): boolean;\n /**\n * Section id whose outline contains a container-relative screen point (or null).\n * Feeds the far-zoom \"tap a section to zoom in\" flow (Slice 5).\n */\n sectionAt?(clientPoint: Point): string | null;\n /** Seat ids belonging to a section — for the section-summary card (Slice 5). */\n sectionMembers?(id: string): string[];\n /**\n * Smoothly glide (pan+zoom) the camera to frame a section (by id) or a world-\n * space bounds rect over a calm easeInOutCubic glide. `prefers-reduced-motion` snaps.\n * A pointer-down (grab/pan) cancels an in-flight glide. Slice 5 \"glide in\".\n */\n focusRegion?(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void;\n /** Current LOD rung derived from zoom (for the ZONES/SECTIONS/SEATS pill). */\n getRung?(): LodRung;\n /** Jump the camera to a rung's zoom band, centred on the chart (glided). */\n setRung?(rung: LodRung): void;\n /** Read actual browser-rendered label visibility, size, fill, ink and state.\n * Pure diagnostic: it never changes chart or renderer state. */\n getRenderedQualityEvidence(): RendererQualityEvidence;\n destroy(): void;\n}\n\n/** localStorage key the Designer writes and the Picker reads. */\nexport const CHART_STORAGE_KEY = 'seatmap.chart';\n","import type { CubicPath, Point } from './types';\n\nexport type SectionShellMode = 'auto' | 'rectangle' | 'tapered' | 'bezier';\n\nexport function cubicPoint(path: CubicPath, t: number): Point {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n return {\n x: a * path.start.x + b * path.control1.x + c * path.control2.x + d * path.end.x,\n y: a * path.start.y + b * path.control1.y + c * path.control2.y + d * path.end.y,\n };\n}\n\n/** Equal-arc-length points on a cubic path, including both endpoints. */\nexport function distributeAlongCubic(path: CubicPath, count: number, resolution = 192): Point[] {\n if (!Number.isInteger(count) || count < 1) throw new Error('Path point count must be a positive integer');\n if (count === 1) return [cubicPoint(path, 0.5)];\n const samples = Array.from({ length: resolution + 1 }, (_, index) => cubicPoint(path, index / resolution));\n const lengths = new Float64Array(samples.length);\n for (let index = 1; index < samples.length; index += 1) {\n const dx = samples[index].x - samples[index - 1].x;\n const dy = samples[index].y - samples[index - 1].y;\n lengths[index] = lengths[index - 1] + Math.hypot(dx, dy);\n }\n const total = lengths[lengths.length - 1];\n if (total <= 1e-9) return Array.from({ length: count }, () => ({ ...path.start }));\n const output: Point[] = [];\n let segment = 1;\n for (let index = 0; index < count; index += 1) {\n const target = (total * index) / (count - 1);\n while (segment < lengths.length - 1 && lengths[segment] < target) segment += 1;\n const before = lengths[segment - 1];\n const after = lengths[segment];\n const ratio = after === before ? 0 : (target - before) / (after - before);\n output.push({\n x: samples[segment - 1].x + (samples[segment].x - samples[segment - 1].x) * ratio,\n y: samples[segment - 1].y + (samples[segment].y - samples[segment - 1].y) * ratio,\n });\n }\n return output;\n}\n\nfunction add(a: Point, b: Point): Point { return { x: a.x + b.x, y: a.y + b.y }; }\nfunction sub(a: Point, b: Point): Point { return { x: a.x - b.x, y: a.y - b.y }; }\nfunction mul(a: Point, scale: number): Point { return { x: a.x * scale, y: a.y * scale }; }\nfunction distance(a: Point, b: Point): number { return Math.hypot(a.x - b.x, a.y - b.y); }\nfunction lerp(a: Point, b: Point, t: number): Point { return add(a, mul(sub(b, a), t)); }\n\nfunction sample(path: CubicPath, count = 13): Point[] {\n return Array.from({ length: count }, (_, index) => cubicPoint(path, index / (count - 1)));\n}\n\nfunction pointOnSampledPath(points: Point[], t: number): Point {\n const scaled = Math.max(0, Math.min(1, t)) * (points.length - 1);\n const index = Math.min(points.length - 2, Math.floor(scaled));\n return lerp(points[index], points[index + 1], scaled - index);\n}\n\nfunction sampledPathSegment(points: Point[], from: number, to: number): Point[] {\n const start = Math.max(0, Math.min(1, from));\n const end = Math.max(start, Math.min(1, to));\n const output = [pointOnSampledPath(points, start)];\n for (let index = 1; index < points.length - 1; index += 1) {\n const t = index / (points.length - 1);\n if (t > start + 1e-9 && t < end - 1e-9) output.push(points[index]);\n }\n output.push(pointOnSampledPath(points, end));\n return output;\n}\n\ninterface SectionFrame {\n p0: Point;\n p1: Point;\n p2: Point;\n p3: Point;\n normal: Point;\n depth: number;\n}\n\nfunction orientSectionFrame(corners: Point[], focal: Point): SectionFrame {\n const edges: Array<[number, number]> = [[0, 1], [1, 2], [2, 3], [3, 0]];\n let nearEdge = 0;\n let nearDistance = Number.POSITIVE_INFINITY;\n edges.forEach(([a, b], index) => {\n const d = distance(lerp(corners[a], corners[b], 0.5), focal);\n if (d < nearDistance) {\n nearDistance = d;\n nearEdge = index;\n }\n });\n const p0 = corners[nearEdge];\n const p1 = corners[(nearEdge + 1) % 4];\n const p2 = corners[(nearEdge + 2) % 4];\n const p3 = corners[(nearEdge + 3) % 4];\n const nearMid = lerp(p0, p1, 0.5);\n const inward = sub(focal, nearMid);\n const inwardLength = Math.max(1e-9, Math.hypot(inward.x, inward.y));\n return {\n p0,\n p1,\n p2,\n p3,\n normal: mul(inward, 1 / inwardLength),\n depth: (distance(p0, p3) + distance(p1, p2)) / 2,\n };\n}\n\nfunction bezierSectionPaths(frame: SectionFrame): { nearPath: CubicPath; farPath: CubicPath } {\n const { p0, p1, p2, p3, normal, depth } = frame;\n const nearSpan = sub(p1, p0);\n const farSpan = sub(p2, p3);\n const nearCurve = depth * 0.22;\n const farCurve = depth * 0.12;\n return {\n nearPath: {\n start: p0,\n control1: add(add(p0, mul(nearSpan, 1 / 3)), mul(normal, nearCurve)),\n control2: add(add(p0, mul(nearSpan, 2 / 3)), mul(normal, nearCurve)),\n end: p1,\n },\n farPath: {\n start: p2,\n control1: add(add(p3, mul(farSpan, 2 / 3)), mul(normal, farCurve)),\n control2: add(add(p3, mul(farSpan, 1 / 3)), mul(normal, farCurve)),\n end: p3,\n },\n };\n}\n\n/**\n * Convert a server-mapped rectangle into an editable complex shell. The four\n * corners must be clockwise. No caller-supplied control points are accepted.\n */\nexport function buildSectionShell(corners: Point[], focal: Point, requested: SectionShellMode): {\n mode: Exclude<SectionShellMode, 'auto'>;\n outline: Point[];\n} {\n if (corners.length !== 4) throw new Error('A section shell requires four mapped bounds corners');\n const center = corners.reduce((sum, point) => add(sum, point), { x: 0, y: 0 });\n center.x /= 4;\n center.y /= 4;\n const width = distance(corners[0], corners[1]);\n const height = distance(corners[0], corners[3]);\n const mode = requested === 'auto'\n ? (width > height * 1.25 && distance(center, focal) > height ? 'bezier' : 'tapered')\n : requested;\n if (mode === 'rectangle') return { mode, outline: corners.map((point) => ({ ...point })) };\n\n // Rotate corners so local p0→p1 is the edge nearest the focal point and\n // p3→p2 is the far edge, while preserving clockwise winding.\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n\n if (mode === 'tapered') {\n const inset = 0.14;\n return {\n mode,\n outline: [\n add(p0, mul(sub(p1, p0), inset)),\n add(p0, mul(sub(p1, p0), 1 - inset)),\n p2,\n p3,\n ],\n };\n }\n\n const { nearPath, farPath } = bezierSectionPaths(frame);\n return { mode, outline: [...sample(nearPath), ...sample(farPath).slice(1)] };\n}\n\n/** Server-owned straight aisle cutouts spanning the near/far edges. */\nexport function buildAisleHoles(\n corners: Point[],\n focal: Point,\n count: number,\n mode: Exclude<SectionShellMode, 'auto'>,\n): Point[][] {\n if (corners.length !== 4) throw new Error('Aisle generation requires four mapped bounds corners');\n if (!Number.isInteger(count) || count < 0 || count > 3) throw new Error('Aisle count must be an integer from 0 to 3');\n if (count === 0) return [];\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n const paths = mode === 'bezier' ? bezierSectionPaths(frame) : null;\n // For curved shells, interpolate the same sampled polylines stored in the\n // document. Exact cubic points between samples can sit fractionally outside\n // their chord approximation and fail topology validation/hit clipping.\n const nearSamples = paths ? sample(paths.nearPath) : null;\n const farLateralSamples = paths ? sample(paths.farPath).reverse() : null;\n const widthFraction = Math.min(0.055, 0.18 / (count + 1));\n return Array.from({ length: count }, (_, index) => {\n const t = (index + 1) / (count + 1);\n const left = t - widthFraction / 2;\n const right = t + widthFraction / 2;\n if (nearSamples && farLateralSamples) {\n return [\n ...sampledPathSegment(nearSamples, left, right),\n ...sampledPathSegment(farLateralSamples, left, right).reverse(),\n ];\n }\n return [lerp(p0, p1, left), lerp(p0, p1, right), lerp(p3, p2, right), lerp(p3, p2, left)];\n });\n}\n","import type { Point, SectionOutlinePath, SectionPathSegment } from './types';\n\nconst TAU = Math.PI * 2;\n\nfunction finitePoint(point: Point): boolean {\n return Number.isFinite(point.x) && Number.isFinite(point.y);\n}\n\nfunction distance(left: Point, right: Point): number {\n return Math.hypot(left.x - right.x, left.y - right.y);\n}\n\nfunction arcSweep(start: number, end: number, clockwise: boolean): number {\n let delta = end - start;\n if (clockwise) {\n while (delta < 0) delta += TAU;\n while (delta >= TAU) delta -= TAU;\n } else {\n while (delta > 0) delta -= TAU;\n while (delta <= -TAU) delta += TAU;\n }\n return delta;\n}\n\nexport function sectionPathSegmentEnd(segment: SectionPathSegment): Point {\n return segment.end;\n}\n\n/** Validate finite, continuous closed-path geometry without trusting renderer\n * behaviour. Arc endpoints must lie on their declared circle. */\nexport function validSectionOutlinePath(path: SectionOutlinePath): boolean {\n if (path.version !== 1 || path.closed !== true || !finitePoint(path.start)\n || !Array.isArray(path.segments) || path.segments.length < 2 || path.segments.length > 512) return false;\n let current = path.start;\n for (const segment of path.segments) {\n if (!segment || !finitePoint(segment.end)) return false;\n if (segment.kind === 'line') {\n if (distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'bezier') {\n if (!finitePoint(segment.control1) || !finitePoint(segment.control2)\n || distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'arc') {\n if (!finitePoint(segment.center) || !Number.isFinite(segment.radius) || segment.radius <= 1e-6\n || Math.abs(distance(current, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || Math.abs(distance(segment.end, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || distance(current, segment.end) <= 1e-9) return false;\n } else return false;\n current = segment.end;\n }\n return distance(current, path.start) <= 1e-4;\n}\n\nfunction cubicPoint(start: Point, segment: Extract<SectionPathSegment, { kind: 'bezier' }>, t: number): Point {\n const mt = 1 - t;\n return {\n x: mt ** 3 * start.x + 3 * mt ** 2 * t * segment.control1.x\n + 3 * mt * t ** 2 * segment.control2.x + t ** 3 * segment.end.x,\n y: mt ** 3 * start.y + 3 * mt ** 2 * t * segment.control1.y\n + 3 * mt * t ** 2 * segment.control2.y + t ** 3 * segment.end.y,\n };\n}\n\n/** Deterministic polygon sample used by validation, hit testing, diff, and old\n * clients. The returned loop omits the duplicate closing point. */\nexport function sampleSectionOutlinePath(path: SectionOutlinePath, maxStep = 2): Point[] {\n if (!validSectionOutlinePath(path)) throw new Error('Section outline path is invalid');\n const step = Math.max(0.25, maxStep);\n const points: Point[] = [{ ...path.start }];\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') {\n points.push({ ...segment.end });\n } else if (segment.kind === 'arc') {\n const startAngle = Math.atan2(current.y - segment.center.y, current.x - segment.center.x);\n const endAngle = Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x);\n const sweep = arcSweep(startAngle, endAngle, segment.clockwise);\n const count = Math.max(2, Math.ceil(Math.abs(sweep) * segment.radius / step));\n for (let index = 1; index <= count; index += 1) {\n const angle = startAngle + sweep * index / count;\n points.push({\n x: segment.center.x + Math.cos(angle) * segment.radius,\n y: segment.center.y + Math.sin(angle) * segment.radius,\n });\n }\n } else {\n const controlLength = distance(current, segment.control1)\n + distance(segment.control1, segment.control2)\n + distance(segment.control2, segment.end);\n const count = Math.max(2, Math.ceil(controlLength / step));\n for (let index = 1; index <= count; index += 1) points.push(cubicPoint(current, segment, index / count));\n }\n current = segment.end;\n }\n if (distance(points[points.length - 1], points[0]) <= 1e-4) points.pop();\n return points;\n}\n\nexport function translateSectionOutlinePath(path: SectionOutlinePath, dx: number, dy: number): SectionOutlinePath {\n const translate = (point: Point): Point => ({ x: point.x + dx, y: point.y + dy });\n return transformSectionOutlinePath(path, translate);\n}\n\n/** Apply a similarity transform. Callers provide the point transform and the\n * absolute radius scale; reflections toggle arc direction. */\nexport function transformSectionOutlinePath(\n path: SectionOutlinePath,\n transform: (point: Point) => Point,\n radiusScale = 1,\n reflected = false,\n): SectionOutlinePath {\n return {\n ...path,\n start: transform(path.start),\n segments: path.segments.map((segment) => segment.kind === 'line'\n ? { ...segment, end: transform(segment.end) }\n : segment.kind === 'arc'\n ? {\n ...segment,\n center: transform(segment.center),\n radius: segment.radius * Math.abs(radiusScale),\n clockwise: reflected ? !segment.clockwise : segment.clockwise,\n end: transform(segment.end),\n }\n : {\n ...segment,\n control1: transform(segment.control1),\n control2: transform(segment.control2),\n end: transform(segment.end),\n }),\n };\n}\n\n/** Reverse a closed path without changing its painted boundary. */\nexport function reverseSectionOutlinePath(path: SectionOutlinePath): SectionOutlinePath {\n const starts: Point[] = [];\n let current = path.start;\n for (const segment of path.segments) {\n starts.push(current);\n current = segment.end;\n }\n const segments: SectionPathSegment[] = [];\n for (let index = path.segments.length - 1; index >= 0; index -= 1) {\n const segment = path.segments[index];\n const end = starts[index];\n if (segment.kind === 'line') segments.push({ kind: 'line', end: { ...end } });\n else if (segment.kind === 'arc') segments.push({\n kind: 'arc', center: { ...segment.center }, radius: segment.radius,\n clockwise: !segment.clockwise, end: { ...end },\n });\n else segments.push({\n kind: 'bezier', control1: { ...segment.control2 }, control2: { ...segment.control1 }, end: { ...end },\n });\n }\n return { version: 1, closed: true, start: { ...path.start }, segments };\n}\n","/**\n * Pure geometry helpers — no Konva, no DOM. Turns the parametric chart\n * document into concrete seat coordinates and computes bounding boxes.\n */\n\nimport type {\n AccessibilityType,\n BoothObject,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n Floor,\n LabelStyle,\n Point,\n RowObject,\n SeatOverride,\n TableObject,\n} from './types';\nimport { distributeAlongCubic } from './complexGeometry';\nimport { translateSectionOutlinePath } from './sectionPath';\n\n/** Resolve a seat override's accessibility, honouring the legacy boolean flag. */\nfunction overrideAccessibility(o: SeatOverride | undefined): AccessibilityType[] {\n if (!o) return [];\n if (o.accessibility && o.accessibility.length) return o.accessibility;\n return o.accessible ? ['wheelchair'] : [];\n}\n\nconst DEG = Math.PI / 180;\n/** Seat visual radius (mirrors the renderer) — used only for bounds padding. */\nconst SEAT_R = 9;\n/** How far outside a table's body its seats sit. */\nconst TABLE_SEAT_OFFSET = 16;\n\n/** Rotate a local point clockwise by `deg` (screen coords, +y down) then translate. */\nfunction place(lx: number, ly: number, deg: number, origin: Point): { x: number; y: number } {\n const a = deg * DEG;\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n return {\n x: origin.x + lx * cos - ly * sin,\n y: origin.y + lx * sin + ly * cos,\n };\n}\n\n/**\n * Expand a parametric row into seat positions.\n *\n * Straight (curve === 0): seat i sits at local (i·spacing, 0).\n *\n * Curved: seats lie on a circular arc. Per-seat angular step is\n * `curve/(seatCount-1)`; radius is derived so the chord between neighbours\n * equals seatSpacing → radius = spacing / (2·sin(step/2)). Seat 0 sits at the\n * bottom of the arc (local origin) with the circle centre directly above it at\n * (0,-radius); increasing index sweeps toward +x while the ends rise toward -y,\n * i.e. positive curve is concave toward -y (a row wrapping a stage above it).\n * Local points are then rotated by `rotation` and translated to `origin`.\n *\n * Numbering (labels only, never geometry): `seatNumbering.direction === 'rtl'`\n * numbers from the far physical end; `step === 2` produces odd/even numbering\n * (start at 1 → 1,3,5…; start at 2 → 2,4,6…).\n */\n/** Base (pre-override) seat centre per index — shared by expandRow + designer edit mode. */\nfunction rowSeatPositions(row: RowObject): Point[] {\n const { seatCount, seatSpacing, curve, rotation, origin } = row;\n const out: Point[] = [];\n if (row.path) return distributeAlongCubic(row.path, seatCount);\n if (seatCount <= 1) {\n if (seatCount === 1) out.push({ x: origin.x, y: origin.y });\n return out;\n }\n if (curve === 0) {\n for (let i = 0; i < seatCount; i++) out.push(place(i * seatSpacing, 0, rotation, origin));\n return out;\n }\n const arcStep = (curve / (seatCount - 1)) * DEG; // radians per seat\n const radius = seatSpacing / (2 * Math.sin(Math.abs(arcStep) / 2));\n // Centre above seat 0. φ measured from the downward vertical, growing with index.\n for (let i = 0; i < seatCount; i++) {\n const phi = i * arcStep;\n const lx = radius * Math.sin(phi);\n const ly = -radius + radius * Math.cos(phi); // ≤ 0 → ends rise toward -y\n out.push(place(lx, ly, rotation, origin));\n }\n return out;\n}\n\nfunction overrideMap(row: RowObject): Map<number, SeatOverride> {\n const m = new Map<number, SeatOverride>();\n if (row.overrides) for (const o of row.overrides) m.set(o.index, o);\n return m;\n}\n\n/**\n * Every seat slot of a row INCLUDING skipped ones (designer seat-edit mode uses\n * this to draw un-skip handles). Overrides (dx/dy/label/categoryKey) are applied\n * but a skipped slot is flagged, not omitted.\n */\nexport interface RowSeatSlot {\n index: number;\n x: number;\n y: number;\n label: string;\n displayLabel: string;\n categoryKey: string;\n skipped: boolean;\n accessible: boolean;\n accessibility: AccessibilityType[];\n commercial?: RowObject['commercial'];\n viewUrl?: string;\n labelStyle?: LabelStyle;\n}\n\nexport function expandRowSlots(row: RowObject): RowSeatSlot[] {\n const start = row.seatLabelStart ?? 1;\n const dir = row.seatNumbering?.direction ?? 'ltr';\n const step = row.seatNumbering?.step ?? 1;\n const n = row.seatCount;\n let seatNumber: (i: number) => number;\n if (dir === 'center') {\n // Number outward from the middle: rank seats by distance from centre\n // (inner-left wins ties), so the centre seat gets `start`.\n const rank = new Array<number>(n);\n Array.from({ length: n }, (_, i) => i)\n .sort((a, b) => Math.abs(2 * a - (n - 1)) - Math.abs(2 * b - (n - 1)) || a - b)\n .forEach((idx, k) => (rank[idx] = k));\n seatNumber = (i) => start + rank[i] * step;\n } else {\n seatNumber = (i) => start + (dir === 'rtl' ? n - 1 - i : i) * step;\n }\n const ov = overrideMap(row);\n return rowSeatPositions(row).map((p, i) => {\n const o = ov.get(i);\n const accessibility = overrideAccessibility(o);\n const inventoryLabel = o?.label ?? `${row.label}-${seatNumber(i)}`;\n const displayPrefix = row.displayLabel ?? row.label;\n const commercial = { ...row.commercial, ...o?.commercial };\n return {\n index: i,\n x: p.x + (o?.dx ?? 0),\n y: p.y + (o?.dy ?? 0),\n label: inventoryLabel,\n displayLabel: o?.displayLabel ?? `${displayPrefix}-${seatNumber(i)}`,\n categoryKey: o?.categoryKey ?? row.categoryKey,\n skipped: !!o?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n commercial: Object.values(commercial).some((value) => value !== undefined && value !== false && value !== '') ? commercial : undefined,\n viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl,\n labelStyle: o?.labelStyle,\n };\n });\n}\n\nexport function expandRow(row: RowObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n for (const slot of expandRowSlots(row)) {\n if (slot.skipped) continue; // physical seat absent; numbering gap preserved\n seats.push({\n id: `${row.id}:${slot.index}`,\n label: slot.label,\n displayLabel: slot.displayLabel === slot.label ? undefined : slot.displayLabel,\n x: slot.x,\n y: slot.y,\n rowId: row.id,\n categoryKey: slot.categoryKey,\n accessible: slot.accessible || undefined,\n accessibility: slot.accessibility.length ? slot.accessibility : undefined,\n commercial: slot.commercial,\n viewUrl: slot.viewUrl,\n labelStyle: slot.labelStyle,\n });\n }\n return seats;\n}\n\n/**\n * Expand a table into its perimeter seats.\n *\n * Round: seats spread evenly on a circle of radius `radius + 16`, the first at\n * angle `rotation` (degrees, clockwise from +x). Rect: seats line the top and\n * bottom edges (split evenly, any remainder to the top), 16u outside the edge,\n * the whole set rotated about the table centre.\n */\nexport function expandTable(t: TableObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n const n = Math.max(0, Math.round(t.seatCount));\n if (n === 0) return seats;\n\n const mk = (i: number, x: number, y: number): ExpandedSeat => ({\n id: `${t.id}:${i}`,\n label: `${t.label}-${i + 1}`,\n x,\n y,\n rowId: t.id,\n categoryKey: t.categoryKey,\n });\n\n if (t.shape === 'round') {\n const R = (t.radius ?? 40) + TABLE_SEAT_OFFSET;\n const base = t.rotation * DEG;\n const arc = Math.max(0, Math.min(360, t.seatArc ?? 360));\n if (arc >= 360 || n === 1) {\n // Full ring (or a lone seat) — evenly spaced around the whole table.\n for (let i = 0; i < n; i++) {\n const a = base + (i / n) * 2 * Math.PI;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n // Open side: seats fill the arc, leaving a gap centred on `rotation` (the\n // opening — face it toward the aisle/wall). Seats span edge-to-edge of the\n // seated arc so people flank the gap.\n const arcRad = arc * DEG;\n const halfGap = (2 * Math.PI - arcRad) / 2;\n const start = base + halfGap;\n for (let i = 0; i < n; i++) {\n const a = start + (i / (n - 1)) * arcRad;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n\n // Rect: seats line the enabled edges. Round-robin the count across sides in\n // canonical order so they stay balanced; top/bottom run along width, left/\n // right along height, all 16u outside and rotated with the table.\n const w = t.width ?? 80;\n const h = t.height ?? 50;\n const enabled: NonNullable<TableObject['sides']> =\n t.sides && t.sides.length ? t.sides : ['top', 'bottom'];\n const order = (['top', 'bottom', 'left', 'right'] as const).filter((s) => enabled.includes(s));\n if (!order.length) return seats;\n const counts = new Map<(typeof order)[number], number>(order.map((s) => [s, 0]));\n for (let i = 0; i < n; i++) {\n const s = order[i % order.length];\n counts.set(s, counts.get(s)! + 1);\n }\n let idx = 0;\n for (const side of order) {\n const count = counts.get(side)!;\n for (let j = 0; j < count; j++) {\n let localX: number;\n let localY: number;\n if (side === 'top') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = -h / 2 - TABLE_SEAT_OFFSET;\n } else if (side === 'bottom') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = h / 2 + TABLE_SEAT_OFFSET;\n } else if (side === 'left') {\n localX = -w / 2 - TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n } else {\n localX = w / 2 + TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n }\n const p = place(localX, localY, t.rotation, t.center);\n seats.push(mk(idx++, p.x, p.y));\n }\n }\n return seats;\n}\n\n/** Expand a booth into its single bookable block unit. */\nexport function expandBooth(b: BoothObject): ExpandedSeat[] {\n return [\n {\n id: `${b.id}:0`,\n label: b.label,\n x: b.center.x,\n y: b.center.y,\n rowId: b.id,\n categoryKey: b.categoryKey,\n kind: 'booth',\n },\n ];\n}\n\n/** Ray-cast point-in-polygon test — odd crossings ⇒ inside. */\nexport function pointInPolygon(p: Point, poly: Point[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x;\n const yi = poly[i].y;\n const xj = poly[j].x;\n const yj = poly[j].y;\n const hit = yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;\n if (hit) inside = !inside;\n }\n return inside;\n}\n\nfunction pointOnPolygonBoundary(p: Point, poly: Point[]): boolean {\n return poly.some((start, index) => {\n const end = poly[(index + 1) % poly.length];\n const cross = (p.y - start.y) * (end.x - start.x) - (p.x - start.x) * (end.y - start.y);\n if (Math.abs(cross) > 1e-7) return false;\n const dot = (p.x - start.x) * (end.x - start.x) + (p.y - start.y) * (end.y - start.y);\n const lengthSquared = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;\n return dot >= -1e-7 && dot <= lengthSquared + 1e-7;\n });\n}\n\nexport function pointInPolygonWithHoles(p: Point, outer: Point[], holes: Point[][] | undefined): boolean {\n return pointInPolygon(p, outer)\n && !(holes ?? []).some((hole) => pointInPolygon(p, hole) || pointOnPolygonBoundary(p, hole));\n}\n\n/** Stable interior label anchor that cannot land inside a polygon cutout. */\nexport function polygonLabelPoint(outer: Point[], holes: Point[][] | undefined): Point {\n if (!outer.length) return { x: 0, y: 0 };\n const xs = outer.map((point) => point.x);\n const ys = outer.map((point) => point.y);\n const bounds = { minX: Math.min(...xs), maxX: Math.max(...xs), minY: Math.min(...ys), maxY: Math.max(...ys) };\n const centroid = polygonCentroid(outer);\n if (pointInPolygonWithHoles(centroid, outer, holes)) return centroid;\n let best = outer[0];\n let bestScore = -Infinity;\n const rings = [outer, ...(holes ?? [])];\n for (let row = 1; row < 24; row += 1) {\n for (let column = 1; column < 24; column += 1) {\n const point = {\n x: bounds.minX + ((bounds.maxX - bounds.minX) * column) / 24,\n y: bounds.minY + ((bounds.maxY - bounds.minY) * row) / 24,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) continue;\n const score = Math.min(...rings.flatMap((ring) => ring.map((start, index) => {\n const end = ring[(index + 1) % ring.length];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const denominator = dx * dx + dy * dy;\n const projection = denominator\n ? ((point.x - start.x) * dx + (point.y - start.y) * dy) / denominator\n : 0;\n const t = Math.max(0, Math.min(1, projection));\n return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));\n })));\n if (score > bestScore) { best = point; bestScore = score; }\n }\n }\n return best;\n}\n\n/** Average of polygon vertices (v1 centroid — good enough for labels/membership). */\nfunction polygonCentroid(pts: Point[]): Point {\n if (!pts.length) return { x: 0, y: 0 };\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p.x;\n y += p.y;\n }\n return { x: x / pts.length, y: y / pts.length };\n}\n\n/**\n * Visual centre of any object — used for spatial section membership and for\n * rotating an object about its centre. Rows: centroid of expanded seats (or\n * origin when empty); tables/booths: centre; GA/section: polygon centroid;\n * shape: bbox centre; text: its position.\n */\nexport function objectCenter(o: ChartObject): Point {\n switch (o.type) {\n case 'row': {\n const seats = expandRow(o);\n if (!seats.length) return { x: o.origin.x, y: o.origin.y };\n let x = 0;\n let y = 0;\n for (const s of seats) {\n x += s.x;\n y += s.y;\n }\n return { x: x / seats.length, y: y / seats.length };\n }\n case 'table':\n case 'booth':\n return { x: o.center.x, y: o.center.y };\n case 'gaArea':\n return polygonCentroid(o.points);\n case 'section':\n return polygonCentroid(o.outline);\n case 'text':\n return { x: o.position.x, y: o.position.y };\n case 'shape':\n if (o.points && o.points.length) return polygonCentroid(o.points);\n if (o.x != null && o.y != null && o.width != null && o.height != null) {\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n return { x: o.x ?? 0, y: o.y ?? 0 };\n case 'decorImage':\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n}\n\n/**\n * Normalized floor list (Batch 5): a multi-floor chart's `floors`, or a synthetic\n * single floor wrapping a single-floor chart's `objects`. Every consumer that needs\n * to reason about floors goes through this so single-floor charts stay untouched.\n */\nexport function floorsOf(doc: ChartDoc): Floor[] {\n if (doc.floors && doc.floors.length) return doc.floors;\n return [{ id: 'floor-0', name: 'Main', objects: doc.objects, focalPoint: doc.focalPoint, backgroundImage: doc.backgroundImage }];\n}\n\n/** Objects of one floor by id (defaults to the first floor). */\nexport function floorObjects(doc: ChartDoc, floorId?: string): ChartObject[] {\n const floors = floorsOf(doc);\n return (floorId ? floors.find((f) => f.id === floorId) : floors[0])?.objects ?? [];\n}\n\n/** Every object across ALL floors — the whole venue (single-floor = `doc.objects`). */\nexport function allObjects(doc: ChartDoc): ChartObject[] {\n return doc.floors && doc.floors.length ? doc.floors.flatMap((f) => f.objects) : doc.objects;\n}\n\n/** A copy of an object translated by (dx, dy) — every coordinate field shifted. */\nfunction translateObject(o: ChartObject, dx: number, dy: number): ChartObject {\n const p = (pt: Point): Point => ({ x: pt.x + dx, y: pt.y + dy });\n const pts = (a: Point[]): Point[] => a.map(p);\n switch (o.type) {\n case 'row':\n return { ...o, origin: p(o.origin) };\n case 'table':\n case 'booth':\n return { ...o, center: p(o.center) };\n case 'gaArea':\n return { ...o, points: pts(o.points), ...(o.holes ? { holes: o.holes.map(pts) } : {}) };\n case 'section':\n return {\n ...o,\n outline: pts(o.outline),\n ...(o.outlinePath ? { outlinePath: translateSectionOutlinePath(o.outlinePath, dx, dy) } : {}),\n ...(o.holes ? { holes: o.holes.map(pts) } : {}),\n };\n case 'text':\n return { ...o, position: p(o.position) };\n case 'shape':\n return {\n ...o,\n ...(o.points ? { points: pts(o.points) } : {}),\n ...(o.x != null ? { x: o.x + dx } : {}),\n ...(o.y != null ? { y: o.y + dy } : {}),\n };\n case 'decorImage':\n return { ...o, x: o.x + dx, y: o.y + dy };\n }\n}\n\n/**\n * Multi-floor 3D stack (Batch 5): flatten every floor into ONE doc with floor `i`\n * lifted by `i * spread` in −y, so the isometric view shows the floors as stacked\n * decks (ground at the bottom). Returns a single-floor doc (no `floors`). Meant\n * only for the 3D overview render — 2D still shows one floor via `floorObjects`.\n */\nexport function stackFloors(doc: ChartDoc, spread = 900): ChartDoc {\n if (!doc.floors || doc.floors.length < 2) return doc;\n const objects: ChartObject[] = [];\n doc.floors.forEach((f, i) => {\n const dy = -i * spread;\n for (const o of f.objects) objects.push(dy === 0 ? o : translateObject(o, 0, dy));\n });\n return { ...doc, objects, floors: undefined };\n}\n\n/** Expand every seat-bearing object across all floors (rows, tables, booths). */\nexport function expandChart(doc: ChartDoc): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n for (const obj of allObjects(doc)) {\n if (obj.type === 'row') out.push(...expandRow(obj));\n else if (obj.type === 'table') out.push(...expandTable(obj));\n else if (obj.type === 'booth') out.push(...expandBooth(obj));\n }\n return out;\n}\n\nconst PAD = 40;\n\n/** Axis-aligned bounds over every object plus the background image, with padding. */\nexport function chartBounds(doc: ChartDoc): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n const acc = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n\n for (const s of expandChart(doc)) acc(s.x, s.y);\n\n for (const obj of allObjects(doc)) {\n if (obj.type === 'gaArea') {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.type === 'section') {\n for (const p of obj.outline) acc(p.x, p.y);\n } else if (obj.type === 'decorImage') {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n } else if (obj.type === 'shape') {\n if (obj.points && obj.points.length) {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n }\n } else if (obj.type === 'table') {\n const off = TABLE_SEAT_OFFSET + SEAT_R;\n const ext =\n obj.shape === 'round'\n ? (obj.radius ?? 40) + off\n : Math.max((obj.width ?? 80) / 2, (obj.height ?? 50) / 2) + off; // rotation-agnostic over-approximation\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'booth') {\n const ext = Math.max(obj.width, obj.height) / 2;\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'text') {\n const w = obj.fontSize * obj.text.length * 0.6; // approximate glyph advance\n acc(obj.position.x, obj.position.y);\n acc(obj.position.x + w, obj.position.y + obj.fontSize);\n }\n }\n\n if (doc.backgroundImage) {\n const { center, width } = doc.backgroundImage;\n const bh = (width * 3) / 4; // assume 4:3 when the true aspect is unknown at bounds-time\n acc(center.x - width / 2, center.y - bh / 2);\n acc(center.x + width / 2, center.y + bh / 2);\n }\n\n // Empty document → a sane default box around the focal point.\n if (!isFinite(minX)) {\n const f = doc.focalPoint ?? { x: 0, y: 0 };\n return { x: f.x - 200, y: f.y - 200, width: 400, height: 400 };\n }\n\n return {\n x: minX - PAD,\n y: minY - PAD,\n width: maxX - minX + PAD * 2,\n height: maxY - minY + PAD * 2,\n };\n}\n","import type { ChartDoc, GAAreaObject } from './types';\nimport { allObjects } from './layout';\n\nconst PREFIX = '__sl_ga__';\nexport const MAX_GA_CAPACITY = 100_000;\nexport const MAX_EVENT_INVENTORY = 100_000;\n\n/** Stable internal inventory label for one unit of a GA area's capacity. */\nexport function gaUnitLabel(areaId: string, index: number): string {\n return `${PREFIX}${encodeURIComponent(areaId)}__${index + 1}`;\n}\n\nexport function gaUnitLabels(area: GAAreaObject): string[] {\n const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));\n return Array.from({ length: capacity }, (_, i) => gaUnitLabel(area.id, i));\n}\n\nexport function gaAreasOf(doc: ChartDoc): GAAreaObject[] {\n return allObjects(doc).filter((o): o is GAAreaObject => o.type === 'gaArea');\n}\n\nexport function isGaUnitLabel(label: string): boolean {\n return label.startsWith(PREFIX);\n}\n","/**\n * Section membership + hide/show resolution (Batch 3.3).\n *\n * A `SectionObject` is a polygon drawn over existing seat objects; an object\n * \"belongs\" to a section when its visual centre (`objectCenter`) falls inside\n * the section outline, first section in doc order winning. This is the same\n * spatial notion `objectCenter`'s doc-comment describes, resolved once here so\n * BOTH the event manager (Sections tab counts) and the buyer picker (omit\n * hidden seats) agree on which seats live in which section.\n *\n * Hiding is per-EVENT (the EventDO holds the hidden id set), not a chart edit —\n * so a republish of the chart never disturbs it. A hidden id may be a section\n * id, a zone id (hides every section in the zone), or `UNGROUPED_ID` (the\n * catch-all bucket of seat objects that sit in no section).\n */\nimport type { ChartDoc, ChartObject, SectionObject } from './types';\nimport { allObjects, expandBooth, expandRow, expandTable, objectCenter, pointInPolygonWithHoles } from './layout';\nimport { gaUnitLabels } from './ga';\n\n/** Synthetic section id for seat objects that fall in no drawn section. */\nexport const UNGROUPED_ID = '__ungrouped__';\n\n/**\n * A per section/zone availability window (Batch 3.4). Wire-compatible with the\n * EventDO's own `AvailabilityRule`. Absence of a rule for an id = on sale.\n * 'hidden' — manual: hidden until the organizer reveals it (3.3).\n * 'timed' — hidden until `revealAt` (epoch ms), then auto-reveals.\n * 'threshold' — auto-reveals once the on-sale inventory is `thresholdPct`% sold.\n * 'closed' — visible to buyers but not purchasable (rendered flat grey);\n * unlike 'hidden', the seats stay on the map, just off sale.\n * `labels` are the seat labels the id governs, so a threshold's denominator can\n * exclude still-hidden seats.\n */\nexport interface AvailabilityRule {\n mode: 'hidden' | 'timed' | 'threshold' | 'closed';\n revealAt?: number;\n thresholdPct?: number;\n labels?: string[];\n}\n\nexport interface SectionNode {\n /** Section id (a `SectionObject.id`, or `UNGROUPED_ID`). */\n id: string;\n label: string;\n /** Zone id this section points at (`SectionObject.zone`), if any. */\n zone?: string;\n /** Total seats across the member objects. */\n seatCount: number;\n /** Ids of the seat-bearing objects that belong to this section. */\n objectIds: string[];\n /** Seat labels across the member objects (for availability-rule denominators). */\n seatLabels: string[];\n}\n\n/** Seat labels produced by one seat-bearing object (rows/tables/booths); [] otherwise. */\nfunction objectSeatLabels(o: ChartObject): string[] {\n if (o.type === 'row') return expandRow(o).map((s) => s.label);\n if (o.type === 'table') return expandTable(o).map((s) => s.label);\n if (o.type === 'booth') return expandBooth(o).map((s) => s.label);\n if (o.type === 'gaArea') return gaUnitLabels(o);\n return [];\n}\n\nfunction isSeatObject(o: ChartObject): o is Extract<ChartObject, { type: 'row' | 'table' | 'booth' | 'gaArea' }> {\n return o.type === 'row' || o.type === 'table' || o.type === 'booth' || o.type === 'gaArea';\n}\n\nfunction samePoints(left: Array<{ x: number; y: number }>, right: Array<{ x: number; y: number }>): boolean {\n return left.length === right.length\n && left.every((point, index) => point.x === right[index].x && point.y === right[index].y);\n}\n\nfunction sameGASurfaceAsSection(object: ChartObject, section: SectionObject): boolean {\n if (object.type !== 'gaArea' || !samePoints(object.points, section.outline)) return false;\n const objectHoles = object.holes ?? [];\n const sectionHoles = section.holes ?? [];\n return objectHoles.length === sectionHoles.length\n && objectHoles.every((hole, index) => samePoints(hole, sectionHoles[index]));\n}\n\n/**\n * Resolve section membership for a chart. Returns one node per drawn section\n * (doc order), a synthetic \"Ungrouped\" node for loose seat objects (null when\n * every seat sits in a section), and the object→section id map.\n */\nexport function computeSections(doc: ChartDoc): {\n sections: SectionNode[];\n ungrouped: SectionNode | null;\n /** seat-object id → owning section id (or `UNGROUPED_ID`). */\n objectToSection: Map<string, string>;\n} {\n // Span all floors (Batch 5) — a multi-floor chart's sections live in floors[];\n // single-floor charts fall through to doc.objects. Section ids are chart-unique.\n const objs = allObjects(doc);\n const sectionObjs = objs.filter((o): o is SectionObject => o.type === 'section');\n const nodes = new Map<string, SectionNode>();\n for (const s of sectionObjs) {\n const logicalId = s.logicalSectionId ?? s.id;\n const existing = nodes.get(logicalId);\n if (existing) {\n // Validation owns disagreement reporting; keep the first component's\n // public identity deterministic if an invalid document reaches here.\n continue;\n }\n nodes.set(logicalId, {\n id: logicalId,\n label: s.displayLabel || s.label || 'Section',\n zone: s.zone,\n seatCount: 0,\n objectIds: [],\n seatLabels: [],\n });\n }\n const ungrouped: SectionNode = { id: UNGROUPED_ID, label: 'Other seats', seatCount: 0, objectIds: [], seatLabels: [] };\n const objectToSection = new Map<string, string>();\n\n for (const obj of objs) {\n if (!isSeatObject(obj)) continue;\n const labels = objectSeatLabels(obj);\n if (labels.length === 0) continue;\n // Deterministically generated reference inventory carries durable ownership.\n // Prefer the named logical section when its geometry confirms that claim: a\n // concave GA surface can have an arithmetic centre outside its own shell,\n // while malformed provenance must not pull a truly standalone area inside.\n const referencedLogicalId = obj.referenceInventorySource?.logicalSectionId;\n const c = objectCenter(obj);\n const referencedOwner = referencedLogicalId\n ? sectionObjs.find((section) => (\n (section.logicalSectionId ?? section.id) === referencedLogicalId\n && (sameGASurfaceAsSection(obj, section) || pointInPolygonWithHoles(c, section.outline, section.holes))\n ))\n : undefined;\n // Ordinary authored inventory still uses the first drawn section (doc order)\n // whose outline contains the visual centre.\n const owner = referencedOwner ?? sectionObjs.find((s) => pointInPolygonWithHoles(c, s.outline, s.holes));\n const node = owner ? nodes.get(owner.logicalSectionId ?? owner.id)! : ungrouped;\n node.seatCount += labels.length;\n node.objectIds.push(obj.id);\n node.seatLabels.push(...labels);\n objectToSection.set(obj.id, node.id);\n }\n\n return {\n sections: [...nodes.values()],\n ungrouped: ungrouped.objectIds.length ? ungrouped : null,\n objectToSection,\n };\n}\n\n/** Is a drawn section hidden under `hidden` — directly, or via its zone? */\nexport function isSectionHidden(s: SectionObject, hidden: ReadonlySet<string>): boolean {\n return hidden.has(s.id)\n || (!!s.logicalSectionId && hidden.has(s.logicalSectionId))\n || (!!s.zone && hidden.has(s.zone));\n}\n\n/**\n * The set of seat-object ids to omit from the buyer view for a given hidden id\n * set. An object is hidden when its owning section is hidden (directly or via\n * zone), or it is ungrouped and the catch-all bucket is hidden.\n */\nexport function hiddenObjectIds(doc: ChartDoc, hidden: ReadonlySet<string>): Set<string> {\n const out = new Set<string>();\n if (!hidden.size) return out;\n const { sections, ungrouped, objectToSection } = computeSections(doc);\n const hiddenSectionIds = new Set<string>();\n const zoneById = new Map(sections.map((s) => [s.id, s.zone] as const));\n for (const s of sections) {\n const zone = zoneById.get(s.id);\n if (hidden.has(s.id) || (zone && hidden.has(zone))) hiddenSectionIds.add(s.id);\n }\n const ungroupedHidden = !!ungrouped && hidden.has(UNGROUPED_ID);\n for (const [objId, secId] of objectToSection) {\n if (hiddenSectionIds.has(secId) || (ungroupedHidden && secId === UNGROUPED_ID)) out.add(objId);\n }\n return out;\n}\n\n/**\n * A copy of the doc with hidden sections' member objects removed, plus the\n * hidden section overlays themselves (so no empty block renders). Returns the\n * SAME reference when nothing is hidden — callers can skip a re-render on `===`.\n */\nexport function applyHidden(doc: ChartDoc, hidden: ReadonlySet<string>): ChartDoc {\n if (!hidden.size) return doc;\n const hide = hiddenObjectIds(doc, hidden);\n const hiddenSet = hidden instanceof Set ? hidden : new Set(hidden);\n const keep = (o: ChartObject): boolean => {\n if (hide.has(o.id)) return false;\n if (o.type === 'section' && isSectionHidden(o, hiddenSet)) return false;\n return true;\n };\n // Multi-floor (Batch 5): filter each floor + the floor-0 mirror.\n if (doc.floors && doc.floors.length) {\n let changed = false;\n const floors = doc.floors.map((f) => {\n const objects = f.objects.filter(keep);\n if (objects.length !== f.objects.length) changed = true;\n return objects.length === f.objects.length ? f : { ...f, objects };\n });\n if (!changed) return doc;\n return { ...doc, floors, objects: floors[0].objects };\n }\n const objects = doc.objects.filter(keep);\n if (objects.length === doc.objects.length) return doc;\n return { ...doc, objects };\n}\n","/**\n * SeatmapRenderer — the shared canvas rendering core (buyer picker shell).\n *\n * Uses Konva directly with per-module imports to keep the bundle lean. The\n * whole point of the spike is staying smooth at ~5,000 seats on mobile, so the\n * hot paths lean on: layer bitmap caching + listening(false) when zoomed out,\n * per-seat fill updates (never full rebuilds) on status change, and viewport-\n * only label rendering rebuilt on interaction-end rather than per frame.\n */\n\n// Core (not Global): Core assembles the real Konva namespace — Global alone\n// lacks DD/Util and Stage._pointermove dereferences Konva.DD unconditionally.\nimport { Konva } from 'konva/lib/Core';\nimport { Stage } from 'konva/lib/Stage';\nimport { Layer } from 'konva/lib/Layer';\nimport { Group } from 'konva/lib/Group';\nimport { Circle } from 'konva/lib/shapes/Circle';\nimport { Rect } from 'konva/lib/shapes/Rect';\nimport { Ellipse } from 'konva/lib/shapes/Ellipse';\nimport { Line } from 'konva/lib/shapes/Line';\nimport { Text } from 'konva/lib/shapes/Text';\nimport { Image as KImage } from 'konva/lib/shapes/Image';\nimport type { KonvaEventObject } from 'konva/lib/Node';\nimport { Shape } from 'konva/lib/Shape';\n\nimport type {\n AccessibilityType,\n ChartDoc,\n ChartTheme,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n Point,\n RenderedBookableLabelEvidence,\n RenderedGAAreaEvidence,\n RenderedFreeTextEvidence,\n RendererQualityEvidence,\n RendererOptions,\n SeatStatus,\n SectionOutlinePath,\n SectionObject,\n} from '../core/types';\nimport { accessibilityRingColor } from '../core/types';\nimport { chartBounds, expandChart, floorsOf, pointInPolygonWithHoles, polygonLabelPoint, stackFloors } from '../core/layout';\nimport {\n BOOTH_LABEL_FONT_SIZE,\n GA_CAPACITY_LABEL_FONT_SIZE,\n GA_FILL_OPACITY,\n GA_LABEL_FONT_SIZE,\n MIN_VISIBLE_BOOKABLE_LABEL_PX,\n SEAT_LABEL_FONT_SIZE,\n bookableMarkerLabel,\n compositeHexOver,\n isBookableLabelLegibleAtScale,\n stateAwareBookableLabelInk,\n} from '../core/chartRenderRules';\nimport { t } from '../i18n';\nimport { formatMoney } from '../lib/money';\n\nconst SEAT_RADIUS = 9;\n/** Absolute scale at which a seat (r=9) renders ~legibly (~8px). */\nconst SEAT_LEGIBLE_SCALE = 0.9;\n/** Below this absolute scale we swap seats for a cached bitmap. */\nconst CACHE_THRESHOLD = 0.55 * SEAT_LEGIBLE_SCALE;\n/** First scale where a 7u seat label reaches the shared rendered-size floor. */\nconst LABEL_SCALE = MIN_VISIBLE_BOOKABLE_LABEL_PX / SEAT_LABEL_FONT_SIZE;\nconst MIN_FITTED_SEAT_LABEL_FONT_SIZE = 4;\n/** Extra screen-px of slack around a seat circle that still counts as a tap on\n * it. Gives small seats a finger-friendly hit target (§4 \"hit ≥ 24px\") so a\n * near-miss on mobile still selects the nearest seat instead of doing nothing. */\nconst SEAT_TAP_SLOP_PX = 14;\n/** At/below this scale, sections read as clean labelled shells (seats hidden). */\nconst SECTION_PROMINENT_SCALE = 0.45 * SEAT_LEGIBLE_SCALE;\n/**\n * Above this scale, seats are fully shown (dots); between here and\n * SECTION_PROMINENT the block melts in. Set high so a big sectioned chart OPENS\n * as named blocks and only reveals seats once you zoom in close.\n */\nconst BLOCK_MELT_TOP = 0.9 * SEAT_LEGIBLE_SCALE;\n/** Camera scale used after a section drill-in. Keeping this above the block\n * melt band guarantees that a section tap lands on live, legible seats even\n * when a narrow phone viewport cannot frame the whole section at that scale. */\nconst SEAT_FOCUS_SCALE = Math.max(SEAT_LEGIBLE_SCALE * 1.1, BLOCK_MELT_TOP);\n/** Ignore normal finger jitter before treating a tap as a map pan. */\nconst PAN_START_SLOP_PX = 8;\n/**\n * Below this scale, ZONE blocks/labels take over from per-section detail (the\n * farthest rung). ~0.55× the section rung so: seats → section blocks → zones.\n */\nconst ZONE_PROMINENT_SCALE = 0.55 * SECTION_PROMINENT_SCALE;\n/** Never label more than this many seats at once (viewport clutter guard). */\nconst MAX_LABELS = 700;\n/**\n * Manage-mode marquee: above this many selected seats we stop drawing per-seat\n * selection-ring nodes (they'd be an invisible speck at that zoom and a huge\n * node count on a 13k arena) and rely on the seat-fill selection paint instead.\n * Selection membership (getSelection / bulk block) is unaffected.\n */\nconst MARQUEE_RING_CAP = 2500;\n\n// ---- Isometric (\"3D\") view mode -------------------------------------------\n/** Full-iso rotation of the chart about its centre (degrees). */\nconst ISO_ANGLE_DEG = -11.5;\n/** Full-iso vertical squash (1 = flat). */\nconst ISO_SQUASH = 0.58;\n/** World units a section (and its members) lift per elevation step at full iso. */\nconst LIFT_PER_STEP = 58;\n/** Flat⇄iso tween duration (ms); reduced-motion snaps. */\nconst ISO_TWEEN_MS = 320;\n/** Buyer camera travel should be easy to follow without feeling sluggish. */\nconst CAMERA_GLIDE_MS = 650;\n\n// ---- Section/zone LOD (\"melt\") tuning -------------------------------------\n/** Section overview is a semantic hierarchy, not a price/availability heatmap. */\nconst BLOCK_FILL_ALPHA = 1;\nconst SECTION_STROKE_PX = 2;\nconst LIGHT_OVERVIEW_SECTION_FILL = '#e5e7eb';\nconst LIGHT_OVERVIEW_SECTION_STROKE = '#c7cbd1';\nconst LIGHT_OVERVIEW_SECTION_INK = '#595f69';\nconst LIGHT_OVERVIEW_FOCAL_FILL = '#d1d5db';\nconst LIGHT_OVERVIEW_FOCAL_STROKE = '#b8bdc4';\nconst DARK_OVERVIEW_SECTION_FILL = '#273142';\nconst DARK_OVERVIEW_SECTION_STROKE = '#526078';\nconst DARK_OVERVIEW_SECTION_INK = '#f1f5f9';\nconst DARK_OVERVIEW_FOCAL_FILL = '#374151';\nconst DARK_OVERVIEW_FOCAL_STROKE = '#64748b';\n/** Screen-space target sizes (px) for scale-compensated section/zone labels. */\nconst SECTION_LABEL_PX = 20;\nconst MIN_SECTION_LABEL_PX = 12;\nconst ZONE_LABEL_PX = 18;\nconst ZONE_SUB_PX = 12;\nconst HIERARCHY_PILL_BACKGROUND = '#111827';\n\nconst HELD_FILL = '#6b7280';\nconst TAKEN_FILL = '#374151';\nconst NFS_STROKE = '#4b5563';\n/** Phase 2 event-level `closed` section: a flat desaturated slate block (label\n * kept), distinct from the per-seat availability-grey. Seats inside read grey\n * at 40% and are not pickable (per chart-design-standards §3). */\nconst CLOSED_SEAT_FILL = '#4b5563';\nconst CLOSED_SEAT_OPACITY = 0.4;\n/** AXS section-focus: non-focused sections dim to this opacity. */\nconst FOCUS_DIM_OPACITY = 0.16;\n/** Light/neutral backdrop panel drawn behind the focused section's seats. */\nconst FOCUS_BACKDROP_FILL = 'rgba(244,246,248,0.06)';\n/** Okabe-Ito colorblind-safe hues (black dropped — unreadable on dark charts).\n * Categories map to these by their doc order when colorblind mode is on. */\nconst CB_PALETTE = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7'];\n\n/** Does a seat satisfy a filter? `[]` means \"any accessible seat\". */\nfunction seatMatchesAccess(seat: ExpandedSeat, filter: AccessibilityType[]): boolean {\n if (filter.length === 0) return !!seat.accessible;\n return !!seat.accessibility?.some((t) => filter.includes(t));\n}\n\n// Theme fallbacks (dark defaults) — used when doc.theme leaves a slot unset.\nconst DEF_SEAT_LABEL = '#0b1220';\nconst DEF_SELECTION = '#ffffff';\n/** Selection/hover ring on LIGHT canvases — a white ring vanishes there. */\nconst DEF_SELECTION_ON_LIGHT = '#0b1220';\nconst DEF_DECOR_FILL = '#232c40';\nconst DEF_TEXT = '#8b93a7';\nconst DEF_CANVAS_BACKGROUND = '#0e1117';\n\n/**\n * Relative luminance (0..1) of a CSS color — supports #rgb, #rrggbb and\n * rgb()/rgba(). Returns NaN for anything unparseable (gradients, ''), which\n * callers must treat as \"unknown → assume dark\" to preserve dark defaults.\n */\nfunction colorLuminance(color: string): number {\n const s = color.trim();\n let r = NaN;\n let g = NaN;\n let b = NaN;\n const hex = /^#([\\da-f]{3}|[\\da-f]{6})$/i.exec(s);\n if (hex) {\n const h = hex[1].length === 3 ? hex[1].split('').map((c) => c + c).join('') : hex[1];\n r = parseInt(h.slice(0, 2), 16);\n g = parseInt(h.slice(2, 4), 16);\n b = parseInt(h.slice(4, 6), 16);\n } else {\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/.exec(s);\n if (rgb) {\n r = +rgb[1];\n g = +rgb[2];\n b = +rgb[3];\n }\n }\n if (Number.isNaN(r)) return NaN;\n return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;\n}\n\n/** Light enough that white UI accents (selection ring) lose contrast. */\nfunction isLightColor(color: string): boolean {\n const lum = colorLuminance(color);\n return !Number.isNaN(lum) && lum > 0.6;\n}\n\n/** Normalize the opaque CSS colours used by supported buyer surfaces. */\nfunction opaqueColorHex(color: string): string | null {\n const value = color.trim();\n const hex = /^#([\\da-f]{3}|[\\da-f]{6})$/i.exec(value);\n if (hex) {\n const expanded = hex[1].length === 3\n ? hex[1].split('').map((channel) => channel + channel).join('')\n : hex[1];\n return `#${expanded.toLowerCase()}`;\n }\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)$/i.exec(value);\n if (!rgb || (rgb[4] != null && Number(rgb[4]) < 0.999)) return null;\n const channels = [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];\n if (channels.some((channel) => !Number.isInteger(channel) || channel < 0 || channel > 255)) return null;\n return `#${channels.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`;\n}\n\ninterface OverviewPalette {\n sectionFill: string;\n sectionStroke: string;\n sectionInk: string;\n focalFill: string;\n focalStroke: string;\n}\n\nfunction overviewPalette(canvasBackground: string): OverviewPalette {\n return isLightColor(canvasBackground)\n ? {\n sectionFill: LIGHT_OVERVIEW_SECTION_FILL,\n sectionStroke: LIGHT_OVERVIEW_SECTION_STROKE,\n sectionInk: LIGHT_OVERVIEW_SECTION_INK,\n focalFill: LIGHT_OVERVIEW_FOCAL_FILL,\n focalStroke: LIGHT_OVERVIEW_FOCAL_STROKE,\n }\n : {\n sectionFill: DARK_OVERVIEW_SECTION_FILL,\n sectionStroke: DARK_OVERVIEW_SECTION_STROKE,\n sectionInk: DARK_OVERVIEW_SECTION_INK,\n focalFill: DARK_OVERVIEW_FOCAL_FILL,\n focalStroke: DARK_OVERVIEW_FOCAL_STROKE,\n };\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.max(lo, Math.min(hi, v));\n\n/** Read a custom attr off an event target (Stage | Shape union isn't callable directly). */\nfunction seatIdOf(target: unknown): string | undefined {\n const n = target as { getAttr?: (k: string) => unknown } | null;\n return (n?.getAttr?.('seatId') as string | undefined) ?? undefined;\n}\n\n/** Mix a #rrggbb colour toward white by `amt` (0..1). */\nfunction lighten(hex: string, amt: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const r = (n >> 16) & 255;\n const g = (n >> 8) & 255;\n const b = n & 255;\n const mix = (c: number) => Math.round(c + (255 - c) * amt);\n return `#${((1 << 24) | (mix(r) << 16) | (mix(g) << 8) | mix(b)).toString(16).slice(1)}`;\n}\n\n/** Mix a #rrggbb colour toward black by `amt` (0..1). */\nfunction darken(hex: string, amt: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const mix = (c: number) => Math.round(c * (1 - amt));\n return `#${((1 << 24) | (mix((n >> 16) & 255) << 16) | (mix((n >> 8) & 255) << 8) | mix(n & 255)).toString(16).slice(1)}`;\n}\n\n/** Axis-aligned bounds of a polygon (no padding). */\nfunction polyBounds(pts: Point[]): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n}\n\nfunction rotatedRectPoints(center: Point, width: number, height: number, rotation: number): Point[] {\n const radians = rotation * Math.PI / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return [\n { x: -width / 2, y: -height / 2 },\n { x: width / 2, y: -height / 2 },\n { x: width / 2, y: height / 2 },\n { x: -width / 2, y: height / 2 },\n ].map((point) => ({\n x: center.x + point.x * cos - point.y * sin,\n y: center.y + point.x * sin + point.y * cos,\n }));\n}\n\nfunction pointsBounds(points: Point[]): { x: number; y: number; width: number; height: number } {\n const bounds = polyBounds(points);\n return { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height };\n}\n\n/**\n * Prove the whole rotated label rectangle remains on the filled shell. Sampling\n * a small grid (rather than corners alone) also catches a concave edge or aisle\n * hole passing through the middle of otherwise-valid corners.\n */\nfunction rotatedRectFitsPolygon(\n center: Point,\n width: number,\n height: number,\n rotation: number,\n outer: Point[],\n holes: Point[][],\n): boolean {\n const radians = rotation * Math.PI / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n for (let yStep = 0; yStep <= 4; yStep++) {\n for (let xStep = 0; xStep <= 6; xStep++) {\n const localX = width * (xStep / 6 - 0.5);\n const localY = height * (yStep / 4 - 0.5);\n const point = {\n x: center.x + localX * cos - localY * sin,\n y: center.y + localX * sin + localY * cos,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) return false;\n }\n }\n return true;\n}\n\n/** Centre-first interior anchors used when a hole/concavity occupies the shell centre. */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\n const centre = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n const points: Point[] = [preferred];\n for (let row = 1; row < 12; row += 1) {\n for (let column = 1; column < 12; column += 1) {\n const point = {\n x: bounds.x + bounds.width * column / 12,\n y: bounds.y + bounds.height * row / 12,\n };\n if (pointInPolygonWithHoles(point, outer, holes)) points.push(point);\n }\n }\n return points\n .sort((left, right) => Math.hypot(left.x - centre.x, left.y - centre.y)\n - Math.hypot(right.x - centre.x, right.y - centre.y))\n .filter((point, index, all) => index === all.findIndex((other) => (\n Math.abs(other.x - point.x) < 1e-6 && Math.abs(other.y - point.y) < 1e-6\n )));\n}\n\nfunction polygonWithHolesShape(\n outer: Point[],\n holes: Point[][] | undefined,\n attrs: { fill?: string; stroke?: string; strokeWidth?: number; opacity?: number; listening?: boolean },\n outerPath?: SectionOutlinePath,\n): Shape {\n const signedArea = (points: Point[]): number => points.reduce((sum, point, index) => {\n const next = points[(index + 1) % points.length];\n return sum + point.x * next.y - next.x * point.y;\n }, 0);\n const outerClockwise = signedArea(outer) > 0;\n return new Shape({\n ...attrs,\n sceneFunc(context, shape) {\n context.beginPath();\n const polygonPath = (points: Point[]) => {\n if (!points.length) return;\n context.moveTo(points[0].x, points[0].y);\n for (let index = 1; index < points.length; index += 1) context.lineTo(points[index].x, points[index].y);\n context.closePath();\n };\n const vectorPath = (path: SectionOutlinePath) => {\n context.moveTo(path.start.x, path.start.y);\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') context.lineTo(segment.end.x, segment.end.y);\n else if (segment.kind === 'arc') context.arc(\n segment.center.x,\n segment.center.y,\n segment.radius,\n Math.atan2(current.y - segment.center.y, current.x - segment.center.x),\n Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x),\n !segment.clockwise,\n );\n else context.bezierCurveTo(\n segment.control1.x, segment.control1.y,\n segment.control2.x, segment.control2.y,\n segment.end.x, segment.end.y,\n );\n current = segment.end;\n }\n context.closePath();\n };\n if (outerPath) vectorPath(outerPath);\n else polygonPath(outer);\n // Canvas' default non-zero rule cuts a hole only when its winding is the\n // opposite of the outer path. Normalize here so imported docs do not\n // depend on the order in which a client happened to serialize vertices.\n for (const hole of holes ?? []) {\n const holeClockwise = signedArea(hole) > 0;\n polygonPath(holeClockwise === outerClockwise ? [...hole].reverse() : hole);\n }\n context.fillStrokeShape(shape);\n },\n perfectDrawEnabled: false,\n });\n}\n\n/** #rrggbb → rgba() string at alpha `a`; passes non-hex through unchanged. */\nfunction rgba(hex: string, a: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${a})`;\n}\n\n/** Parse #rrggbb → [r,g,b] (0..255); null for non-hex. */\nfunction hexToRgb(hex: string): [number, number, number] | null {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return null;\n const n = parseInt(m[1], 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nconst toHex = (r: number, g: number, b: number): string =>\n `#${((1 << 24) | (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b)).toString(16).slice(1)}`;\n\n/**\n * Count-weighted RGB blend of member seat colours — a section reads as its\n * price makeup, not one flat colour. Falls back to `fallback` when empty.\n */\nfunction mixColors(parts: Array<{ hex: string; w: number }>, fallback: string): string {\n let r = 0;\n let g = 0;\n let b = 0;\n let tw = 0;\n for (const p of parts) {\n const rgb = hexToRgb(p.hex);\n if (!rgb || p.w <= 0) continue;\n r += rgb[0] * p.w;\n g += rgb[1] * p.w;\n b += rgb[2] * p.w;\n tw += p.w;\n }\n return tw > 0 ? toHex(r / tw, g / tw, b / tw) : fallback;\n}\n\n/** Linear interpolate between two #rrggbb colours (t 0..1); passes `a` through if unparseable. */\nfunction lerpColor(a: string, b: string, t: number): string {\n const ca = hexToRgb(a);\n const cb = hexToRgb(b);\n if (!ca || !cb) return a;\n return toHex(ca[0] + (cb[0] - ca[0]) * t, ca[1] + (cb[1] - ca[1]) * t, ca[2] + (cb[2] - ca[2]) * t);\n}\n\n/** Per-section render state for the block LOD rung (fills, labels, membership). */\ninterface SectionRender {\n id: string;\n /** Shared public management identity for disconnected visual components. */\n logicalId: string;\n label: string;\n outline: Point[];\n outlinePath?: SectionOutlinePath;\n holes: Point[][];\n centroid: Point;\n /** Deterministic centre-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n zone?: string;\n /** Seats whose centre falls inside the outline (first-match, doc order). */\n memberIds: string[];\n total: number;\n free: number;\n /** Category-mix (or explicit override) fill BEFORE the availability tint. */\n baseFill: string;\n outlineTint: string;\n /** Faint outline drawn under seats — the existing near-zoom look, untouched. */\n outlinePoly: Shape;\n /** Solid block fill that melts in at the block rung. */\n blockPoly: Shape;\n /** Section name (always drawn; brightens at the block rung, hides at zone rung). */\n nameLabel: Text;\n /** Availability retained for focused/detail UI, never painted on the overview shell. */\n subLabel: Text;\n /** Preferred name ink (labelStyle.color or the overview default) fed through\n * auto-contrast each frame so an authored colour survives the block melt. */\n preferredInk: string;\n /** labelStyle.size relative to the default (1 = default), scaling the fitted\n * screen-px band so a larger authored label reads larger in the overview. */\n labelScale: number;\n /** Responsive fit decisions for the current stage scale and local polygon span. */\n nameLabelFits: boolean;\n subLabelFits: boolean;\n /** Tier height (0 = floor). Lifts the section + members in iso (\"3D\") view. */\n elevation: number;\n /**\n * When elevation > 0, the section's bg nodes + member seats live in these\n * groups so a single position offset lifts the whole tier in iso view.\n */\n liftGroupBg: Group | null;\n liftGroupSeat: Group | null;\n /** Extruded side faces (one per outline edge) shown only as isoT rises. */\n sideFaces: Line[];\n}\n\n/** Per-zone render state for the farthest LOD rung. */\ninterface ZoneRender {\n id: string;\n anchor: Point;\n back: Rect;\n background: string;\n label: Text;\n sub: Text | null;\n}\n\nexport class SeatmapRenderer implements ISeatmapRenderer {\n private container: HTMLDivElement;\n private opts: Required<Pick<RendererOptions, 'maxSelection'>> & RendererOptions;\n\n private stage: Stage;\n private bgLayer: Layer;\n private seatLayer: Layer;\n private overlayLayer: Layer;\n private labelGroup: Group;\n\n private seats: ExpandedSeat[] = [];\n private seatById = new Map<string, ExpandedSeat>();\n /** Multi-floor (Batch 5): the last-set chart + which floor we're rendering. */\n private chartDoc: ChartDoc | null = null;\n private activeFloorId = '';\n /** When true on a multi-floor chart, render ALL floors stacked (3D overview). */\n private stacked = false;\n /** Interactive node per seat/booth — a Circle for seats, a Rect for booths. */\n private circleById = new Map<string, Shape>();\n /** Booth block geometry, keyed by booth id (= the unit's rowId). */\n private boothDims = new Map<string, { width: number; height: number; rotation: number }>();\n /** Booth labels live with the booth shape but obey the shared rendered-size LOD. */\n private boothLabelById = new Map<string, Text>();\n /** Viewport seat labels are rebuilt after each settled camera change. */\n private seatLabelById = new Map<string, Text>();\n /** Authored free-text nodes obey the same rendered-size visibility floor. */\n private freeTextById = new Map<string, {\n objectId?: string;\n node: Text;\n background: string;\n kind: RenderedFreeTextEvidence['kind'];\n categoryKey?: string;\n }>();\n /** Stage/rink landmarks retain a readable screen-space caption at overview. */\n private primaryFocalLabels = new Map<Text, number>();\n /** GA paint and text share price/highlight filter state. */\n private gaById = new Map<string, {\n label: string;\n capacity: number;\n categoryKey: string;\n points: Point[];\n polygon: Shape;\n effectiveBackground: string;\n /** GA inventory contained by a section is detail, not overview paint. */\n sectionId?: string;\n }>();\n private statusById = new Map<string, SeatStatus>();\n private catColor = new Map<string, string>();\n private theme: ChartTheme = {};\n /** Opaque paint actually visible behind transparent Konva canvases. */\n private canvasBackground = DEF_CANVAS_BACKGROUND;\n /** Effective selection/hover ring color — resolved per chart in setChart(). */\n private effSelection: string = DEF_SELECTION;\n /** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */\n private colorblind = false;\n /** Category order from the doc — the stable index into the CB palette. */\n private catOrder: string[] = [];\n\n private selection = new Set<string>();\n /** Whole-seat/block selection markers: outline + non-colour check cue. */\n private selectionMarkers = new Map<string, Group>();\n /** Held by this picker instance, not by another buyer. */\n private ownedHold = new Set<string>();\n /** One selected seat being inspected before it is committed to the cart. */\n private selectionFocusId: string | null = null;\n private hoverRing: Circle;\n /** Keyboard-navigation focus ring + the currently focused seat id. */\n private focusRing: Circle;\n private focusedId: string | null = null;\n /**\n * Accessibility filter: `null` = off; `[]` = dim all non-accessible free seats;\n * a type list = dim free seats lacking any of those accommodations.\n */\n private accessFilter: AccessibilityType[] | null = null;\n /** Category highlight (legend hover): dims free seats NOT of this category. */\n private categoryHighlight: string | null = null;\n /** Price-band filter (F4): dim free seats whose category is NOT in this set. */\n private categoryFilter: Set<string> | null = null;\n\n // Section/zone overlays (bgLayer) — the 3-rung LOD: seats → section blocks →\n // zone blocks. Kept for the melt restyle and for hit-testing a zoomed-out tap.\n private sections: SectionRender[] = [];\n private zones: ZoneRender[] = [];\n private seatSection = new Map<string, SectionRender>();\n private catPrice = new Map<string, number>();\n /** ISO 4217 currency for on-map \"FROM …\" prices (undefined ⇒ money default). */\n private currency: string | undefined;\n /** Section/zone ids to render dimmed (organizer manager: held-back inventory). */\n private dimmedSections = new Set<string>();\n /** Organizer control-room velocity overlay; absent on buyer surfaces. */\n private sectionHeat = new Map<string, number>();\n /** Phase 2: section/zone ids in the event-level `closed` state — flat grey\n * block, seats greyed + not pickable, but the section stays rendered. */\n private closedSections = new Set<string>();\n /** AXS section-focus: the currently-focused section id (others dim), or null. */\n private focusedSectionId: string | null = null;\n /** Light backdrop panel drawn behind the focused section (removed on clear). */\n private focusBackdrop: Group | null = null;\n /** Object id → floor id (multi-floor only) — resolves a deck tap in the 3D stack. */\n private objectFloor = new Map<string, string>();\n /** Zone id → colour (drives extruded side faces in iso view). */\n private zoneColor = new Map<string, string>();\n private hasSections = false;\n /** seatLayer carries Text (booth labels) — gate the upright-label scan. */\n private hasBoothText = false;\n\n // Isometric (\"3D\") view — an affine skew/rotate + elevation lift, tweened.\n /** 0 = flat (default), 1 = full isometric; animated by setViewMode. */\n private isoT = 0;\n private isoTarget = 0;\n private isoRaf = 0;\n /** Chart centre the iso projection pivots about (bounds centre). */\n private isoCentre = { x: 0, y: 0 };\n /** rAF for an in-flight camera glide (focusRegion / setRung); 0 = none. */\n private glideRaf = 0;\n /** Set in destroy() so an in-flight iso tween bails. */\n private destroyed = false;\n /** Cached scale the section/zone labels were last sized for (scale-compensation). */\n private lodScale = 0;\n /** prefers-reduced-motion → hard-swap rungs instead of cross-fading. */\n private reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n private fitScale = 1;\n /** Effective seat radius (base × theme.seatScale), set per chart in setChart. */\n private seatR = SEAT_RADIUS;\n private bounds = { x: 0, y: 0, width: 1, height: 1 };\n private cached = false;\n private dpr = Math.min(typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, 2);\n\n private rafId = 0;\n private frames = 0;\n private lastFpsAt = 0;\n private recacheTimer: ReturnType<typeof setTimeout> | null = null;\n private resizeObs: ResizeObserver | null = null;\n /** Coalesces bursty view-change sources (pointermove, wheel) into ≤1 callback/frame. */\n private viewChangeRaf = 0;\n\n // Gesture state — pan/pinch are handled with raw pointer events on the\n // container (Konva stage dragging is off; its touch pipeline proved\n // unreliable for multi-touch on real devices).\n private pointers = new Map<number, { x: number; y: number }>();\n private pinch: { startDist: number; startScale: number; worldMid: { x: number; y: number } } | null = null;\n private panLast: { x: number; y: number } | null = null;\n private panStart: { x: number; y: number } | null = null;\n private panStarted = false;\n /** Maximum displacement from gesture start — suppress taps only after a real pan/pinch. */\n private moved = 0;\n /**\n * Manage-mode rubber-band marquee (option-gated). `start`/`cur` are WORLD-space\n * points (overlayLayer rides the stage transform); `rect` is the on-canvas\n * selection band. Null except during an active manage-mode drag.\n */\n private marquee: { start: { x: number; y: number }; rect: Rect } | null = null;\n private marqueeCur: { x: number; y: number } | null = null;\n\n constructor(container: HTMLDivElement, options: RendererOptions = {}) {\n this.container = container;\n this.opts = { maxSelection: 10, selectableStatuses: ['free'], ...options };\n this.currency = options.currency;\n\n Konva.pixelRatio = this.dpr;\n\n this.stage = new Stage({\n container,\n width: container.clientWidth || 1,\n height: container.clientHeight || 1,\n draggable: false, // pan/pinch are ours, via pointer events\n });\n\n container.style.touchAction = 'none';\n container.addEventListener('pointerdown', this.onPointerDown, { passive: false });\n container.addEventListener('pointermove', this.onPointerMove, { passive: false });\n container.addEventListener('pointerup', this.onPointerEnd, { passive: false });\n container.addEventListener('pointercancel', this.onPointerEnd, { passive: false });\n\n // Keyboard accessibility: the canvas is focusable and navigable seat-by-seat.\n if (container.tabIndex < 0) container.tabIndex = 0;\n container.setAttribute('role', 'application');\n if (!container.getAttribute('aria-label')) {\n container.setAttribute('aria-label', t('map.aria'));\n }\n container.addEventListener('keydown', this.onKeyDown);\n\n this.bgLayer = new Layer({ listening: true });\n this.seatLayer = new Layer({ listening: true });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n\n this.hoverRing = new Circle({\n radius: SEAT_RADIUS + 2,\n stroke: '#ffffff',\n strokeWidth: 2,\n opacity: 0.85,\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(this.hoverRing);\n\n this.focusRing = new Circle({\n radius: SEAT_RADIUS + 3,\n stroke: '#38bdf8',\n strokeWidth: 2.5,\n dash: [4, 3],\n opacity: 0.95,\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(this.focusRing);\n\n this.stage.add(this.bgLayer, this.seatLayer, this.overlayLayer);\n\n this.wireInteraction();\n this.startFpsLoop();\n\n if (import.meta.env.DEV) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObs = new ResizeObserver(() => this.handleResize());\n this.resizeObs.observe(container);\n }\n }\n\n // ---- ISeatmapRenderer -----------------------------------------------------\n\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void {\n // Multi-floor: render the active floor (2D) or all floors stacked (3D). `view`\n // scopes the chart accordingly — single-floor charts pass through (=== doc).\n // A fresh chart (new ref) resets to 2D; a re-render (same ref) preserves the mode.\n if (doc !== this.chartDoc) this.stacked = false;\n this.chartDoc = doc;\n this.activeFloorId = opts?.floorId ?? floorsOf(doc)[0].id;\n // Object id → floor id, for resolving which deck a tap hit in the 3D stack\n // (stackFloors keeps object ids, so the map holds across the flatten).\n this.objectFloor.clear();\n if (doc.floors && doc.floors.length > 1) {\n for (const f of doc.floors) for (const o of f.objects) this.objectFloor.set(o.id, f.id);\n }\n const view = this.floorView(doc);\n this.focusedId = null;\n this.focusRing.visible(false);\n this.bgLayer.destroyChildren();\n this.seatLayer.destroyChildren();\n this.labelGroup.destroyChildren();\n this.circleById.clear();\n this.boothDims.clear();\n this.boothLabelById.clear();\n this.seatLabelById.clear();\n this.freeTextById.clear();\n this.primaryFocalLabels.clear();\n this.gaById.clear();\n for (const marker of this.selectionMarkers.values()) marker.destroy();\n this.selectionMarkers.clear();\n this.ownedHold.clear();\n this.selectionFocusId = null;\n this.statusById.clear();\n this.selection.clear();\n this.seatById.clear();\n this.cached = false;\n this.accessFilter = null;\n this.sections = [];\n this.zones = [];\n this.seatSection.clear();\n // Section focus is a transient camera/view state. Carrying a section id\n // across a floor switch can match nothing on the next floor and dim every\n // newly rendered section as though it were a non-focused sibling.\n this.focusedSectionId = null;\n this.focusBackdrop = null;\n this.catPrice.clear();\n this.zoneColor.clear();\n this.lodScale = 0;\n this.hasBoothText = false;\n // Reloading the chart resets the view to flat (identity layer transforms).\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n this.isoT = 0;\n this.isoTarget = 0;\n this.resetLayerTransforms();\n this.hasSections = view.objects.some((o) => o.type === 'section');\n for (const z of doc.zones ?? []) if (z.color) this.zoneColor.set(z.id, z.color);\n // Seats fade against the block fill during the melt; reset to fully opaque.\n this.seatLayer.opacity(1);\n this.hoverRing.visible(false);\n\n this.theme = doc.theme ?? {};\n // Adjustable seat size: a chart-level scale on the base radius. Clamped so\n // enlarged seats don't collide with typical row spacing (~24 units).\n this.seatR = clamp(this.theme.seatScale ?? 1, 0.7, 1.6) * SEAT_RADIUS;\n // Resolve an unthemed embed against its real host surface once, then pin\n // that opaque paint on the renderer container. Rendering decisions and QA\n // evidence must describe the same pixels even when Konva stays transparent.\n this.container.style.background = '';\n this.canvasBackground = this.resolveCanvasBackground();\n this.container.style.background = this.canvasBackground;\n this.effSelection = this.resolveSelectionColor();\n this.hoverRing.stroke(this.effSelection);\n this.hoverRing.radius(this.seatR + 2);\n\n this.catColor.clear();\n this.catPrice.clear();\n this.catOrder = doc.categories.map((c) => c.key);\n for (const c of doc.categories) {\n this.catColor.set(c.key, c.color);\n if (typeof c.price === 'number') this.catPrice.set(c.key, c.price);\n }\n\n for (const obj of view.objects) {\n if (obj.type === 'booth') {\n this.boothDims.set(obj.id, { width: obj.width, height: obj.height, rotation: obj.rotation });\n }\n }\n\n this.seats = expandChart(view);\n for (const s of this.seats) {\n this.seatById.set(s.id, s);\n this.statusById.set(s.id, 'free');\n }\n\n this.renderBackground(view);\n this.renderSeats();\n // re-add overlay furniture wiped by destroyChildren above\n this.overlayLayer.add(this.labelGroup);\n this.overlayLayer.add(this.hoverRing);\n\n this.bounds = chartBounds(view);\n this.isoCentre = { x: this.bounds.x + this.bounds.width / 2, y: this.bounds.y + this.bounds.height / 2 };\n this.zoomToFit();\n }\n\n /** The chart to render: all floors stacked (3D overview), the active floor, or\n * the whole chart for single-floor charts. */\n private floorView(doc: ChartDoc): ChartDoc {\n if (!doc.floors || !doc.floors.length) return doc;\n if (this.stacked && doc.floors.length >= 2) return stackFloors(doc);\n const floor = doc.floors.find((f) => f.id === this.activeFloorId) ?? doc.floors[0];\n return { ...doc, objects: floor.objects, focalPoint: floor.focalPoint, backgroundImage: floor.backgroundImage, floors: undefined };\n }\n\n /** Toggle the 3D all-floors stacked overview (Batch 5). Re-renders; no-op on\n * single-floor charts. The caller re-applies statuses + animates the iso view. */\n setStacked(on: boolean): void {\n if (!this.chartDoc || on === this.stacked) return;\n const multi = !!this.chartDoc.floors && this.chartDoc.floors.length >= 2;\n if (!multi) return;\n this.stacked = on;\n this.setChart(this.chartDoc, { floorId: this.activeFloorId });\n }\n isStacked(): boolean {\n return this.stacked;\n }\n\n /** Switch which floor is shown (2D). Re-renders + re-fits; no-op if unchanged. */\n setActiveFloor(floorId: string): void {\n if (!this.chartDoc || floorId === this.activeFloorId) return;\n this.setChart(this.chartDoc, { floorId });\n }\n\n /** Floors for the host's switcher (single-floor charts return one synthetic floor). */\n getFloors(): { id: string; name: string }[] {\n return this.chartDoc ? floorsOf(this.chartDoc).map((f) => ({ id: f.id, name: f.name })) : [];\n }\n\n getActiveFloorId(): string {\n return this.activeFloorId;\n }\n\n setStatus(seatIds: string[], status: SeatStatus): void {\n let touched = false;\n // Sections whose availability tint / \"N LEFT\" needs a cheap recompute.\n const affected = this.hasSections ? new Set<SectionRender>() : null;\n for (const id of seatIds) {\n if (!this.statusById.has(id)) continue;\n const prev = this.statusById.get(id);\n this.statusById.set(id, status);\n const c = this.circleById.get(id);\n if (c) {\n this.paintSeat(c, id);\n touched = true;\n }\n if (affected) {\n const sec = this.seatSection.get(id);\n if (sec) {\n if ((prev === 'free') !== (status === 'free')) {\n sec.free += status === 'free' ? 1 : -1;\n }\n affected.add(sec);\n }\n }\n }\n if (affected && affected.size) {\n for (const sec of affected) this.refreshSectionFill(sec);\n this.bgLayer.batchDraw();\n }\n if (!touched) return;\n if (this.cached) {\n // bitmap is stale; debounce a re-cache so bulk updates coalesce\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.recacheTimer = setTimeout(() => this.cacheSeatLayer(), 150);\n } else {\n this.seatLayer.batchDraw();\n }\n if (this.effScale() > LABEL_SCALE) this.updateLabels();\n }\n\n setOwnedHold(seatIds: string[] | null): void {\n const next = new Set((seatIds ?? []).filter((id) => this.statusById.has(id)));\n const touched = new Set([...this.ownedHold, ...next]);\n this.ownedHold = next;\n for (const id of touched) {\n const shape = this.circleById.get(id);\n if (shape) this.paintSeat(shape, id);\n this.syncSelectionMarker(id);\n }\n if (!touched.size) return;\n if (this.cached) {\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.recacheTimer = setTimeout(() => this.cacheSeatLayer(), 150);\n } else {\n this.seatLayer.batchDraw();\n }\n if (this.effScale() > LABEL_SCALE) this.updateLabels();\n this.overlayLayer.batchDraw();\n }\n\n setSelectionFocus(seatId: string | null): void {\n const next = seatId && this.selection.has(seatId) ? seatId : null;\n if (next === this.selectionFocusId) return;\n const previous = this.selectionFocusId;\n this.selectionFocusId = next;\n\n for (const seat of this.seats) {\n const shape = this.circleById.get(seat.id);\n if (shape) this.paintSeat(shape, seat.id);\n }\n if (previous) this.syncSelectionMarker(previous);\n if (next) this.syncSelectionMarker(next);\n for (const [id, marker] of this.selectionMarkers) {\n marker.opacity(!next || id === next ? 1 : 0.2);\n }\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.overlayLayer.batchDraw();\n }\n\n getStatus(seatId: string): SeatStatus {\n return this.statusById.get(seatId) ?? 'free';\n }\n\n getSelection(): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n for (const id of this.selection) {\n const s = this.seatById.get(id);\n if (s) out.push(s);\n }\n return out;\n }\n\n clearSelection(): void {\n const ids = [...this.selection];\n for (const id of ids) this.setSelected(id, false, true);\n this.overlayLayer.batchDraw();\n }\n\n setMaxSelection(maxSelection: number): void {\n this.opts.maxSelection = Math.max(0, Math.floor(maxSelection));\n }\n\n select(seatIds: string[]): ExpandedSeat[] {\n const added: ExpandedSeat[] = [];\n for (const id of seatIds) {\n if (this.selection.has(id) || !this.isSelectable(id)) continue;\n if (this.selection.size >= this.opts.maxSelection) {\n this.opts.onSelectionLimit?.(this.opts.maxSelection);\n break;\n }\n this.setSelected(id, true, true);\n const seat = this.seatById.get(id);\n if (seat) added.push(seat);\n }\n if (added.length) this.overlayLayer.batchDraw();\n return added;\n }\n\n /** Switch organizer interaction in place so the host preserves camera, LOD,\n * focus and live status state while moving between Monitor and Block. */\n setManageInteraction(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void {\n if (this.marquee) this.cancelMarquee();\n this.panLast = null;\n this.panStart = null;\n this.panStarted = false;\n this.opts.manageMode = options.manageMode;\n this.opts.marqueeSelect = options.marqueeSelect;\n this.opts.selectableStatuses = [...options.selectableStatuses];\n if (options.maxSelection != null) this.opts.maxSelection = options.maxSelection;\n\n // A selection from a previous interaction mode must not remain actionable\n // after the new mode makes it read-only or changes its eligible statuses.\n const invalid = [...this.selection].filter((id) => !this.isSelectable(id));\n if (invalid.length) this.deselect(invalid);\n if (!options.manageMode && this.selection.size) this.clearSelection();\n this.container.style.cursor = 'default';\n this.overlayLayer.batchDraw();\n }\n\n /** Apply a non-destructive velocity treatment to section outlines. Seat\n * category/status fills remain untouched so heat never changes seat meaning. */\n setSectionHeat(scores: Record<string, number> | null): void {\n this.sectionHeat.clear();\n for (const [sectionId, raw] of Object.entries(scores ?? {})) {\n if (Number.isFinite(raw)) this.sectionHeat.set(sectionId, Math.max(0, Math.min(1, raw)));\n }\n for (const section of this.sections) this.refreshSectionHeat(section);\n this.bgLayer.batchDraw();\n }\n\n deselect(seatIds: string[]): void {\n let changed = false;\n for (const id of seatIds) {\n if (this.selection.has(id)) {\n this.setSelected(id, false, true);\n changed = true;\n }\n }\n if (changed) this.overlayLayer.batchDraw();\n }\n\n // ---- manage-mode bulk selection (SDK SeatManager) -------------------------\n // All option-gated: no-ops (or empty) unless `manageMode` is set, so buyer\n // surfaces that never pass the flag can't reach any of this.\n\n /** Select every selectable seat on the chart (⌘A). Returns the added seats. */\n selectAllSelectable(): ExpandedSeat[] {\n if (!this.opts.manageMode) return [];\n const ids: string[] = [];\n for (const seat of this.seats) if (this.isSelectable(seat.id)) ids.push(seat.id);\n return this.selectMany(ids);\n }\n\n /** Select the selectable seats matching these public labels (category/row/\n * section bulk resolves to labels host-side). Returns the newly added seats. */\n selectByLabels(labels: string[]): ExpandedSeat[] {\n if (!this.opts.manageMode) return [];\n const want = new Set(labels);\n const ids: string[] = [];\n for (const seat of this.seats) {\n if (want.has(seat.label) && this.isSelectable(seat.id)) ids.push(seat.id);\n }\n return this.selectMany(ids);\n }\n\n /** Exact SDK capture helper. MCP never accepts this id; the SDK derives it\n * from the persisted floor and uses the normal selected paint/ring path. */\n setEvidenceSelection(seatId: string): boolean {\n if (!this.seatById.has(seatId) || !this.isSelectable(seatId)) return false;\n if (this.selection.size) this.clearSelection();\n this.setSelected(seatId, true);\n this.overlayLayer.batchDraw();\n return this.selection.has(seatId);\n }\n\n /** Selectable seats in a section OR zone id — pure read (no selection change). */\n getSelectableInSection(sectionId: string): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n const seen = new Set<string>();\n for (const sec of this.sections) {\n if (sec.id !== sectionId && sec.logicalId !== sectionId && sec.zone !== sectionId) continue;\n for (const id of sec.memberIds) {\n if (seen.has(id)) continue;\n seen.add(id);\n if (!this.isSelectable(id)) continue;\n const s = this.seatById.get(id);\n if (s) out.push(s);\n }\n }\n return out;\n }\n\n /**\n * Union `ids` into the selection in one batched pass. Beyond MARQUEE_RING_CAP\n * total selected we skip the per-seat ring nodes (fill paint still marks the\n * seats) so a whole-arena select doesn't spawn thousands of Konva shapes.\n * Returns the full current selection.\n */\n private selectMany(ids: string[]): ExpandedSeat[] {\n const fresh = ids.filter((id) => !this.selection.has(id));\n if (!fresh.length) return this.getSelection();\n const drawRings = this.selection.size + fresh.length <= MARQUEE_RING_CAP;\n for (const id of fresh) {\n if (drawRings) {\n this.setSelected(id, true, true); // ring + fill, silent (batch draw below)\n } else {\n this.selection.add(id);\n const c = this.circleById.get(id);\n if (c) this.paintSeat(c, id);\n }\n }\n if (!this.cached) this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\n return this.getSelection();\n }\n\n // ---- manage-mode marquee gesture ------------------------------------------\n\n private beginMarquee(clientPt: { x: number; y: number }): void {\n const w = this.screenToWorld(clientPt);\n const s = this.stage.scaleX() || 1;\n const rect = new Rect({\n x: w.x,\n y: w.y,\n width: 0,\n height: 0,\n stroke: this.effSelection,\n strokeWidth: 1.5 / s, // world units → ~constant on-screen px under the stage scale\n dash: [5 / s, 4 / s],\n fill: 'rgba(110,123,255,0.10)',\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(rect);\n this.marquee = { start: w, rect };\n this.marqueeCur = w;\n this.overlayLayer.batchDraw();\n }\n\n private updateMarquee(clientPt: { x: number; y: number }): void {\n if (!this.marquee) return;\n const w = this.screenToWorld(clientPt);\n const { start, rect } = this.marquee;\n rect.setAttrs({\n x: Math.min(start.x, w.x),\n y: Math.min(start.y, w.y),\n width: Math.abs(w.x - start.x),\n height: Math.abs(w.y - start.y),\n });\n this.marqueeCur = w;\n this.overlayLayer.batchDraw();\n }\n\n private cancelMarquee(): void {\n if (!this.marquee) return;\n this.marquee.rect.destroy();\n this.marquee = null;\n this.marqueeCur = null;\n this.overlayLayer.batchDraw();\n }\n\n /**\n * Pointer-up: hit-test the marquee world-rect against the in-memory seat\n * centres (NOT the Konva hit-graph — that's a cached bitmap when zoomed and\n * far slower), keep only SELECTABLE seats, union them into the selection and\n * fire `onMarquee`. A near-zero drag reads as a click: clear the selection.\n */\n private finishMarquee(): void {\n const m = this.marquee;\n this.marquee = null;\n if (!m) return;\n m.rect.destroy();\n this.overlayLayer.batchDraw();\n const cur = this.marqueeCur ?? m.start;\n this.marqueeCur = null;\n const x0 = Math.min(m.start.x, cur.x);\n const x1 = Math.max(m.start.x, cur.x);\n const y0 = Math.min(m.start.y, cur.y);\n const y1 = Math.max(m.start.y, cur.y);\n const s = this.stage.scaleX() || 1;\n // Sub-4px drag = a click on empty canvas → deselect-all affordance.\n if ((x1 - x0) * s < 4 && (y1 - y0) * s < 4) {\n if (this.selection.size) {\n this.clearSelection();\n this.opts.onMarquee?.([]);\n }\n return;\n }\n const ids: string[] = [];\n for (const seat of this.seats) {\n if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;\n if (!this.isSelectable(seat.id)) continue;\n ids.push(seat.id);\n }\n this.selectMany(ids);\n this.opts.onMarquee?.(this.getSelection());\n }\n\n flashSeat(seatId: string, color = '#f43f5e'): void {\n const seat = this.seatById.get(seatId);\n if (!seat) return;\n const ring = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR,\n stroke: color,\n strokeWidth: 3,\n opacity: 0.9,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(ring);\n const start = performance.now();\n const dur = 620;\n const step = (now: number): void => {\n // Guard against a destroy() mid-animation (layer torn down).\n if (!ring.getLayer()) return;\n const t = Math.min(1, (now - start) / dur);\n ring.radius(this.seatR * (1 + t * 1.8));\n ring.opacity(0.9 * (1 - t));\n this.overlayLayer.batchDraw();\n if (t < 1) requestAnimationFrame(step);\n else {\n ring.destroy();\n this.overlayLayer.batchDraw();\n }\n };\n requestAnimationFrame(step);\n }\n\n /**\n * Pulse a section outline without moving the camera or mutating the authored\n * geometry. The temporary halo is drawn in the non-listening overlay layer,\n * so the apparent 4% lift never changes hit testing or selection bounds.\n */\n flashSection(sectionId: string, color = '#22a06b'): void {\n const matches = this.sections.filter((section) =>\n section.id === sectionId || section.zone === sectionId);\n if (!matches.length) return;\n\n for (const section of matches) {\n const centre = section.outline.reduce(\n (sum, point) => ({ x: sum.x + point.x, y: sum.y + point.y }),\n { x: 0, y: 0 },\n );\n centre.x /= section.outline.length;\n centre.y /= section.outline.length;\n const lift = section.elevation > 0 ? this.isoLiftLocal(section.elevation) : { x: 0, y: 0 };\n const halo = new Line({\n x: centre.x + lift.x,\n y: centre.y + lift.y,\n points: section.outline.flatMap((point) => [point.x - centre.x, point.y - centre.y]),\n closed: true,\n stroke: color,\n strokeWidth: 3,\n strokeScaleEnabled: false,\n opacity: 0.92,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: true,\n shadowColor: color,\n shadowBlur: 14,\n shadowOpacity: 0.7,\n });\n this.overlayLayer.add(halo);\n this.overlayLayer.batchDraw();\n\n const remove = (): void => {\n if (!halo.getLayer()) return;\n halo.destroy();\n this.overlayLayer.batchDraw();\n };\n if (this.reducedMotion || (typeof document !== 'undefined' && document.hidden)) {\n setTimeout(remove, 520);\n continue;\n }\n\n const start = performance.now();\n const duration = 820;\n const step = (now: number): void => {\n if (this.destroyed || !halo.getLayer()) return;\n const t = Math.min(1, (now - start) / duration);\n const eased = 1 - Math.pow(1 - t, 3);\n const scale = 1 + eased * 0.04;\n halo.scale({ x: scale, y: scale });\n halo.opacity(0.92 * (1 - t));\n this.overlayLayer.batchDraw();\n if (t < 1) requestAnimationFrame(step);\n else remove();\n };\n requestAnimationFrame(step);\n }\n }\n\n // ---- keyboard navigation (accessibility) ----------------------------------\n\n private onKeyDown = (e: KeyboardEvent): void => {\n // Manage-mode bulk shortcuts: ⌘/Ctrl-A selects all selectable, Escape clears.\n // Both fire onMarquee so the SDK toolbar tracks selection through one path.\n if (this.opts.manageMode) {\n if ((e.metaKey || e.ctrlKey) && (e.key === 'a' || e.key === 'A')) {\n e.preventDefault();\n this.opts.onMarquee?.(this.selectAllSelectable());\n return;\n }\n if (e.key === 'Escape' && this.selection.size) {\n e.preventDefault();\n this.clearSelection();\n this.opts.onMarquee?.([]);\n return;\n }\n }\n const dir =\n e.key === 'ArrowLeft' ? { x: -1, y: 0 }\n : e.key === 'ArrowRight' ? { x: 1, y: 0 }\n : e.key === 'ArrowUp' ? { x: 0, y: -1 }\n : e.key === 'ArrowDown' ? { x: 0, y: 1 }\n : null;\n if (dir) {\n e.preventDefault();\n const next = this.focusedId ? this.nearestSeat(this.focusedId, dir) : this.seats[0]?.id ?? null;\n if (next) this.focusSeat(next);\n return;\n }\n if ((e.key === 'Enter' || e.key === ' ') && this.focusedId) {\n e.preventDefault();\n this.toggleSeat(this.focusedId);\n const s = this.seatById.get(this.focusedId);\n if (s) this.opts.onFocusSeat?.(s); // re-announce; status may have changed\n }\n };\n\n /** Nearest seat from `fromId` in a cardinal direction (aligned + close wins). */\n private nearestSeat(fromId: string, dir: { x: number; y: number }): string | null {\n const from = this.seatById.get(fromId);\n if (!from) return null;\n let best: string | null = null;\n let bestScore = Infinity;\n for (const s of this.seats) {\n if (s.id === fromId) continue;\n const dx = s.x - from.x;\n const dy = s.y - from.y;\n const proj = dx * dir.x + dy * dir.y; // along the chosen direction\n if (proj <= 0.5) continue; // must lie in that direction\n const perp = Math.abs(dx * dir.y - dy * dir.x); // lateral offset\n const score = proj + perp * 2.5; // reward alignment + proximity\n if (score < bestScore) {\n bestScore = score;\n best = s.id;\n }\n }\n return best;\n }\n\n private focusSeat(id: string): void {\n const seat = this.seatById.get(id);\n if (!seat) return;\n this.focusedId = id;\n this.focusRing.radius(this.seatR + 3);\n this.focusRing.position({ x: seat.x, y: seat.y });\n this.focusRing.visible(true);\n this.ensureVisible(seat);\n this.overlayLayer.batchDraw();\n this.opts.onFocusSeat?.(seat);\n }\n\n /** Pan/zoom so a seat sits on-screen at a legible scale (for keyboard focus). */\n private ensureVisible(seat: ExpandedSeat): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const target = Math.max(this.stage.scaleX(), SEAT_LEGIBLE_SCALE * 1.2);\n const p = this.worldToScreen(seat);\n const margin = 70;\n const offscreen = p.x < margin || p.x > w - margin || p.y < margin || p.y > h - margin;\n if (this.stage.scaleX() < target || offscreen) {\n // Centre on the PROJECTED seat position so iso view frames it correctly.\n const ip = this.isoT === 0 ? seat : this.isoForward(seat);\n this.stage.scale({ x: target, y: target });\n this.stage.position({ x: w / 2 - ip.x * target, y: h / 2 - ip.y * target });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n }\n\n zoomToFit(): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const b = this.bounds;\n this.fitScale = Math.min(w / b.width, h / b.height) || 1;\n const s = this.fitScale;\n this.stage.scale({ x: s, y: s });\n this.stage.position({\n x: (w - b.width * s) / 2 - b.x * s,\n y: (h - b.height * s) / 2 - b.y * s,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /** Step factor for the on-screen +/− buttons (B1) — same clamp path as pinch/wheel. */\n private static readonly ZOOM_STEP = 1.4;\n\n zoomIn(): void {\n const center = { x: this.stage.width() / 2, y: this.stage.height() / 2 };\n this.zoomAbout(this.stage.scaleX() * SeatmapRenderer.ZOOM_STEP, center);\n }\n\n zoomOut(): void {\n const center = { x: this.stage.width() / 2, y: this.stage.height() / 2 };\n this.zoomAbout(this.stage.scaleX() / SeatmapRenderer.ZOOM_STEP, center);\n }\n\n seatCount(): number {\n return this.seats.length;\n }\n\n bookableCount(): number {\n let total = this.seats.length;\n for (const area of this.gaById.values()) total += area.capacity;\n return total;\n }\n\n worldToScreen(point: Point): { x: number; y: number } {\n const s = this.stage.scaleX();\n // In iso view, host overlays (confirm card, tooltip) must anchor to the\n // PROJECTED seat, so run the point through the iso affine first. At isoT=0\n // isoForward is the identity — byte-for-byte the flat behaviour.\n const p = this.isoT === 0 ? point : this.isoForward(point);\n return { x: p.x * s + this.stage.x(), y: p.y * s + this.stage.y() };\n }\n\n setAccessibleFilter(on: boolean): void {\n this.setAccessibilityFilter(on ? [] : null);\n }\n\n setAccessibilityFilter(types: AccessibilityType[] | null): void {\n const next = types === null ? null : [...types];\n if (this.sameAccessFilter(next)) return;\n this.accessFilter = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n private sameAccessFilter(next: AccessibilityType[] | null): boolean {\n const cur = this.accessFilter;\n if (cur === null || next === null) return cur === next;\n return cur.length === next.length && cur.every((t, i) => t === next[i]);\n }\n\n /**\n * Price-band filter (F4): dim free, unselected seats whose category key is NOT\n * in `keys`. `null` clears the filter (all categories fully visible). The\n * widget resolves which categories fall inside the buyer's chosen band.\n */\n setCategoryFilter(keys: string[] | null): void {\n const next = keys === null ? null : new Set(keys);\n const same = (next === null && this.categoryFilter === null) ||\n (next !== null && this.categoryFilter !== null &&\n next.size === this.categoryFilter.size && [...next].every((k) => this.categoryFilter!.has(k)));\n if (same) return;\n this.categoryFilter = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.applyGAFilterState();\n }\n\n private gaCategoryDimmed(categoryKey: string): boolean {\n return Boolean(\n (this.categoryHighlight && categoryKey !== this.categoryHighlight)\n || (this.categoryFilter && !this.categoryFilter.has(categoryKey)),\n );\n }\n\n /** Keep GA paint and its two labels in the same legend/price-filter state. */\n private applyGAFilterState(): void {\n this.paintGAStateForView();\n this.updateFreeTextVisibility();\n this.bgLayer.batchDraw();\n }\n\n private paintGAStateForView(): void {\n for (const ga of this.gaById.values()) {\n const filteredOut = Boolean(this.categoryFilter && !this.categoryFilter.has(ga.categoryKey));\n const overviewHidden = ga.sectionId != null && this.effScale() < CACHE_THRESHOLD;\n ga.polygon.opacity(overviewHidden\n ? 0\n : this.gaCategoryDimmed(ga.categoryKey)\n ? GA_FILL_OPACITY * 0.08\n : GA_FILL_OPACITY);\n // A legend hover is only visual; a price-filter exclusion is not sellable\n // from the map until the filter is cleared.\n ga.polygon.listening(!overviewHidden && !filteredOut);\n }\n }\n\n /** Frame the currently available inventory that survived a buyer price\n * filter. Clearing the filter glides back to the full venue. */\n focusCategories(keys: string[] | null): void {\n if (!keys?.length) {\n this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });\n return;\n }\n const wanted = new Set(keys);\n const matching = this.seats.filter((seat) => {\n if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;\n const status = this.statusById.get(seat.id) ?? 'free';\n return status === 'free' || this.ownedHold.has(seat.id);\n });\n if (!matching.length) return;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const seat of matching) {\n minX = Math.min(minX, seat.x);\n maxX = Math.max(maxX, seat.x);\n minY = Math.min(minY, seat.y);\n maxY = Math.max(maxY, seat.y);\n }\n const pad = Math.max(24, this.seatR * 3);\n minX -= pad;\n maxX += pad;\n minY -= pad;\n maxY += pad;\n this.focusRegion(\n { x: minX, y: minY, width: Math.max(40, maxX - minX), height: Math.max(40, maxY - minY) },\n { durationMs: CAMERA_GLIDE_MS },\n );\n }\n\n // ---- isometric (\"3D\") view mode -------------------------------------------\n\n /**\n * Switch the projection between flat top-down and the isometric \"3D\" view\n * (rotate + y-squash about the chart centre, plus per-elevation lift). Tweens\n * `isoT` 0⇄1 over ~0.32s (ease in-out); reduced-motion snaps. Purely visual —\n * geometry stays flat, so hit-testing (Konva's own, plus the manual section\n * inverse) keeps landing on the projected seats/sections.\n */\n setViewMode(mode: 'flat' | 'isometric'): void {\n const target = mode === 'isometric' ? 1 : 0;\n this.isoTarget = target;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n if (this.reducedMotion) {\n this.isoT = target;\n this.applyIso();\n this.afterViewChange();\n return;\n }\n const from = this.isoT;\n if (from === target) { this.applyIso(); this.afterViewChange(); return; }\n const start = performance.now();\n const step = (now: number): void => {\n if (this.destroyed) return; // guard a destroy() mid-tween\n const raw = Math.min(1, (now - start) / ISO_TWEEN_MS);\n // easeInOutCubic — matches the melt's camera glide.\n const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;\n this.isoT = from + (this.isoTarget - from) * e;\n this.applyIso();\n this.scheduleViewChange();\n if (raw < 1) {\n this.isoRaf = requestAnimationFrame(step);\n } else {\n this.isoT = this.isoTarget;\n this.isoRaf = 0;\n this.applyIso();\n this.afterViewChange(); // re-evaluate cache/labels at the settled effective scale\n }\n };\n this.isoRaf = requestAnimationFrame(step);\n }\n\n /** Current projection — reflects the tween target, not the mid-tween isoT. */\n getViewMode(): 'flat' | 'isometric' {\n return this.isoTarget === 1 ? 'isometric' : 'flat';\n }\n\n /** Iso angle (rad) + y-squash for the current isoT. */\n private isoParams(): { th: number; sg: number } {\n return { th: (ISO_ANGLE_DEG * Math.PI) / 180 * this.isoT, sg: 1 - (1 - ISO_SQUASH) * this.isoT };\n }\n\n /** Effective vertical scale = stage scale × iso squash — legibility math uses this. */\n private effScale(): number {\n return this.stage.scaleX() * (1 - (1 - ISO_SQUASH) * this.isoT);\n }\n\n /** Project a world point through the iso affine about the chart centre (→ iso-world). */\n private isoForward(p: Point): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const c = this.isoCentre;\n const dx = p.x - c.x;\n const dy = p.y - c.y;\n const rx = dx * Math.cos(th) - dy * Math.sin(th);\n const ry = (dx * Math.sin(th) + dy * Math.cos(th)) * sg;\n return { x: c.x + rx, y: c.y + ry };\n }\n\n /** Inverse of isoForward (iso-world → world) for screen-space hit-testing. */\n private isoInverse(p: Point): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const c = this.isoCentre;\n const dx = p.x - c.x;\n const dy = p.y - c.y;\n const uy = dy / sg;\n const wx = dx * Math.cos(th) + uy * Math.sin(th);\n const wy = -dx * Math.sin(th) + uy * Math.cos(th);\n return { x: c.x + wx, y: c.y + wy };\n }\n\n /**\n * Local-space offset that, once the layer applies the iso affine, lifts an\n * object straight UP in iso-world by `elevation × LIFT_PER_STEP × isoT`\n * (= inverse-linear of the pure vertical lift). Zero at isoT=0.\n */\n private isoLiftLocal(elevation: number): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const delta = elevation * LIFT_PER_STEP * this.isoT;\n return { x: -(delta / sg) * Math.sin(th), y: -(delta / sg) * Math.cos(th) };\n }\n\n /** Restore the three layers to identity (flat) — byte-for-byte the original. */\n private resetLayerTransforms(): void {\n for (const layer of [this.bgLayer, this.seatLayer, this.overlayLayer]) {\n layer.position({ x: 0, y: 0 });\n layer.offset({ x: 0, y: 0 });\n layer.scale({ x: 1, y: 1 });\n layer.rotation(0);\n layer.skewX(0);\n layer.skewY(0);\n }\n }\n\n /**\n * Apply the current isoT to the scene: the base rotate+squash as a decomposed\n * layer transform (so seats/décor/rings project together and Konva's own\n * hit-testing follows), upright counter-transforms on text, and the elevation\n * lift + extruded side faces on elevated sections.\n */\n private applyIso(): void {\n const t = this.isoT;\n if (t === 0) {\n this.resetLayerTransforms();\n } else {\n const { th, sg } = this.isoParams();\n // L_iso = Scale(1,sg)·Rot(th) about the centre; decompose to Konva props.\n const a = Math.cos(th);\n const b = sg * Math.sin(th);\n const cc = -Math.sin(th);\n const d = sg * Math.cos(th);\n const r = Math.sqrt(a * a + b * b);\n const delta = a * d - b * cc; // = sg\n const rotationDeg = (Math.atan2(b, a) * 180) / Math.PI;\n const scaleX = r;\n const scaleY = delta / r;\n const skewX = (a * cc + b * d) / delta;\n const c = this.isoCentre;\n for (const layer of [this.bgLayer, this.seatLayer, this.overlayLayer]) {\n layer.position({ x: c.x, y: c.y });\n layer.offset({ x: c.x, y: c.y });\n layer.rotation(rotationDeg);\n layer.scaleX(scaleX);\n layer.scaleY(scaleY);\n layer.skewX(skewX);\n layer.skewY(0);\n }\n }\n\n this.applyUprightLabels();\n this.applyElevation();\n\n this.bgLayer.batchDraw();\n this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\n }\n\n /** Counter-skew every visible label so it renders upright at its projected anchor. */\n private applyUprightLabels(): void {\n const thDeg = ISO_ANGLE_DEG * this.isoT;\n const invScaleY = 1 / (1 - (1 - ISO_SQUASH) * this.isoT);\n // Seat labels live in overlayLayer (labelGroup); section/zone/décor in bgLayer.\n // Skip the seatLayer scan unless it actually holds booth labels (else it is\n // thousands of Circles with no Text).\n const layers = this.hasBoothText\n ? [this.bgLayer, this.seatLayer, this.overlayLayer]\n : [this.bgLayer, this.overlayLayer];\n for (const layer of layers) {\n const texts = layer.find('Text') as unknown as Text[];\n for (const tn of texts) {\n let base = tn.getAttr('uprightBase') as number | undefined;\n if (base == null) {\n base = tn.rotation();\n tn.setAttr('uprightBase', base);\n }\n tn.rotation(base - thDeg);\n tn.scaleX(1);\n tn.scaleY(invScaleY);\n tn.skewX(0);\n }\n }\n }\n\n /** Lift elevated sections (+ their members) and update their extruded side faces. */\n private applyElevation(): void {\n const t = this.isoT;\n for (const sec of this.sections) {\n if (sec.elevation <= 0) continue;\n const off = this.isoLiftLocal(sec.elevation);\n sec.liftGroupBg?.position(off);\n sec.liftGroupSeat?.position(off);\n // Side faces: quad per edge from base outline to the lifted outline, in\n // local (world) space — the layer projects them. Invisible at isoT=0.\n const alpha = 0.9 * t;\n for (let i = 0; i < sec.sideFaces.length; i++) {\n const face = sec.sideFaces[i];\n const p0 = sec.outline[i];\n const p1 = sec.outline[(i + 1) % sec.outline.length];\n face.points([p0.x, p0.y, p1.x, p1.y, p1.x + off.x, p1.y + off.y, p0.x + off.x, p0.y + off.y]);\n face.opacity(alpha);\n }\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.isoRaf) cancelAnimationFrame(this.isoRaf);\n if (this.glideRaf) cancelAnimationFrame(this.glideRaf);\n if (this.viewChangeRaf) cancelAnimationFrame(this.viewChangeRaf);\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.resizeObs?.disconnect();\n this.container.removeEventListener('pointerdown', this.onPointerDown);\n this.container.removeEventListener('pointermove', this.onPointerMove);\n this.container.removeEventListener('pointerup', this.onPointerEnd);\n this.container.removeEventListener('pointercancel', this.onPointerEnd);\n this.container.removeEventListener('keydown', this.onKeyDown);\n this.stage.destroy();\n }\n\n // ---- rendering ------------------------------------------------------------\n\n /** Theme font stack for all rendered text (falls back to Inter). */\n private labelFont(): string {\n return this.theme.fontFamily || 'Inter, sans-serif';\n }\n\n /**\n * Where a seat's nodes live: an elevated section's lift group (so the whole\n * tier shifts with one offset in iso view) or the seat layer directly.\n */\n private seatContainer(id: string): Group | Layer {\n return this.seatSection.get(id)?.liftGroupSeat ?? this.seatLayer;\n }\n\n private renderSeats(): void {\n for (const seat of this.seats) {\n if (seat.kind === 'booth') {\n this.renderBoothUnit(seat);\n continue;\n }\n const target = this.seatContainer(seat.id);\n const c = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n c.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, c);\n this.paintSeat(c, seat.id);\n target.add(c);\n // Accessible seats get a static 2px outer ring, coloured by their primary\n // accommodation (few per chart, so the extra node is cheap).\n if (seat.accessible) {\n target.add(\n new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR + 1,\n stroke: accessibilityRingColor(seat.accessibility),\n strokeWidth: 2,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n }),\n );\n }\n }\n }\n\n /** A booth renders as a click-selectable rounded block (dims from the doc). */\n private renderBoothUnit(seat: ExpandedSeat): void {\n const target = this.seatContainer(seat.id);\n const dims = this.boothDims.get(seat.rowId) ?? { width: 40, height: 30, rotation: 0 };\n const rect = new Rect({\n x: seat.x,\n y: seat.y,\n width: dims.width,\n height: dims.height,\n offsetX: dims.width / 2,\n offsetY: dims.height / 2,\n rotation: dims.rotation,\n cornerRadius: 4,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n rect.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, rect);\n target.add(rect);\n\n const t = new Text({\n x: seat.x,\n y: seat.y,\n text: seat.displayLabel ?? seat.label,\n fontSize: BOOTH_LABEL_FONT_SIZE,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n fill: this.theme.seatLabelColor ?? DEF_SEAT_LABEL,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.visible(false);\n this.boothLabelById.set(seat.id, t);\n this.hasBoothText = true; // gate the upright-label scan of the seat layer\n this.boothLabelById.set(seat.id, t);\n target.add(t);\n this.paintSeat(rect, seat.id);\n }\n\n /** The category's display color — Okabe-Ito hue when colorblind-safe is on. */\n private seatBaseColor(categoryKey: string): string {\n if (!this.colorblind) return this.catColor.get(categoryKey) ?? '#6e7bff';\n const idx = this.catOrder.indexOf(categoryKey);\n return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];\n }\n\n /** Per-seat authored label size relative to the neutral default (1 = default),\n * mirroring the section convention (labelStyle.size ?? 18) / 18. Only real\n * seats carry labelStyle, so booths and unstyled seats resolve to 1. */\n private seatLabelScale(seat: ExpandedSeat): number {\n return (seat.labelStyle?.size ?? 18) / 18;\n }\n\n /** Preferred label ink for a seat: the authored per-seat colour when set,\n * otherwise today's theme default. Fed through auto-contrast by seatLabelInk. */\n private seatPreferredLabelInk(seat: ExpandedSeat): string {\n return seat.labelStyle?.color ?? this.theme.seatLabelColor ?? DEF_SEAT_LABEL;\n }\n\n /** Resolve a seat's label ink against the paint actually visible, honouring an\n * authored per-seat colour through the same auto-contrast rule as sections. */\n private seatLabelInk(seat: ExpandedSeat, shape: Shape): string {\n const fill = shape.fill();\n return stateAwareBookableLabelInk(typeof fill === 'string' ? fill : '', this.seatPreferredLabelInk(seat));\n }\n\n /** Apply fill/stroke/opacity for a seat's current status + selection. */\n private paintSeat(c: Shape, id: string): void {\n const seat = this.seatById.get(id)!;\n const status = this.statusById.get(id) ?? 'free';\n const selected = this.selection.has(id);\n const base = this.seatBaseColor(seat.categoryKey);\n const boothLabel = this.boothLabelById.get(id);\n\n c.dash([]);\n c.strokeWidth(0);\n c.stroke('');\n c.opacity(1);\n\n switch (status) {\n case 'free':\n // Selected: on dark canvases the lightened fill + white ring pops; on\n // light canvases that same wash reads as *disabled*, so keep the full\n // category fill and let the dark contrast ring carry the state.\n c.fill(\n selected && this.effSelection === DEF_SELECTION ? lighten(base, 0.28) : base,\n );\n break;\n case 'held':\n if (this.ownedHold.has(id)) {\n // A buyer returning from checkout must be able to distinguish their\n // own inventory from somebody else's hold. Preserve the category\n // identity and outline the actual seat/booth shape (full rectangle\n // for a booth), rather than painting it generic unavailable grey.\n c.fill(lighten(base, this.effSelection === DEF_SELECTION ? 0.24 : 0.1));\n c.stroke(this.effSelection);\n c.strokeWidth(3);\n } else {\n c.fill(HELD_FILL);\n }\n break;\n case 'booked':\n if (this.colorblind) {\n // Non-color cue: booked reads as a hollow ring, never hue alone.\n c.fill('rgba(0,0,0,0)');\n c.stroke(TAKEN_FILL);\n c.strokeWidth(1.5);\n c.opacity(0.9);\n } else {\n c.fill(TAKEN_FILL);\n c.opacity(0.45);\n }\n break;\n case 'not_for_sale':\n c.fill(TAKEN_FILL);\n c.stroke(NFS_STROKE);\n c.strokeWidth(1);\n c.dash([2, 2]);\n break;\n }\n\n if (boothLabel) {\n boothLabel.text(status === 'booked' ? 'SOLD' : status === 'held' ? 'HELD' : seat.label);\n boothLabel.fontSize(status === 'free' ? 10 : Math.min(10, Math.max(6, this.boothDims.get(seat.rowId)?.width ?? 40) / 6));\n boothLabel.fontStyle(status === 'free' ? '600' : '800');\n boothLabel.fill(status === 'free' ? (this.theme.seatLabelColor ?? DEF_SEAT_LABEL) : '#ffffff');\n boothLabel.offsetX(boothLabel.width() / 2);\n boothLabel.offsetY(boothLabel.height() / 2);\n }\n\n // Accessibility filter dims free, unselected seats that don't match.\n if (this.accessFilter && status === 'free' && !selected && !seatMatchesAccess(seat, this.accessFilter)) {\n c.opacity(0.25);\n }\n // Legend hover-highlight dims free, unselected seats of other categories.\n if (this.categoryHighlight && status === 'free' && !selected && seat.categoryKey !== this.categoryHighlight) {\n c.opacity(0.25);\n }\n // Price-band filter (F4): dim free, unselected seats outside the chosen band.\n if (this.categoryFilter && status === 'free' && !selected && !this.categoryFilter.has(seat.categoryKey)) {\n c.opacity(0.22);\n }\n // Held-back inventory (organizer manager): seats in a dimmed section/zone\n // read as inactive so the map matches the Sections list at a glance.\n if (this.dimmedSections.size) {\n const sec = this.seatSection.get(id);\n if (sec && (\n this.dimmedSections.has(sec.id)\n || this.dimmedSections.has(sec.logicalId)\n || (sec.zone != null && this.dimmedSections.has(sec.zone))\n )) {\n c.opacity(0.18);\n }\n }\n // Phase 2 `closed` section: flat grey, 40% opacity, never a category hue —\n // overrides the status paint above. Seats stay visible but read off-sale.\n if (this.closedSections.size && this.seatInClosedSection(id)) {\n c.fill(CLOSED_SEAT_FILL);\n c.stroke('');\n c.strokeWidth(0);\n c.dash([]);\n c.opacity(CLOSED_SEAT_OPACITY);\n }\n // AXS section-focus: seats outside the focused section desaturate + dim so\n // the focused block reads against a calm ground (§4 focus spec).\n if (this.focusedSectionId) {\n const sec = this.seatSection.get(id);\n const inFocus = !!sec && (\n sec.id === this.focusedSectionId\n || sec.logicalId === this.focusedSectionId\n || sec.zone === this.focusedSectionId\n );\n if (!inFocus) c.opacity(FOCUS_DIM_OPACITY);\n }\n // Buyer confirmation focus: retain the candidate at full strength while\n // every unrelated seat recedes. Labels use the resulting opacity below so\n // the detail layer follows the same focus hierarchy as the seat geometry.\n if (this.selectionFocusId && id !== this.selectionFocusId) c.opacity(Math.min(c.opacity(), 0.16));\n const bookableLabel = this.boothLabelById.get(id) ?? this.seatLabelById.get(id);\n if (bookableLabel) {\n // Booths carry no labelStyle, so seatLabelInk resolves to today's theme\n // ink for them; real seats get their authored colour auto-contrasted.\n bookableLabel.fill(this.seatLabelInk(seat, c));\n bookableLabel.visible(\n isBookableLabelLegibleAtScale(bookableLabel.fontSize(), this.effScale())\n && c.opacity() >= 0.5,\n );\n }\n }\n\n /** True when a seat sits in a section/zone currently marked `closed`. */\n private seatInClosedSection(id: string): boolean {\n if (!this.closedSections.size) return false;\n const sec = this.seatSection.get(id);\n return !!sec && (\n this.closedSections.has(sec.id)\n || this.closedSections.has(sec.logicalId)\n || (sec.zone != null && this.closedSections.has(sec.zone))\n );\n }\n\n /**\n * Colorblind-safe mode: swap category hues for the Okabe-Ito palette and\n * render booked seats hollow. Off restores the exact default rendering.\n */\n setColorblindSafe(on: boolean): void {\n if (on === this.colorblind) return;\n this.colorblind = on;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n /**\n * Dim the seats of these section/zone ids (organizer manager use) so held-back\n * inventory is visually distinct on the canvas without hiding it. `null`/empty\n * clears. Unlike the buyer's applyHidden, the sections stay rendered.\n */\n setDimmedSections(ids: string[] | null): void {\n const next = new Set(ids ?? []);\n if (next.size === this.dimmedSections.size && [...next].every((i) => this.dimmedSections.has(i))) return;\n this.dimmedSections = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, but the section stays rendered\n * (unlike the buyer's applyHidden which strips it). `null`/empty clears.\n */\n setClosedSections(ids: string[] | null): void {\n const next = new Set(ids ?? []);\n if (next.size === this.closedSections.size && [...next].every((i) => this.closedSections.has(i))) return;\n this.closedSections = next;\n this.repaintSectionsAndSeats();\n }\n\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * panel behind this section's seats, and glide the camera in to frame it (the\n * seat-pick gate below only lets buyers pick once seats are ≥ LABEL_SCALE big).\n */\n focusSection(id: string): void {\n if (!this.sections.some((section) => section.id === id || section.logicalId === id)) return;\n this.focusedSectionId = id;\n this.drawFocusBackdrop(id);\n this.repaintSectionsAndSeats();\n this.updateLOD();\n this.focusRegion(id, { minScale: SEAT_FOCUS_SCALE });\n }\n\n /** Clear an AXS section focus — restore full-bowl brightness + drop the backdrop. */\n clearSectionFocus(): void {\n if (!this.focusedSectionId) return;\n this.focusedSectionId = null;\n if (this.focusBackdrop) {\n this.focusBackdrop.destroy();\n this.focusBackdrop = null;\n }\n this.repaintSectionsAndSeats();\n this.updateLOD();\n }\n\n /** The currently AXS-focused section id, or null. */\n getFocusedSection(): string | null {\n return this.focusedSectionId;\n }\n\n /** Draw (or replace) the light backdrop panel behind the focused section. */\n private drawFocusBackdrop(id: string): void {\n if (this.focusBackdrop) {\n this.focusBackdrop.destroy();\n this.focusBackdrop = null;\n }\n const sections = this.sections.filter((section) => section.id === id || section.logicalId === id);\n if (!sections.length) return;\n const backdrop = new Group({ listening: false });\n for (const section of sections) {\n backdrop.add(polygonWithHolesShape(section.outline, section.holes, {\n fill: FOCUS_BACKDROP_FILL,\n stroke: rgba('#ffffff', 0.1),\n strokeWidth: 1,\n listening: false,\n }, section.outlinePath));\n }\n this.bgLayer.add(backdrop);\n backdrop.moveToTop(); // above the dimmed sibling blocks, still under the seat layer\n this.focusBackdrop = backdrop;\n }\n\n /** Repaint every seat + section block to reflect closed/focus state, then redraw. */\n private repaintSectionsAndSeats(): void {\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n for (const sec of this.sections) sec.blockPoly.fill(this.sectionBlockFill(sec));\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.bgLayer.batchDraw();\n }\n\n /** The world-space rectangle currently visible in the viewport (minimap F3). */\n getVisibleWorldRect(): { x: number; y: number; width: number; height: number } {\n const tl = this.screenToWorld({ x: 0, y: 0 });\n const br = this.screenToWorld({ x: this.stage.width(), y: this.stage.height() });\n return {\n x: Math.min(tl.x, br.x),\n y: Math.min(tl.y, br.y),\n width: Math.abs(br.x - tl.x),\n height: Math.abs(br.y - tl.y),\n };\n }\n\n /** Axis-aligned world bounds of seats, section outlines, and GA polygons (minimap F3 frame). */\n getWorldBounds(): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n const grow = (x: number, y: number): void => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n for (const s of this.seats) grow(s.x, s.y);\n for (const sec of this.sections) for (const p of sec.outline) grow(p.x, p.y);\n for (const area of this.gaById.values()) for (const p of area.points) grow(p.x, p.y);\n if (!Number.isFinite(minX)) return { x: 0, y: 0, width: 1, height: 1 };\n return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n }\n\n /** Legend hover: highlight one category (dim the rest), or null to clear. */\n setCategoryHighlight(key: string | null): void {\n if (this.categoryHighlight === key) return;\n this.categoryHighlight = key;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.applyGAFilterState();\n }\n\n private renderBackground(doc: ChartDoc): void {\n if (doc.backgroundImage) this.renderBackgroundImage(doc.backgroundImage);\n // Decor graphics (ice rink, court art) draw first so they sit UNDER the\n // section outlines and — being on bgLayer, below seatLayer entirely — under\n // every seat. listening(false) keeps them out of the hit graph.\n for (const obj of doc.objects) if (obj.type === 'decorImage') this.renderDecorImage(obj);\n // Sections sit under all other décor so their outlines never occlude seats.\n // NOTE(phase-2): event-level section open/closed/hidden state will gate this\n // draw + the seat membership below — hide/dim a section by id/zone here.\n for (const obj of doc.objects) if (obj.type === 'section') this.renderSection(obj);\n // Zone labels sit above section blocks (drawn after) — the farthest rung.\n this.renderZones(doc);\n for (const obj of doc.objects) {\n if (obj.type === 'shape') {\n this.renderShape(obj);\n } else if (obj.type === 'gaArea') {\n this.renderGA(obj);\n } else if (obj.type === 'table') {\n this.renderTable(obj);\n } else if (obj.type === 'text') {\n this.renderText(obj);\n }\n }\n // `focalPoint` is authoring geometry, not buyer-facing décor. The designer\n // exposes its guide only while the focal tool is active.\n }\n\n /** Organizer floor-plan photo, dimmed, at the very bottom of the bg layer. */\n private renderBackgroundImage(bg: NonNullable<ChartDoc['backgroundImage']>): void {\n if (!bg.url || bg.visible === false) return;\n const img = new window.Image();\n img.onload = () => {\n const natW = img.naturalWidth || 4;\n const natH = img.naturalHeight || 3;\n const rawCrop = bg.crop ?? { x: 0, y: 0, width: 1, height: 1 };\n const cropX = Math.max(0, Math.min(0.99, rawCrop.x));\n const cropY = Math.max(0, Math.min(0.99, rawCrop.y));\n const crop = {\n x: cropX,\n y: cropY,\n width: Math.max(0.01, Math.min(1 - cropX, rawCrop.width)),\n height: Math.max(0.01, Math.min(1 - cropY, rawCrop.height)),\n };\n const w = bg.width;\n const h = w * ((natH * crop.height) / (natW * crop.width));\n const node = new KImage({\n image: img,\n x: bg.center.x,\n y: bg.center.y,\n offsetX: w / 2,\n offsetY: h / 2,\n width: w,\n height: h,\n rotation: bg.rotation ?? 0,\n crop: {\n x: crop.x * natW,\n y: crop.y * natH,\n width: crop.width * natW,\n height: crop.height * natH,\n },\n opacity: bg.opacity,\n listening: false,\n });\n this.bgLayer.add(node);\n node.moveToBottom();\n this.bgLayer.batchDraw();\n };\n img.src = bg.url;\n }\n\n /**\n * A decor graphic (rink / court / stage art). The KImage node is added to the\n * bgLayer synchronously so it keeps its z-slot beneath the sections drawn right\n * after; the bitmap is decoded async and pasted in on load. A single node = a\n * single drawImage per frame, and it rides the same layer cache — effectively\n * zero per-frame cost. Never listens, so it can't intercept a seat click.\n */\n private renderDecorImage(obj: Extract<ChartDoc['objects'][number], { type: 'decorImage' }>): void {\n // Pass the (not-yet-loaded) Image element as the node's image: Konva draws\n // nothing until it decodes, then onload triggers a repaint. Keeps the node's\n // z-slot fixed beneath the sections drawn immediately after.\n const img = new window.Image();\n const node = new KImage({\n image: img,\n x: obj.x + obj.width / 2,\n y: obj.y + obj.height / 2,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation ?? 0,\n opacity: clamp(obj.opacity ?? 1, 0, 1),\n listening: false,\n perfectDrawEnabled: false,\n });\n this.bgLayer.add(node);\n img.onload = () => {\n if (!node.getLayer()) return; // chart swapped out before the image loaded\n this.bgLayer.batchDraw();\n };\n img.src = obj.href;\n }\n\n private renderTable(obj: Extract<ChartDoc['objects'][number], { type: 'table' }>): void {\n if (obj.shape === 'round') {\n this.bgLayer.add(\n new Circle({\n x: obj.center.x,\n y: obj.center.y,\n radius: obj.radius ?? 40,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n listening: false,\n }),\n );\n } else {\n const w = obj.width ?? 80;\n const h = obj.height ?? 50;\n this.bgLayer.add(\n new Rect({\n x: obj.center.x,\n y: obj.center.y,\n width: w,\n height: h,\n offsetX: w / 2,\n offsetY: h / 2,\n rotation: obj.rotation,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n cornerRadius: 4,\n listening: false,\n }),\n );\n }\n const label = this.addCentredLabel(this.bgLayer, obj.label, obj.center.x, obj.center.y, '#cbd5e1', 12, true);\n this.freeTextById.set(obj.id, { node: label, background: '#232c40', kind: 'table' });\n }\n\n private renderText(obj: Extract<ChartDoc['objects'][number], { type: 'text' }>): void {\n const background = this.canvasBackground;\n const preferredInk = obj.color ?? this.theme.textColor ?? DEF_TEXT;\n const node = new Text({\n x: obj.position.x,\n y: obj.position.y,\n text: obj.text,\n fontSize: obj.fontSize,\n rotation: obj.rotation,\n // Authored ink remains preferred, but an embed/theme surface can change\n // the actual canvas. Fail over to readable black/white instead of\n // painting an otherwise valid caption invisibly on that active surface.\n fill: stateAwareBookableLabelInk(background, preferredInk),\n fontFamily: this.labelFont(),\n listening: false,\n perfectDrawEnabled: false,\n });\n this.freeTextById.set(obj.id, {\n node,\n background,\n kind: 'free-text',\n });\n this.bgLayer.add(node);\n }\n\n private renderShape(obj: Extract<ChartDoc['objects'][number], { type: 'shape' }>): void {\n const authoredFill = obj.fill ?? this.theme.decorFill ?? DEF_DECOR_FILL;\n const isStage = obj.role === 'stage';\n const referenceFocal = obj.role === 'reference-focal';\n const isDecor = !!obj.role && !isStage;\n const palette = overviewPalette(this.canvasBackground);\n // A sampled source colour remains persisted on the object as evidence, but\n // the buyer overview renders the focal landmark as the same neutral visual\n // hierarchy as the supplied seating-chart target. Source black must not\n // become an unlabelled black hole in the generated chart.\n const fill = referenceFocal ? palette.focalFill : authoredFill;\n // Stage: darker at the back (min-y), brighter toward the audience edge (max-y).\n const stroke = isStage ? lighten(fill, 0.28) : referenceFocal ? palette.focalStroke : undefined;\n const strokeWidth = isStage ? 1 : referenceFocal ? 2 : 0;\n let cx = 0;\n let cy = 0;\n if (obj.kind === 'rect' && obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n const grad = isStage\n ? {\n fillLinearGradientStartPoint: { x: 0, y: 0 },\n fillLinearGradientEndPoint: { x: 0, y: obj.height },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n cx = obj.x + obj.width / 2;\n cy = obj.y + obj.height / 2;\n // Rotate about center: pivot at (cx,cy) via offset; local coords (and the\n // gradient) are unchanged, so the fill spans the box regardless of angle.\n this.bgLayer.add(\n new Rect({\n x: cx,\n y: cy,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n rotation: obj.rotation ?? 0,\n width: obj.width,\n height: obj.height,\n ...grad,\n stroke,\n strokeWidth,\n cornerRadius: 4,\n listening: false,\n }),\n );\n } else if (obj.kind === 'ellipse' && obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n cx = obj.x + obj.width / 2;\n cy = obj.y + obj.height / 2;\n const grad = isStage\n ? {\n fillLinearGradientStartPoint: { x: 0, y: -obj.height / 2 },\n fillLinearGradientEndPoint: { x: 0, y: obj.height / 2 },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n this.bgLayer.add(\n new Ellipse({ x: cx, y: cy, rotation: obj.rotation ?? 0, radiusX: obj.width / 2, radiusY: obj.height / 2, ...grad, stroke, strokeWidth, listening: false }),\n );\n } else if (obj.kind === 'polygon' && obj.points && obj.points.length) {\n const pts = obj.points.flatMap((p) => [p.x, p.y]);\n const b = polyBounds(obj.points);\n cx = obj.points.reduce((a, p) => a + p.x, 0) / obj.points.length;\n cy = obj.points.reduce((a, p) => a + p.y, 0) / obj.points.length;\n const grad = isStage\n ? {\n // Line points are absolute chart coords; the gradient endpoints share\n // that space and rotate with the node (pivot at the centroid below).\n fillLinearGradientStartPoint: { x: 0, y: b.y },\n fillLinearGradientEndPoint: { x: 0, y: b.y + b.height },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n // Rotate about the centroid: position=offset=centroid leaves the polygon\n // in place at rotation 0 and pivots there for any angle.\n this.bgLayer.add(\n new Line({ points: pts, closed: true, x: cx, y: cy, offsetX: cx, offsetY: cy, rotation: obj.rotation ?? 0, ...grad, stroke, strokeWidth, listening: false }),\n );\n }\n if (obj.label) {\n if (isStage) {\n const node = this.addStageLabel(cx, cy, obj.label, fill);\n this.primaryFocalLabels.set(node, 22);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'stage' });\n }\n else if (isDecor) {\n // A compiled reference focal is a primary orientation landmark, not\n // quiet furniture. Keep its desktop overview label above the shared\n // 12px rendered floor and choose ink against the actual source fill.\n // Ordinary décor retains the subdued treatment.\n const node = this.addCentredLabel(\n this.bgLayer,\n obj.label,\n cx,\n cy,\n referenceFocal ? stateAwareBookableLabelInk(fill, '#e6e9f0') : '#9aa3b5',\n referenceFocal ? 18 : 12,\n false,\n );\n if (referenceFocal) this.primaryFocalLabels.set(node, 18);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'decor' });\n } else {\n const node = this.addCentredLabel(this.bgLayer, obj.label, cx, cy, '#cbd5e1', 16, true);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'decor' });\n }\n }\n }\n\n /** Prominent stage caption: uppercase, letter-spaced, larger, softly dimmed. */\n private addStageLabel(x: number, y: number, text: string, background: string): Text {\n const ink = stateAwareBookableLabelInk(background, '#e6e9f0');\n const t = new Text({\n x,\n y,\n text: text.toUpperCase(),\n fontSize: 22,\n fontStyle: '700',\n letterSpacing: 4,\n fontFamily: this.labelFont(),\n fill: ink,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n this.bgLayer.add(t);\n return t;\n }\n\n private renderGA(obj: Extract<ChartDoc['objects'][number], { type: 'gaArea' }>): void {\n const color = this.catColor.get(obj.categoryKey) ?? '#6e7bff';\n const canvas = this.canvasBackground;\n const effectiveBackground = compositeHexOver(color, canvas, GA_FILL_OPACITY);\n const preferredInk = this.theme.textColor ?? '#e6e9f0';\n const ink = stateAwareBookableLabelInk(effectiveBackground, preferredInk);\n const poly = polygonWithHolesShape(obj.points, obj.holes, {\n fill: color,\n opacity: GA_FILL_OPACITY,\n stroke: color,\n strokeWidth: 1.5,\n });\n poly.setAttr('gaId', obj.id);\n poly.on('click tap', () => this.opts.onGAClick?.(obj.id));\n poly.on('mouseenter', () => {\n this.container.style.cursor = 'pointer';\n });\n poly.on('mouseleave', () => {\n this.container.style.cursor = 'default';\n });\n this.bgLayer.add(poly);\n\n const labelPoint = polygonLabelPoint(obj.points, obj.holes);\n const containingSection = this.sections.find((section) => (\n pointInPolygonWithHoles(labelPoint, section.outline, section.holes)\n ));\n const label = this.addCentredLabel(this.bgLayer, obj.label, labelPoint.x, labelPoint.y - 8, ink, GA_LABEL_FONT_SIZE, false);\n const capacity = this.addCentredLabel(this.bgLayer, `cap ${obj.capacity}`, labelPoint.x, labelPoint.y + 10, ink, GA_CAPACITY_LABEL_FONT_SIZE, false);\n this.freeTextById.set(`${obj.id}:label`, {\n objectId: obj.id,\n node: label,\n background: effectiveBackground,\n kind: 'ga-label',\n categoryKey: obj.categoryKey,\n });\n this.freeTextById.set(`${obj.id}:capacity`, {\n objectId: obj.id,\n node: capacity,\n background: effectiveBackground,\n kind: 'ga-capacity',\n categoryKey: obj.categoryKey,\n });\n this.gaById.set(obj.id, {\n label: obj.label,\n capacity: obj.capacity,\n categoryKey: obj.categoryKey,\n points: obj.points,\n polygon: poly,\n effectiveBackground,\n ...(containingSection ? { sectionId: containingSection.logicalId } : {}),\n });\n }\n\n /**\n * A section renders in three coordinated layers driven by the LOD melt:\n * • a faint outline (the existing near-zoom look, untouched),\n * • a neutral solid shell that fades in at the overview rung, and\n * • one readable, contained section name.\n * Category, row, seat, and availability detail belongs to section focus/zoom.\n * Membership and category mix are still precomputed for the detailed state.\n */\n private renderSection(obj: SectionObject): void {\n const centroid = polygonLabelPoint(obj.outline, obj.holes);\n const palette = overviewPalette(this.canvasBackground);\n\n // Membership: seats inside the outline, first section (doc order) wins.\n const memberIds: string[] = [];\n const catCounts = new Map<string, number>();\n let free = 0;\n for (const seat of this.seats) {\n if (this.seatSection.has(seat.id)) continue;\n if (!pointInPolygonWithHoles(seat, obj.outline, obj.holes)) continue;\n memberIds.push(seat.id);\n catCounts.set(seat.categoryKey, (catCounts.get(seat.categoryKey) ?? 0) + 1);\n if ((this.statusById.get(seat.id) ?? 'free') === 'free') free++;\n }\n\n // Category-mix fill: explicit override wins, else blend member colours by count.\n const baseFill =\n obj.color ??\n mixColors(\n [...catCounts].map(([key, w]) => ({ hex: this.catColor.get(key) ?? '#6e7bff', w })),\n '#3a4358',\n );\n\n // Elevation: elevated sections lift as one tier in the iso view, so their bg\n // nodes + member seats go into lift groups (positioned in applyElevation).\n // Side faces (a zone-coloured quad per outline edge) extrude only as isoT rises.\n const elevation = Math.max(0, Math.round(obj.elevation ?? 0));\n let liftGroupBg: Group | null = null;\n let liftGroupSeat: Group | null = null;\n const sideFaces: Line[] = [];\n if (elevation > 0) {\n const faceFill = darken(this.zoneColor.get(obj.zone ?? '') ?? baseFill, 0.42);\n for (let i = 0; i < obj.outline.length; i++) {\n const face = new Line({\n points: [],\n closed: true,\n fill: faceFill,\n stroke: rgba('#000000', 0.25),\n strokeWidth: 1,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n sideFaces.push(face);\n this.bgLayer.add(face); // behind the group added next → behind the fill\n }\n liftGroupBg = new Group({ listening: false });\n this.bgLayer.add(liftGroupBg);\n liftGroupSeat = new Group({ listening: false });\n this.seatLayer.add(liftGroupSeat);\n }\n const bgTarget: Group | Layer = liftGroupBg ?? this.bgLayer;\n\n // Zone-coloured outline under the seats — matches the crisp section blocks\n // the designer draws, so the near-zoom map reads as defined zones too.\n const outlineTint = obj.color ?? this.zoneColor.get(obj.zone ?? '') ?? '#3a4358';\n const outlinePoly = polygonWithHolesShape(obj.outline, obj.holes, {\n stroke: rgba(outlineTint, 0.5),\n strokeWidth: 1.75,\n fill: rgba(outlineTint, 0.08),\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(outlinePoly);\n\n // Neutral overview shell — category paint is intentionally deferred until\n // focus/seat detail so the venue hierarchy remains legible at first glance.\n const blockPoly = polygonWithHolesShape(obj.outline, obj.holes, {\n fill: palette.sectionFill,\n stroke: palette.sectionStroke,\n strokeWidth: SECTION_STROKE_PX,\n opacity: 0,\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(blockPoly);\n\n // Per-section label overrides (size/color) layered on the overview defaults.\n // color becomes the preferred ink the block-melt loop auto-contrasts each\n // frame; size scales the fitted screen-px band (default section size = 18).\n const labelStyle = obj.labelPresentation?.labelStyle;\n const preferredInk = labelStyle?.color ?? palette.sectionInk;\n const labelScale = (labelStyle?.size ?? 18) / 18;\n const nameLabel = new Text({\n x: obj.labelPresentation?.position?.x ?? centroid.x,\n y: obj.labelPresentation?.position?.y ?? centroid.y,\n text: obj.displayLabel ?? obj.label,\n rotation: obj.labelPresentation?.rotation ?? 0,\n visible: obj.labelPresentation?.visible !== false,\n fontSize: 22 * labelScale,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: stateAwareBookableLabelInk(palette.sectionFill, preferredInk),\n listening: false,\n perfectDrawEnabled: false,\n });\n nameLabel.offsetX(nameLabel.width() / 2);\n nameLabel.offsetY(nameLabel.height() / 2);\n bgTarget.add(nameLabel);\n\n const subLabel = new Text({\n x: centroid.x,\n y: centroid.y,\n text: t('map.seatsLeft', { count: free }),\n fontSize: 12,\n fontStyle: '700',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: palette.sectionInk,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n subLabel.offsetX(subLabel.width() / 2);\n bgTarget.add(subLabel);\n\n const sec: SectionRender = {\n id: obj.id,\n logicalId: obj.logicalSectionId ?? obj.id,\n label: obj.displayLabel ?? obj.label,\n outline: obj.outline,\n ...(obj.outlinePath ? { outlinePath: obj.outlinePath } : {}),\n holes: obj.holes ?? [],\n centroid,\n labelAnchors: polygonLabelCandidates(obj.outline, obj.holes ?? [], centroid),\n zone: obj.zone,\n memberIds,\n total: memberIds.length,\n free,\n baseFill,\n outlineTint,\n outlinePoly,\n blockPoly,\n nameLabel,\n subLabel,\n preferredInk,\n labelScale,\n nameLabelFits: true,\n subLabelFits: true,\n elevation,\n liftGroupBg,\n liftGroupSeat,\n sideFaces,\n };\n for (const id of memberIds) this.seatSection.set(id, sec);\n this.refreshSectionFill(sec);\n this.refreshSectionHeat(sec);\n this.sections.push(sec);\n }\n\n private refreshSectionHeat(sec: SectionRender): void {\n const raw = this.sectionHeat.get(sec.id)\n ?? this.sectionHeat.get(sec.logicalId)\n ?? (sec.zone ? this.sectionHeat.get(sec.zone) : undefined);\n if (raw == null || raw <= 0) {\n sec.outlinePoly.stroke(rgba(sec.outlineTint, 0.5));\n sec.outlinePoly.fill(rgba(sec.outlineTint, 0.08));\n sec.outlinePoly.strokeWidth(1.75);\n sec.outlinePoly.shadowOpacity(0);\n return;\n }\n const color = lerpColor('#f4b740', '#ef4444', raw);\n sec.outlinePoly.stroke(rgba(color, 0.72 + raw * 0.25));\n sec.outlinePoly.fill(rgba(color, 0.08 + raw * 0.13));\n sec.outlinePoly.strokeWidth(2 + raw * 3.5);\n sec.outlinePoly.shadowColor(color);\n sec.outlinePoly.shadowBlur(4 + raw * 12);\n sec.outlinePoly.shadowOpacity(0.25 + raw * 0.45);\n }\n\n /** Recompute a section's neutral overview state and retained detail count. */\n private refreshSectionFill(sec: SectionRender): void {\n sec.blockPoly.fill(this.sectionBlockFill(sec));\n sec.subLabel.text(t('map.seatsLeft', { count: sec.free }));\n sec.subLabel.offsetX(sec.subLabel.width() / 2);\n }\n\n /** True when a section/zone is currently in the `closed` event-state. */\n private isSectionClosed(sec: SectionRender): boolean {\n return this.closedSections.has(sec.id)\n || this.closedSections.has(sec.logicalId)\n || (sec.zone != null && this.closedSections.has(sec.zone));\n }\n\n /** Clean overview shells never leak category, price, or live availability paint. */\n private sectionBlockFill(sec: SectionRender): string {\n const fill = overviewPalette(this.canvasBackground).sectionFill;\n return this.isSectionClosed(sec) ? darken(fill, 0.12) : fill;\n }\n\n /**\n * Zone rung: one giant screen-constant label per zone (+ optional \"FROM $n\"),\n * shown at the farthest zoom in place of per-section detail. Skipped entirely\n * when the doc declares no zones — sections then stay the far rung (graceful).\n */\n private renderZones(doc: ChartDoc): void {\n if (!doc.zones?.length || !this.sections.length) return;\n const byZone = new Map<string, SectionRender[]>();\n for (const sec of this.sections) {\n if (!sec.zone) continue;\n (byZone.get(sec.zone) ?? byZone.set(sec.zone, []).get(sec.zone)!).push(sec);\n }\n for (const z of doc.zones) {\n const members = byZone.get(z.id);\n if (!members || !members.length) continue;\n // Anchor at the TOPMOST member (min y), not the mean centroid: for a\n // symmetric bowl (a zone = a full ring around the stage) the mean lands on\n // the origin and every zone label stacks on the stage. The topmost member\n // gives a distinct point per ring (labels stack up the vertical axis).\n let anchor = members[0];\n for (const s of members) if (s.centroid.y < anchor.centroid.y) anchor = s;\n const cx = anchor.centroid.x;\n const cy = anchor.centroid.y;\n\n // \"FROM $n\" = cheapest category price found among this zone's member seats.\n let minPrice = Infinity;\n for (const sec of members) {\n for (const id of sec.memberIds) {\n const seat = this.seatById.get(id);\n const p = seat && this.catPrice.get(seat.categoryKey);\n if (typeof p === 'number' && p < minPrice) minPrice = p;\n }\n }\n\n // A zone name often extends beyond its irregular section polygon. Give\n // the entire caption an opaque, measured backing instead of choosing ink\n // against only the anchor section and then painting part of that text over\n // the surrounding canvas.\n const back = new Rect({\n x: cx,\n y: cy,\n width: 1,\n height: 1,\n offsetX: 0.5,\n offsetY: 0.5,\n cornerRadius: 1,\n fill: HIERARCHY_PILL_BACKGROUND,\n stroke: z.color ?? anchor.outlineTint,\n strokeWidth: 1,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n this.bgLayer.add(back);\n\n const label = new Text({\n x: cx,\n y: cy,\n text: z.label.toUpperCase(),\n fontSize: ZONE_LABEL_PX,\n fontStyle: '800',\n letterSpacing: 0.5,\n fontFamily: this.labelFont(),\n fill: '#f4f6fb',\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n label.offsetX(label.width() / 2);\n label.offsetY(label.height() / 2);\n this.bgLayer.add(label);\n\n let sub: Text | null = null;\n if (isFinite(minPrice)) {\n sub = new Text({\n x: cx,\n y: cy,\n text: t('map.fromPrice', { price: formatMoney(minPrice, this.currency) }),\n fontSize: 14,\n fontStyle: '600',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: '#cbd5e1',\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n sub.offsetX(sub.width() / 2);\n this.bgLayer.add(sub);\n }\n this.zones.push({\n id: z.id,\n anchor: { x: cx, y: cy },\n back,\n background: HIERARCHY_PILL_BACKGROUND,\n label,\n sub,\n });\n }\n }\n\n /**\n * THE MELT — a continuous, scale-driven cross-fade across the three rungs:\n * seats ⇄ section blocks ⇄ zone blocks.\n * `blockT` ramps 0→1 as scale falls through [SECTION_PROMINENT, CACHE_THRESHOLD]\n * so the solid fill is fully present exactly as seats become the cached bitmap\n * and fade out; `zoneT` ramps 0→1 across [ZONE_PROMINENT, SECTION_PROMINENT] so\n * per-section detail hands off to giant zone labels. Reduced-motion hard-swaps.\n * Section/zone labels are scale-compensated to hold a roughly constant screen size.\n */\n private applySectionLod(scale: number): void {\n let blockT: number;\n let zoneT: number;\n if (this.reducedMotion) {\n blockT = scale <= SECTION_PROMINENT_SCALE ? 1 : 0;\n zoneT = scale <= ZONE_PROMINENT_SCALE ? 1 : 0;\n } else {\n blockT = clamp((BLOCK_MELT_TOP - scale) / (BLOCK_MELT_TOP - SECTION_PROMINENT_SCALE), 0, 1);\n zoneT = clamp((SECTION_PROMINENT_SCALE - scale) / (SECTION_PROMINENT_SCALE - ZONE_PROMINENT_SCALE), 0, 1);\n }\n // The overview rung is a crisp semantic composition. Finish the melt before\n // entering it so no residual seats or category outlines leak through simply\n // because zoom-to-fit landed a few hundredths below the detail threshold.\n const sectionOverview = scale < CACHE_THRESHOLD;\n if (sectionOverview) blockT = 1;\n // No zones ⇒ skip the zone rung: sections stay the far rung (graceful).\n if (!this.zones.length) zoneT = 0;\n\n // Seats melt out as the block fill melts in (coordinated with the bitmap swap).\n this.seatLayer.opacity(sectionOverview ? 0 : 1 - blockT);\n\n // Labels are drawn UPRIGHT (the iso squash is cancelled per-text), so their\n // on-screen size follows the raw stage scale, not the squashed effective one.\n const sx = this.stage.scaleX();\n // Scale-compensate label sizes only when the scale meaningfully changed.\n const rescale = this.lodScale === 0 || Math.abs(scale - this.lodScale) / (this.lodScale || 1) > 0.02;\n if (rescale) this.lodScale = scale;\n\n const focus = this.focusedSectionId;\n const palette = overviewPalette(this.canvasBackground);\n // Avoid a ghosted label during the first 20% of the block melt, when\n // individual bookable shapes are still the dominant visual layer.\n const sectionLabelT = clamp((blockT - 0.2) / 0.8, 0, 1);\n for (const sec of this.sections) {\n // AXS focus: non-focused sections dim to ~16%; the focused block stays full.\n const dim = focus && sec.id !== focus && sec.logicalId !== focus && sec.zone !== focus ? FOCUS_DIM_OPACITY : 1;\n // Category-tinted detail outlines disappear as the clean shell takes over.\n sec.outlinePoly.opacity(sectionOverview ? 0 : (1 - blockT) * dim);\n sec.blockPoly.opacity(BLOCK_FILL_ALPHA * blockT * dim);\n sec.blockPoly.stroke(palette.sectionStroke);\n sec.blockPoly.strokeWidth(SECTION_STROKE_PX / Math.max(sx, 0.0001));\n // Section names belong to the block rung. Hide them completely once\n // individual seats/booths are the active layer so they cannot sit under\n // bookable labels or shapes.\n const sectionFill = sec.blockPoly.fill();\n const sectionInk = stateAwareBookableLabelInk(\n typeof sectionFill === 'string' ? sectionFill : sec.baseFill,\n sec.preferredInk,\n );\n sec.nameLabel.fill(sectionInk);\n sec.subLabel.fill(sectionInk);\n if (rescale) this.fitSectionRungLabels(sec, sx);\n const labelOpacity = sectionLabelT * (1 - zoneT) * dim;\n sec.nameLabel.opacity(sec.nameLabelFits ? labelOpacity : 0);\n // Availability stays in the focused/detail UI. It is deliberately not a\n // second map label at the clean section-overview rung.\n sec.subLabel.opacity(0);\n }\n\n // Fade the big zone labels out as the view tilts into 3D — the raised tiers\n // read clearly on their own, and the overlaid zone text just clutters them.\n const zoneOpacity = zoneT * (1 - this.isoT);\n for (const zone of this.zones) {\n zone.back.opacity(zoneOpacity);\n zone.label.opacity(zoneOpacity);\n if (zone.sub) zone.sub.opacity(zoneOpacity);\n if (rescale) this.sizeZonePill(zone, sx);\n }\n // Greedy de-collision of the visible label tiers (small canvases stack\n // \"UPPER BOWL\"/\"LOWER BOWL\"/FROM-$ on top of each other otherwise).\n this.decollideRungLabels(sx);\n this.dedupeLogicalSectionLabels();\n for (const zone of this.zones) {\n const opacity = zone.label.opacity();\n zone.back.opacity(opacity);\n if (zone.sub) zone.sub.opacity(opacity);\n }\n this.bgLayer.batchDraw();\n }\n\n /** One semantic section gets one overview label, even across split contours. */\n private dedupeLogicalSectionLabels(): void {\n const byLogical = new Map<string, SectionRender[]>();\n for (const section of this.sections) {\n (byLogical.get(section.logicalId) ?? byLogical.set(section.logicalId, []).get(section.logicalId)!).push(section);\n }\n for (const components of byLogical.values()) {\n if (components.length < 2) continue;\n const visible = components\n .filter((component) => component.nameLabel.opacity() > 0.05)\n .sort((left, right) => {\n const leftBounds = polyBounds(left.outline);\n const rightBounds = polyBounds(right.outline);\n return rightBounds.width * rightBounds.height - leftBounds.width * leftBounds.height;\n });\n for (const component of visible.slice(1)) component.nameLabel.opacity(0);\n }\n }\n\n /**\n * Keep transitional zone pills from covering section names. Section names\n * are already proven inside disjoint shells, so they must not cull each other.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; box: { x: number; y: number; w: number; h: number } }\n const cands: Cand[] = [];\n const boxOf = (t: Text): { x: number; y: number; w: number; h: number } => {\n const p = this.worldToScreen({ x: t.x(), y: t.y() });\n const rotated = pointsBounds(rotatedRectPoints(\n { x: 0, y: 0 },\n t.width() * sx,\n t.height() * sx,\n t.rotation(),\n ));\n const w = rotated.width;\n const h = rotated.height;\n return { x: p.x - w / 2, y: p.y - h / 2, w, h };\n };\n for (const zone of this.zones) {\n if (zone.label.opacity() > 0.05) {\n const p = this.worldToScreen(zone.anchor);\n const w = zone.back.width() * sx;\n const h = zone.back.height() * sx;\n cands.push({ node: zone.label, tier: 0, section: false, box: { x: p.x - w / 2, y: p.y - h / 2, w, h } });\n }\n }\n for (const sec of this.sections) {\n if (sec.nameLabel.opacity() > 0.05) cands.push({ node: sec.nameLabel, tier: 1, section: true, box: boxOf(sec.nameLabel) });\n }\n if (cands.length < 2) return;\n cands.sort((a, b) => a.tier - b.tier || a.box.y - b.box.y || a.box.x - b.box.x);\n const kept: Cand['box'][] = [];\n const collides = (b: Cand['box']): boolean =>\n kept.some((k) =>\n b.x < k.x + k.w + GAP && k.x < b.x + b.w + GAP &&\n b.y < k.y + k.h + GAP && k.y < b.y + b.h + GAP,\n );\n for (const c of cands) {\n if (collides(c.box)) {\n c.node.opacity(0);\n } else if (!c.section) {\n // Section shells do not collide by construction; only zone pills form\n // blockers for later transitional labels.\n kept.push(c.box);\n }\n }\n }\n\n /** Set a centred label's world fontSize (for a target screen px) and re-anchor it. */\n private sizeLabel(t: Text, fontSize: number, y: number): void {\n t.fontSize(Math.max(1, fontSize));\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.y(y);\n }\n\n /** Fit one centred section name, rotating narrow shells like the target chart. */\n private fitSectionRungLabels(sec: SectionRender, sx: number): void {\n const paddingPx = 8;\n sec.subLabelFits = false;\n // Scale the fitted screen-px band by the section's authored label size so a\n // larger override reads larger; the step still shrinks to fit the polygon.\n const maxPx = SECTION_LABEL_PX * sec.labelScale;\n const minPx = MIN_SECTION_LABEL_PX * sec.labelScale;\n for (let fontPx = maxPx; fontPx >= minPx; fontPx -= 1) {\n for (const rotation of [0, -90]) {\n sec.nameLabel.rotation(rotation);\n this.sizeLabel(sec.nameLabel, fontPx / sx, sec.nameLabel.y());\n for (const anchor of sec.labelAnchors) {\n sec.nameLabel.position(anchor);\n const paddingWorld = paddingPx / sx;\n if (rotatedRectFitsPolygon(\n anchor,\n sec.nameLabel.width() + paddingWorld,\n sec.nameLabel.height() + paddingWorld,\n rotation,\n sec.outline,\n sec.holes,\n )) {\n sec.nameLabelFits = true;\n return;\n }\n }\n }\n }\n sec.nameLabel.position(sec.centroid);\n sec.nameLabel.rotation(0);\n sec.nameLabelFits = false;\n }\n\n /** Size one screen-constant zone name/price pill around its shared anchor. */\n private sizeZonePill(zone: ZoneRender, sx: number): void {\n const padX = 10 / sx;\n const padY = 6 / sx;\n const gap = zone.sub ? 3 / sx : 0;\n this.sizeLabel(zone.label, ZONE_LABEL_PX / sx, zone.anchor.y);\n if (zone.sub) this.sizeLabel(zone.sub, ZONE_SUB_PX / sx, zone.anchor.y);\n const width = Math.max(zone.label.width(), zone.sub?.width() ?? 0) + padX * 2;\n const height = zone.label.height() + (zone.sub ? gap + zone.sub.height() : 0) + padY * 2;\n zone.label.y(zone.anchor.y - (zone.sub ? (gap + zone.sub.height()) / 2 : 0));\n if (zone.sub) zone.sub.y(zone.anchor.y + (zone.label.height() + gap) / 2);\n zone.back.position(zone.anchor);\n zone.back.size({ width, height });\n zone.back.offset({ x: width / 2, y: height / 2 });\n zone.back.cornerRadius(7 / sx);\n zone.back.strokeWidth(1 / sx);\n }\n\n /**\n * Map a container-relative screen point back to world coords. Inverts the\n * stage (scale/pos) and, in iso view, the iso affine — so screen-space taps\n * test against the flat world outlines/geometry. Identity-equivalent at isoT=0.\n */\n private screenToWorld(clientPoint: { x: number; y: number }): { x: number; y: number } {\n const s = this.stage.scaleX();\n const iso = { x: (clientPoint.x - this.stage.x()) / s, y: (clientPoint.y - this.stage.y()) / s };\n return this.isoT === 0 ? iso : this.isoInverse(iso);\n }\n\n /** Section id under a container-relative screen point, or null (Slice 5 tap-to-zoom). */\n sectionAt(clientPoint: { x: number; y: number }): string | null {\n if (!this.sections.length) return null;\n const world = this.screenToWorld(clientPoint);\n const hit = this.sections.find((sec) => pointInPolygonWithHoles(world, sec.outline, sec.holes));\n return hit ? hit.logicalId : null;\n }\n\n /** Seat ids belonging to a section (Slice 5 section-summary card). */\n sectionMembers(id: string): string[] {\n return [...new Set(this.sections\n .filter((section) => section.id === id || section.logicalId === id || section.zone === id)\n .flatMap((section) => section.memberIds))];\n }\n\n private addCentredLabel(\n layer: Layer,\n text: string,\n x: number,\n y: number,\n fill: string,\n fontSize: number,\n bold: boolean,\n ): Text {\n const t = new Text({\n x,\n y,\n text,\n fontSize,\n fontStyle: bold ? '700' : '500',\n fontFamily: this.labelFont(),\n fill,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n layer.add(t);\n return t;\n }\n\n // ---- selection ------------------------------------------------------------\n\n private isSelectable(id: string): boolean {\n // A closed section's seats are never pickable, whatever their raw status.\n if (this.seatInClosedSection(id)) return false;\n const statuses = this.opts.selectableStatuses ?? ['free'];\n return statuses.includes(this.statusById.get(id) ?? 'free');\n }\n\n private toggleSeat(id: string): void {\n if (this.selection.has(id)) {\n this.setSelected(id, false);\n const seat = this.seatById.get(id);\n if (seat) this.opts.onDeselect?.(seat);\n } else {\n if (!this.isSelectable(id)) return;\n if (this.selection.size >= this.opts.maxSelection) {\n this.opts.onSelectionLimit?.(this.opts.maxSelection);\n return;\n }\n this.setSelected(id, true);\n const seat = this.seatById.get(id);\n if (seat) this.opts.onSelect?.(seat);\n }\n this.overlayLayer.batchDraw();\n }\n\n /**\n * Selection/hover ring color. An explicit theme.selectionColor always wins;\n * otherwise auto-contrast against the effective canvas background — the\n * designer renders on dark (white ring reads), but light-themed hosts (e.g.\n * the DesiPass buyer picker on cream) made the white ring invisible and\n * selected seats looked *disabled*. theme.background is checked first, then\n * the container's computed CSS background (walking up past transparent\n * ancestors). Unknown/unparseable backgrounds keep the dark default.\n */\n private resolveCanvasBackground(): string {\n const themed = this.theme.background ? opaqueColorHex(this.theme.background) : null;\n if (themed) return themed;\n if (typeof getComputedStyle === 'function') {\n let element: HTMLElement | null = this.container;\n while (element) {\n const resolved = opaqueColorHex(getComputedStyle(element).backgroundColor);\n if (resolved) return resolved;\n element = element.parentElement;\n }\n }\n return DEF_CANVAS_BACKGROUND;\n }\n\n private resolveSelectionColor(): string {\n if (this.theme.selectionColor) return this.theme.selectionColor;\n return isLightColor(this.canvasBackground) ? DEF_SELECTION_ON_LIGHT : DEF_SELECTION;\n }\n\n private setSelected(id: string, on: boolean, silent = false): void {\n const c = this.circleById.get(id);\n if (on) {\n this.selection.add(id);\n } else {\n if (this.selectionFocusId === id) this.setSelectionFocus(null);\n this.selection.delete(id);\n }\n this.syncSelectionMarker(id);\n if (c) {\n this.paintSeat(c, id);\n if (!silent && !this.cached) this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild one marker after selected/held/candidate state changes. */\n private syncSelectionMarker(id: string): void {\n this.selectionMarkers.get(id)?.destroy();\n this.selectionMarkers.delete(id);\n if (!this.selection.has(id) && !this.ownedHold.has(id)) return;\n\n const seat = this.seatById.get(id);\n if (!seat) return;\n const candidate = this.selectionFocusId === id;\n const dims = this.boothDims.get(seat.rowId);\n const marker = new Group({\n name: 'selection-ring',\n x: seat.x,\n y: seat.y,\n rotation: dims?.rotation ?? 0,\n listening: false,\n perfectDrawEnabled: false,\n opacity: this.selectionFocusId && !candidate ? 0.2 : 1,\n });\n marker.setAttr('seatId', id);\n const common = {\n stroke: this.effSelection,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n };\n\n if (dims) {\n marker.add(new Rect({\n ...common,\n width: dims.width,\n height: dims.height,\n offsetX: dims.width / 2,\n offsetY: dims.height / 2,\n cornerRadius: 4,\n strokeWidth: candidate ? 4 : 3,\n }));\n if (candidate) {\n marker.add(new Rect({\n ...common,\n width: dims.width + 10,\n height: dims.height + 10,\n offsetX: (dims.width + 10) / 2,\n offsetY: (dims.height + 10) / 2,\n cornerRadius: 7,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n const badgeX = Math.max(0, dims.width / 2 - 14);\n const badgeY = -Math.max(0, dims.height / 2 - 14);\n marker.add(new Circle({ x: badgeX, y: badgeY, radius: 10, fill: this.effSelection, listening: false }));\n marker.add(new Line({\n x: badgeX,\n y: badgeY,\n points: [-4.5, 0, -1, 3.5, 5.5, -4.5],\n stroke: isLightColor(this.effSelection) ? '#0b1220' : '#ffffff',\n strokeWidth: 2.4,\n lineCap: 'round',\n lineJoin: 'round',\n listening: false,\n }));\n }\n } else {\n marker.add(new Circle({ ...common, radius: this.seatR + (candidate ? 4.5 : 2.5), strokeWidth: candidate ? 3.5 : 2.5 }));\n if (candidate) {\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 8,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n marker.add(new Line({\n points: [-this.seatR * 0.52, 0, -this.seatR * 0.12, this.seatR * 0.4, this.seatR * 0.6, -this.seatR * 0.46],\n stroke: '#ffffff',\n strokeWidth: Math.max(2.6, this.seatR * 0.34),\n lineCap: 'round',\n lineJoin: 'round',\n shadowColor: '#0b1220',\n shadowBlur: 1.5,\n shadowOpacity: 0.55,\n listening: false,\n }));\n }\n }\n\n this.selectionMarkers.set(id, marker);\n this.overlayLayer.add(marker);\n }\n\n // ---- interaction ----------------------------------------------------------\n\n /**\n * The stage scale `focusRegion(id)` would settle at — i.e. the zoom that\n * frames this section in the current viewport. Used to decide whether\n * redirecting a seat tap to section-focus would actually zoom in FURTHER, or\n * whether the section already fills the viewport (small container) so the tap\n * must fall through and pick.\n */\n private sectionBounds(id: string): { x: number; y: number; width: number; height: number } | null {\n const bounds = this.sections\n .filter((section) => section.id === id || section.logicalId === id)\n .map((section) => polyBounds(section.outline));\n if (!bounds.length) return null;\n const left = Math.min(...bounds.map((box) => box.x));\n const top = Math.min(...bounds.map((box) => box.y));\n const right = Math.max(...bounds.map((box) => box.x + box.width));\n const bottom = Math.max(...bounds.map((box) => box.y + box.height));\n return { x: left, y: top, width: right - left, height: bottom - top };\n }\n\n private sectionFrameScale(id: string): number {\n const b = this.sectionBounds(id);\n if (!b) return this.stage.scaleX();\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n if (b.width <= 0 || b.height <= 0) return this.stage.scaleX();\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n return clamp(Math.max(frameScale, SEAT_FOCUS_SCALE), min, max);\n }\n\n /**\n * Resolve a seat tap: honour the 3D deck-drill and the AXS seat-pick gate,\n * then toggle. The gate (§4) redirects small on-screen seats to section-focus\n * to avoid blind mis-picks at overview scales — but ONLY when focusing would\n * zoom the seat up to a safe size. If we're already focused on the section, or\n * the section already fills the viewport (a narrow — OR even a wide — container\n * frames a big section BELOW LABEL_SCALE), redirecting is a no-op that would\n * leave the seat permanently unpickable (§5 `picking-gate-unreachable`), so we\n * fall through and PICK. This is the invariant: seats are never unpickable.\n */\n private handleSeatTap(id: string): void {\n // In the 3D all-floors overview, tapping a seat enters its deck in 2D\n // rather than selecting (seat picking happens on the flat floor map).\n if (this.stacked && this.opts.onDeckTap) {\n const floorId = this.objectFloor.get(this.seatById.get(id)?.rowId ?? '');\n if (floorId) { this.opts.onDeckTap(floorId); return; }\n }\n if (this.effScale() < LABEL_SCALE && this.sections.length) {\n const sec = this.seatSection.get(id);\n if (sec) {\n const alreadyFocused = this.focusedSectionId === sec.logicalId;\n // Would section-focus zoom us in meaningfully (>2%)? If not, the gate has\n // nowhere left to go — pick instead of deadlocking.\n const canZoomInFurther = this.sectionFrameScale(sec.logicalId) > this.stage.scaleX() * 1.02;\n if (!alreadyFocused && canZoomInFurther) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(sec.logicalId);\n else this.focusSection(sec.logicalId);\n return;\n }\n }\n }\n this.toggleSeat(id);\n }\n\n /**\n * Nearest SELECTABLE seat whose centre is within `slopPx` (screen space) of a\n * seat circle edge, or null. Enlarges the effective tap target for small seats\n * so a near-miss on mobile still lands on the intended seat, without ever\n * hijacking a clean tap on empty space beyond the slop.\n */\n private nearestSeatToScreen(screen: { x: number; y: number }, slopPx: number): string | null {\n const s = this.stage.scaleX() || 1;\n const reachWorld = this.seatR + slopPx / s; // circle radius + finger slack\n const world = this.screenToWorld(screen);\n let best: string | null = null;\n let bestD = reachWorld;\n for (const seat of this.seats) {\n if (!this.selection.has(seat.id) && !this.isSelectable(seat.id)) continue;\n const d = Math.hypot(seat.x - world.x, seat.y - world.y);\n if (d < bestD) {\n bestD = d;\n best = seat.id;\n }\n }\n return best;\n }\n\n private wireInteraction(): void {\n this.seatLayer.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.moved > PAN_START_SLOP_PX) return; // it was a pan/pinch, not a tap\n const id = seatIdOf(e.target);\n if (!id) return;\n this.handleSeatTap(id);\n });\n\n // Hover (mouse only) via delegated enter/leave on seat circles.\n this.seatLayer.on('mouseover', (e: KonvaEventObject<MouseEvent>) => {\n const id = seatIdOf(e.target);\n if (!id) return;\n const seat = this.seatById.get(id);\n if (!seat) return;\n this.hoverRing.position({ x: seat.x, y: seat.y });\n this.hoverRing.visible(true);\n this.overlayLayer.batchDraw();\n this.container.style.cursor = 'pointer';\n this.opts.onHover?.(seat);\n });\n this.seatLayer.on('mouseout', () => {\n this.hoverRing.visible(false);\n this.overlayLayer.batchDraw();\n this.container.style.cursor = 'default';\n this.opts.onHover?.(null);\n });\n\n this.stage.on('wheel', (e: KonvaEventObject<WheelEvent>) => {\n e.evt.preventDefault();\n // Position from the event itself — Konva's tracked pointer position is\n // unreliable when the last pointer event went elsewhere.\n const r = this.container.getBoundingClientRect();\n const pointer = { x: e.evt.clientX - r.left, y: e.evt.clientY - r.top };\n // Scale with the actual wheel delta so trackpad flings and fast wheels\n // zoom proportionally (a fixed step per event ignores delta magnitude).\n const factor = Math.exp(-e.evt.deltaY * 0.002);\n this.zoomAbout(this.stage.scaleX() * clamp(factor, 0.5, 2), pointer);\n });\n\n // Zoomed out, the seat layer is a non-listening cached bitmap and seats\n // are finger-width anyway — a tap zooms into that area instead of\n // attempting a 4px-precision selection (same behaviour as seats.io).\n this.stage.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.moved > PAN_START_SLOP_PX) return;\n const pointer = this.stage.getPointerPosition();\n if (!pointer) return;\n // Seats are LIVE (not a cached bitmap): the seatLayer handler above owns\n // direct seat hits. Here we only rescue near-misses — a finger landing just\n // off a small seat picks the nearest one (mobile hit target, §4 hit ≥ 24px).\n // A clean tap on empty space beyond the slop still does nothing.\n if (!this.cached) {\n if (seatIdOf(e.target)) return; // direct hit already handled\n const near = this.nearestSeatToScreen(pointer, SEAT_TAP_SLOP_PX);\n if (near) this.handleSeatTap(near);\n return;\n }\n // 3D all-floors overview: tapping a deck enters that floor in 2D. The iso\n // projection is a layer transform, so the flat screenToWorld hit-test below\n // won't work here — resolve the deck via the iso-aware nearest seat instead.\n if (this.stacked && this.opts.onDeckTap) {\n const floorId = this.deckFloorAt();\n if (floorId) { this.opts.onDeckTap(floorId); return; }\n }\n // A tap inside a section (seats aren't the active rung here — the layer is\n // cached) hands off to the host: fire onSectionTap so the picker can glide\n // in + show the section-summary card (Slice 5). With no handler wired we\n // keep the standalone behaviour of gliding to fit that section.\n if (this.sections.length) {\n const world = this.screenToWorld(pointer);\n const hit = this.sections.find((sn) => pointInPolygonWithHoles(world, sn.outline, sn.holes));\n if (hit) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(hit.logicalId);\n else this.focusRegion(hit.logicalId);\n return;\n }\n }\n const target = Math.max(SEAT_LEGIBLE_SCALE * 1.2, this.stage.scaleX() * 2.5);\n this.zoomAbout(target, pointer);\n });\n }\n\n /**\n * Which deck (floor) a screen tap landed on in the 3D stacked overview. The\n * seat layer is melt-cached at that zoom so individual seat nodes aren't\n * hit-testable; instead we invert the iso+stage transform via the layer's\n * relative pointer and take the nearest seat's floor. Only the floor matters,\n * so within-floor elevation offsets don't affect the result. Null if none.\n */\n private deckFloorAt(): string | null {\n if (!this.objectFloor.size) return null;\n const p = this.seatLayer.getRelativePointerPosition();\n if (!p) return null;\n let best: string | null = null;\n let bestD = Infinity;\n for (const s of this.seats) {\n const dx = s.x - p.x;\n const dy = s.y - p.y;\n const d = dx * dx + dy * dy;\n if (d < bestD) { bestD = d; best = s.rowId; }\n }\n return best ? this.objectFloor.get(best) ?? null : null;\n }\n\n // ---- Pan & pinch (raw pointer events — mouse, touch and pen alike) --------\n\n private toLocal(e: PointerEvent): { x: number; y: number } {\n const r = this.container.getBoundingClientRect();\n return { x: e.clientX - r.left, y: e.clientY - r.top };\n }\n\n // NOTE: no setPointerCapture here — capturing on the container retargets\n // pointer events away from Konva's canvas, killing its click/tap/hover\n // pipeline. We rely on bubbling instead.\n private onPointerDown = (e: PointerEvent): void => {\n this.cancelGlide(); // grabbing the map cancels an in-flight glide\n const local = this.toLocal(e);\n this.pointers.set(e.pointerId, local);\n if (this.pointers.size === 1) {\n this.moved = 0;\n this.pinch = null;\n this.panStart = local;\n this.panStarted = false;\n // Manage-mode rubber-band marquee (option-gated — buyer pan is byte-\n // identical when manageMode is off). A mouse/pen primary-button drag at\n // the seats rung selects instead of panning; touch keeps single-finger\n // pan (pinch zooms) and a middle-button drag (button !== 0) still pans.\n // Disabled below the seats rung so the organizer zooms in first.\n if (\n this.opts.manageMode && this.opts.marqueeSelect &&\n e.pointerType !== 'touch' && e.button === 0 &&\n this.getRung() === 'seats'\n ) {\n this.beginMarquee(local);\n this.panLast = null;\n } else {\n this.panLast = local;\n }\n } else if (this.pointers.size === 2) {\n // A second finger converts an in-progress marquee into a pinch-zoom.\n if (this.marquee) this.cancelMarquee();\n // Anchor the whole pinch to its starting geometry: scale follows the\n // finger-distance ratio and the world point under the midpoint stays\n // glued to the midpoint. No per-event compounding → no drift.\n const [a, b] = [...this.pointers.values()];\n const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n const s = this.stage.scaleX();\n this.pinch = {\n startDist: Math.hypot(b.x - a.x, b.y - a.y),\n startScale: s,\n worldMid: { x: (mid.x - this.stage.x()) / s, y: (mid.y - this.stage.y()) / s },\n };\n this.panLast = null;\n this.panStart = null;\n this.panStarted = true;\n this.moved = PAN_START_SLOP_PX + 1;\n }\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.pointers.has(e.pointerId)) return;\n e.preventDefault();\n const p = this.toLocal(e);\n this.pointers.set(e.pointerId, p);\n if (this.pointers.size === 1 && this.panStart) {\n this.moved = Math.max(this.moved, Math.hypot(p.x - this.panStart.x, p.y - this.panStart.y));\n } else if (this.pointers.size >= 2) {\n this.moved = PAN_START_SLOP_PX + 1;\n }\n\n if (this.marquee) {\n this.updateMarquee(p);\n return;\n }\n if (this.pinch && this.pointers.size >= 2) {\n const [a, b] = [...this.pointers.values()];\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n if (this.pinch.startDist < 1) return;\n const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n const { min, max } = this.zoomBounds();\n const scale = clamp(this.pinch.startScale * (dist / this.pinch.startDist), min, max);\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: mid.x - this.pinch.worldMid.x * scale,\n y: mid.y - this.pinch.worldMid.y * scale,\n });\n this.stage.batchDraw();\n this.scheduleViewChange();\n } else if (this.panLast && this.pointers.size === 1) {\n // Keep the camera still through normal finger jitter. Aside from making\n // taps feel steadier, this lets Konva deliver the section tap instead of\n // losing it to a one- or two-pixel accidental drag.\n if (!this.panStarted) {\n if (this.moved <= PAN_START_SLOP_PX) return;\n this.panStarted = true;\n }\n this.stage.position({\n x: this.stage.x() + (p.x - this.panLast.x),\n y: this.stage.y() + (p.y - this.panLast.y),\n });\n this.panLast = p;\n this.stage.batchDraw();\n this.scheduleViewChange();\n }\n };\n\n private onPointerEnd = (e: PointerEvent): void => {\n // Finishing a manage-mode marquee: compute the selection on pointer-UP.\n if (this.marquee) {\n this.finishMarquee();\n this.pointers.delete(e.pointerId);\n if (this.pointers.size === 0) this.panLast = null;\n return;\n }\n this.pointers.delete(e.pointerId);\n if (this.pointers.size < 2) this.pinch = null;\n if (this.pointers.size === 1) {\n // pinch → single finger: continue as a pan without jumping\n this.panLast = [...this.pointers.values()][0];\n this.panStart = this.panLast;\n this.panStarted = true;\n }\n if (this.pointers.size === 0) {\n this.panLast = null;\n this.panStart = null;\n this.panStarted = false;\n this.afterViewChange();\n }\n };\n\n /**\n * Min is chart-relative (never lose the room); max is absolute so seats\n * reach a readable size on any chart, however large the venue.\n */\n private zoomBounds(): { min: number; max: number } {\n let min = 0.5 * this.fitScale;\n // When the chart has zones, the zone rung lives at an ABSOLUTE scale\n // (ZONE_PROMINENT_SCALE). On a large venue `0.5·fitScale` can sit above it,\n // making the zone overview unreachable by zooming out — allow a touch more\n // room so the rung is actually reachable (zone-charts only).\n if (this.zones.length) min = Math.min(min, ZONE_PROMINENT_SCALE * 0.9);\n return { min, max: Math.max(10 * this.fitScale, 4) };\n }\n\n /** Zoom so `clientPoint` (stage-relative px) stays fixed under the cursor. */\n private zoomAbout(nextScale: number, clientPoint: { x: number; y: number }): void {\n const { min, max } = this.zoomBounds();\n const scale = clamp(nextScale, min, max);\n const old = this.stage.scaleX();\n if (scale === old) return;\n const worldX = (clientPoint.x - this.stage.x()) / old;\n const worldY = (clientPoint.y - this.stage.y()) / old;\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: clientPoint.x - worldX * scale,\n y: clientPoint.y - worldY * scale,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /** Zoom + pan so world-rect `b` fills the viewport (with a small margin). */\n private zoomToBounds(\n b: { x: number; y: number; width: number; height: number },\n minScale?: number,\n ): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n const scale = clamp(Math.max(frameScale, minScale ?? min), min, max);\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: w / 2 - (b.x + b.width / 2) * scale,\n y: h / 2 - (b.y + b.height / 2) * scale,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /**\n * Smoothly glide the camera to frame a section (by id) or a world-space bounds\n * rect — the Slice 5 \"glide in\". Pan+zoom tween over a calm easeInOutCubic; the\n * melt/LOD rides the camera every frame. `prefers-reduced-motion` (or\n * `opts.animate === false`) snaps via zoomToBounds. A grab (pointer-down) or a\n * newer glide cancels an in-flight one.\n */\n focusRegion(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void {\n const b =\n typeof target === 'string'\n ? this.sectionBounds(target)\n : target;\n if (!b) return;\n this.cancelGlide();\n if (opts?.animate === false || this.reducedMotion) {\n this.zoomToBounds(b, opts?.minScale);\n return;\n }\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n const toScale = clamp(Math.max(frameScale, opts?.minScale ?? min), min, max);\n const toX = w / 2 - (b.x + b.width / 2) * toScale;\n const toY = h / 2 - (b.y + b.height / 2) * toScale;\n const fromScale = this.stage.scaleX();\n const fromX = this.stage.x();\n const fromY = this.stage.y();\n if (Math.abs(toScale - fromScale) < 1e-4 && Math.abs(toX - fromX) < 0.5 && Math.abs(toY - fromY) < 0.5) {\n this.afterViewChange();\n return;\n }\n const start = performance.now();\n const duration = Math.max(180, Math.min(1200, opts?.durationMs ?? CAMERA_GLIDE_MS));\n const step = (now: number): void => {\n if (this.destroyed) { this.glideRaf = 0; return; }\n const raw = Math.min(1, (now - start) / duration);\n const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;\n const sc = fromScale + (toScale - fromScale) * e;\n this.stage.scale({ x: sc, y: sc });\n this.stage.position({ x: fromX + (toX - fromX) * e, y: fromY + (toY - fromY) * e });\n this.updateLOD(); // the melt cross-fades as the camera rides in\n this.scheduleViewChange();\n this.stage.batchDraw();\n if (raw < 1) {\n this.glideRaf = requestAnimationFrame(step);\n } else {\n this.glideRaf = 0;\n this.afterViewChange();\n }\n };\n this.glideRaf = requestAnimationFrame(step);\n }\n\n /** Cancel an in-flight camera glide (a grab or a newer glide interrupts it). */\n private cancelGlide(): void {\n if (this.glideRaf) {\n cancelAnimationFrame(this.glideRaf);\n this.glideRaf = 0;\n }\n }\n\n /** Current LOD rung derived from effective zoom — drives the ZONES/SECTIONS/SEATS pill. */\n getRung(): LodRung {\n const scale = this.effScale();\n if (scale >= CACHE_THRESHOLD) return 'seats';\n if (this.zones.length && scale < ZONE_PROMINENT_SCALE) return 'zones';\n return 'sections';\n }\n\n getRenderedQualityEvidence(): RendererQualityEvidence {\n const effectiveScale = this.effScale();\n const stageScale = this.stage.scaleX();\n const viewport = { width: this.stage.width(), height: this.stage.height() };\n const rounded = (value: number) => Math.round(value * 100) / 100;\n const labels: RenderedBookableLabelEvidence[] = this.seats.map((seat) => {\n const shape = this.circleById.get(seat.id);\n const label = this.boothLabelById.get(seat.id) ?? this.seatLabelById.get(seat.id);\n const authoredFontSize = seat.kind === 'booth'\n ? BOOTH_LABEL_FONT_SIZE\n : SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const renderedFontPx = rounded((label?.fontSize() ?? authoredFontSize) * effectiveScale);\n const screen = this.worldToScreen(seat);\n const outside = screen.x < 0 || screen.x > viewport.width || screen.y < 0 || screen.y > viewport.height;\n const opacity = shape?.opacity() ?? 0;\n const section = this.seatSection.get(seat.id);\n const visible = Boolean(label?.isVisible()) && opacity >= 0.5 && !outside;\n let hiddenReason: RenderedBookableLabelEvidence['hiddenReason'];\n if (!visible) {\n if (opacity < 0.5) hiddenReason = 'dimmed-or-unavailable';\n else if (renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX) hiddenReason = 'below-minimum-size';\n else if (outside) hiddenReason = 'outside-viewport';\n else if (!label) hiddenReason = 'clutter-or-fit';\n else hiddenReason = 'renderer-hidden';\n }\n const labelWidth = label ? label.width() * stageScale : 0;\n const labelHeight = label ? label.height() * effectiveScale : 0;\n const directWidthPx = shape instanceof Rect\n ? shape.width() * stageScale\n : this.seatR * 2 * effectiveScale;\n const directHeightPx = shape instanceof Rect\n ? shape.height() * stageScale\n : this.seatR * 2 * effectiveScale;\n // The stage-level near-miss resolver extends every live seat target by\n // SEAT_TAP_SLOP_PX around the same seat radius used by interaction.\n const assistedDiameterPx = 2 * (this.seatR * effectiveScale + SEAT_TAP_SLOP_PX);\n const fill = shape?.fill();\n const ink = label?.fill();\n return {\n seatId: seat.id,\n label: seat.label,\n kind: seat.kind === 'booth' ? 'booth' : 'seat',\n categoryKey: seat.categoryKey,\n ...(section ? { sectionId: section.id } : {}),\n ...(section?.zone ? { zoneId: section.zone } : {}),\n status: this.statusById.get(seat.id) ?? 'free',\n selected: this.selection.has(seat.id),\n visible,\n renderedFontPx,\n fill: typeof fill === 'string' ? fill : '',\n ink: typeof ink === 'string' ? ink : (this.theme.seatLabelColor ?? DEF_SEAT_LABEL),\n opacity: rounded(opacity),\n pointerTarget: {\n active: !this.cached && this.isSelectable(seat.id),\n directWidthPx: rounded(directWidthPx),\n directHeightPx: rounded(directHeightPx),\n effectiveMinimumPx: rounded(Math.max(\n Math.min(directWidthPx, directHeightPx),\n assistedDiameterPx,\n )),\n },\n screenCenter: { x: rounded(screen.x), y: rounded(screen.y) },\n ...(visible ? {\n screenBox: {\n x: rounded(screen.x - labelWidth / 2),\n y: rounded(screen.y - labelHeight / 2),\n width: rounded(labelWidth),\n height: rounded(labelHeight),\n },\n } : {}),\n ...(hiddenReason ? { hiddenReason } : {}),\n };\n });\n const visibleLabels = labels.filter((label) => label.visible).length;\n const hierarchyEvidence = (\n id: string,\n kind: 'section' | 'zone',\n role: 'name' | 'availability' | 'price',\n node: Text,\n backgroundFill: string,\n section?: SectionRender,\n ) => {\n const worldCorners = rotatedRectPoints(\n { x: node.x(), y: node.y() },\n node.width(),\n node.height(),\n node.rotation(),\n );\n const screenBounds = pointsBounds(worldCorners.map((corner) => this.worldToScreen(corner)));\n const opacity = rounded(node.opacity());\n const ink = node.fill();\n const outside = screenBounds.x + screenBounds.width < 0 || screenBounds.x > viewport.width\n || screenBounds.y + screenBounds.height < 0 || screenBounds.y > viewport.height;\n const visible = node.isVisible() && opacity > 0.05 && !outside;\n const fitsContainer = section\n ? rotatedRectFitsPolygon(\n { x: node.x(), y: node.y() },\n node.width(),\n node.height(),\n node.rotation(),\n section.outline,\n section.holes,\n )\n : undefined;\n return {\n id,\n kind,\n role,\n label: node.text(),\n visible,\n renderedFontPx: rounded(node.fontSize() * stageScale),\n opacity,\n fill: backgroundFill,\n ink: typeof ink === 'string' ? ink : '',\n ...(fitsContainer == null ? {} : { fitsContainer }),\n ...(visible ? {\n screenBox: {\n x: rounded(screenBounds.x),\n y: rounded(screenBounds.y),\n width: rounded(screenBounds.width),\n height: rounded(screenBounds.height),\n },\n } : {}),\n };\n };\n const hierarchyLabels = [\n ...this.sections.map((section) => {\n const fill = section.blockPoly.fill();\n return hierarchyEvidence(\n section.id,\n 'section',\n 'name',\n section.nameLabel,\n typeof fill === 'string' ? fill : section.baseFill,\n section,\n );\n }),\n ...this.sections.map((section) => {\n const fill = section.blockPoly.fill();\n return hierarchyEvidence(\n `${section.id}:availability`,\n 'section',\n 'availability',\n section.subLabel,\n typeof fill === 'string' ? fill : section.baseFill,\n section,\n );\n }),\n ...this.zones.flatMap((zone) => [\n hierarchyEvidence(zone.id, 'zone', 'name', zone.label, zone.background),\n ...(zone.sub ? [hierarchyEvidence(`${zone.id}:price`, 'zone', 'price', zone.sub, zone.background)] : []),\n ]),\n ];\n const gaAreas: RenderedGAAreaEvidence[] = [...this.gaById].map(([areaId, ga]) => {\n const screenPoints = ga.points.map((point) => this.worldToScreen(point));\n const left = Math.min(...screenPoints.map((point) => point.x));\n const top = Math.min(...screenPoints.map((point) => point.y));\n const right = Math.max(...screenPoints.map((point) => point.x));\n const bottom = Math.max(...screenPoints.map((point) => point.y));\n const outside = right < 0 || left > viewport.width || bottom < 0 || top > viewport.height;\n const opacity = rounded(ga.polygon.opacity());\n const visible = opacity >= 0.1 && !outside;\n const fill = ga.polygon.fill();\n return {\n areaId,\n label: ga.label,\n capacity: ga.capacity,\n categoryKey: ga.categoryKey,\n ...(ga.sectionId ? { sectionId: ga.sectionId } : {}),\n visible,\n interactive: ga.polygon.listening(),\n opacity,\n fill: typeof fill === 'string' ? fill : '',\n effectiveBackground: ga.effectiveBackground,\n ...(visible ? {\n screenBox: {\n x: rounded(left),\n y: rounded(top),\n width: rounded(right - left),\n height: rounded(bottom - top),\n },\n } : {}),\n };\n });\n const freeTextLabels = [...this.freeTextById].map(([recordKey, record]) => {\n const { node, background, kind } = record;\n const point = this.worldToScreen({ x: node.x(), y: node.y() });\n const width = node.width() * stageScale;\n const height = node.height() * effectiveScale;\n const left = point.x - node.offsetX() * stageScale;\n const top = point.y - node.offsetY() * effectiveScale;\n const renderedFontPx = rounded(node.fontSize() * effectiveScale);\n const outside = left + width < 0 || left > viewport.width\n || top + height < 0 || top > viewport.height;\n const visible = node.isVisible() && !outside;\n const ink = node.fill();\n const opacity = rounded(node.getAbsoluteOpacity());\n let hiddenReason: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden' | undefined;\n if (!visible) {\n if (renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX) hiddenReason = 'below-minimum-size';\n else if (outside) hiddenReason = 'outside-viewport';\n else hiddenReason = 'renderer-hidden';\n }\n return {\n objectId: record.objectId ?? recordKey,\n kind,\n text: node.text(),\n visible,\n renderedFontPx,\n ink: typeof ink === 'string' ? ink : '',\n background,\n opacity,\n ...(visible ? {\n screenBox: {\n x: rounded(left),\n y: rounded(top),\n width: rounded(width),\n height: rounded(height),\n },\n } : {}),\n ...(hiddenReason ? { hiddenReason } : {}),\n };\n });\n const palette = overviewPalette(this.canvasBackground);\n const neutralSectionFills = new Set([\n palette.sectionFill.toLowerCase(),\n darken(palette.sectionFill, 0.12).toLowerCase(),\n ]);\n const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);\n return {\n viewport,\n canvasBackground: this.canvasBackground,\n effectiveScale: rounded(effectiveScale),\n rung: this.getRung(),\n minimumVisibleLabelPx: MIN_VISIBLE_BOOKABLE_LABEL_PX,\n totalLabelledBookableUnits: labels.length,\n visibleLabels,\n hiddenLabels: labels.length - visibleLabels,\n totalBookableUnits: labels.length + gaAreas.reduce((sum, area) => sum + area.capacity, 0),\n selectionRingSeatIds: this.overlayLayer.find('.selection-ring')\n .map((node) => String(node.getAttr('seatId') ?? ''))\n .filter(Boolean),\n selectionRingColor: this.effSelection,\n focusedSectionId: this.focusedSectionId,\n focusBackdropVisible: Boolean(this.focusBackdrop?.isVisible()),\n categoryFilterKeys: this.categoryFilter ? [...this.categoryFilter].sort() : null,\n overviewStyle: {\n visibleSectionShells: visibleSectionShells.length,\n categoryPaintedSectionShells: visibleSectionShells.filter((section) => {\n const fill = section.blockPoly.fill();\n return typeof fill !== 'string' || !neutralSectionFills.has(fill.toLowerCase());\n }).length,\n visibleCategoryDetailOutlines: this.sections.filter((section) => section.outlinePoly.opacity() > 0.05).length,\n // Row-hint nodes no longer exist in the production overview scene.\n visibleSectionRowHints: 0,\n visibleSectionAvailabilityLabels: this.sections.filter((section) => section.subLabel.opacity() > 0.05).length,\n visibleSectionGADetails: [...this.gaById.values()].filter((area) => (\n area.sectionId != null && area.polygon.opacity() > 0.05\n )).length,\n },\n labels,\n gaAreas,\n hierarchyLabels,\n freeTextLabels,\n };\n }\n\n /** Jump the camera to a rung's zoom band (glided). */\n setRung(rung: LodRung): void {\n if (rung === 'zones') {\n this.cancelGlide();\n this.zoomToFit();\n return;\n }\n const target =\n rung === 'sections'\n ? (SECTION_PROMINENT_SCALE + CACHE_THRESHOLD) / 2\n : Math.max(\n this.seatLabelTargetScale() * 1.05,\n SEAT_FOCUS_SCALE,\n CACHE_THRESHOLD * 1.3,\n );\n const w = this.stage.width();\n const h = this.stage.height();\n const visible = this.getVisibleWorldRect();\n const viewCentre = {\n x: visible.x + visible.width / 2,\n y: visible.y + visible.height / 2,\n };\n let cx = viewCentre.x;\n let cy = viewCentre.y;\n if (rung === 'sections' && this.sections.length > 0) {\n const sectionCentres = this.sections.map((section) => {\n const bounds = polyBounds(section.outline);\n return {\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n };\n });\n const halfWidth = w / (target * 2);\n const halfHeight = h / (target * 2);\n const hierarchyWillBeVisible = sectionCentres.some((point) =>\n Math.abs(point.x - viewCentre.x) <= halfWidth\n && Math.abs(point.y - viewCentre.y) <= halfHeight);\n if (!hierarchyWillBeVisible) {\n // A narrow viewport through the empty centre of an upper stadium deck\n // can miss every section. Fall back to the nearest hierarchy block.\n const nearest = sectionCentres.reduce((best, point) => {\n const distance = (point.x - viewCentre.x) ** 2 + (point.y - viewCentre.y) ** 2;\n return distance < best.distance ? { point, distance } : best;\n }, { point: sectionCentres[0], distance: Infinity });\n cx = nearest.point.x;\n cy = nearest.point.y;\n }\n }\n const seatAnchors = rung === 'seats' ? this.seats.filter((seat) => seat.kind !== 'booth') : [];\n if (seatAnchors.length > 0) {\n // Bowl/arena charts commonly have an empty focal area at their geometric\n // centre. Centring a deep seat zoom there exposes only the pitch or stage.\n // Anchor the rung on the nearest actual seat to the current view centre so\n // explicit LOD navigation stays local after a pan and always reveals\n // bookable inventory after zoom-to-fit.\n let nearest = seatAnchors[0];\n let nearestDistance = Infinity;\n for (const seat of seatAnchors) {\n const dx = seat.x - viewCentre.x;\n const dy = seat.y - viewCentre.y;\n const distance = dx * dx + dy * dy;\n if (distance < nearestDistance) {\n nearest = seat;\n nearestDistance = distance;\n }\n }\n cx = nearest.x;\n cy = nearest.y;\n }\n const bw = w / (target * 1.12);\n const bh = h / (target * 1.12);\n this.focusRegion({ x: cx - bw / 2, y: cy - bh / 2, width: bw, height: bh });\n }\n\n /**\n * The seat rung must account for labels that auto-fit inside a seat circle.\n * A short `A-1` remains at the normal 7u target; a table label such as\n * `T13-10` may fit at 4u and therefore needs a deeper camera target to reach\n * the same 12 CSS-pixel floor. Measurement happens only on explicit rung\n * navigation, never during pan/zoom frames.\n */\n private seatLabelTargetScale(): number {\n let minimumFont = BOOTH_LABEL_FONT_SIZE;\n const measure = new Text({\n fontSize: SEAT_LABEL_FONT_SIZE,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n listening: false,\n });\n const maxWidth = this.seatR * 2 - 3;\n for (const seat of this.seats) {\n if (seat.kind === 'booth') {\n minimumFont = Math.min(minimumFont, BOOTH_LABEL_FONT_SIZE);\n continue;\n }\n const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n measure.fontSize(authoredFontSize);\n measure.text(bookableMarkerLabel(seat.displayLabel ?? seat.label));\n const fitted = measure.width() > maxWidth\n ? Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, (authoredFontSize * maxWidth) / measure.width())\n : authoredFontSize;\n minimumFont = Math.min(minimumFont, fitted);\n }\n measure.destroy();\n return MIN_VISIBLE_BOOKABLE_LABEL_PX / Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, minimumFont);\n }\n\n /** Recompute LOD (cache/labels) after any pan/zoom settles. */\n private afterViewChange(): void {\n this.updateLOD();\n this.updateFreeTextVisibility();\n this.updateLabels();\n this.scheduleViewChange();\n }\n\n /** rAF-coalesced `onViewChange` — at most one host callback per animation frame. */\n private scheduleViewChange(): void {\n if (this.viewChangeRaf) return;\n this.viewChangeRaf = requestAnimationFrame(() => {\n this.viewChangeRaf = 0;\n this.opts.onViewChange?.();\n });\n }\n\n private updateLOD(): void {\n // Effective scale folds in the iso y-squash (smaller ⇒ seats read smaller),\n // so LOD/melt thresholds trip correctly in 3D view. Equals the raw stage\n // scale at isoT=0 → flat behaviour is unchanged.\n const scale = this.effScale();\n const focalScale = Math.max(scale, 0.0001);\n for (const [label, targetPx] of this.primaryFocalLabels) {\n this.sizeLabel(label, targetPx / focalScale, label.y());\n }\n if (this.hasSections) this.applySectionLod(scale);\n else if (this.primaryFocalLabels.size) this.bgLayer.batchDraw();\n this.paintGAStateForView();\n const shouldCache = scale < CACHE_THRESHOLD;\n if (shouldCache && !this.cached) {\n this.cacheSeatLayer();\n } else if (!shouldCache && this.cached) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the\n * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */\n private rebuildSeatCache(): void {\n // Cache at ~screen resolution: bitmap px ≈ on-screen px, so a huge chart in\n // chart-units doesn't blow up into a gigapixel canvas when zoomed out.\n const pr = clamp(this.stage.scaleX() * this.dpr, 0.15, 2);\n this.seatLayer.clearCache();\n this.seatLayer.cache({ pixelRatio: pr });\n this.seatLayer.listening(false);\n this.cached = true;\n }\n\n private cacheSeatLayer(): void {\n this.rebuildSeatCache();\n this.seatLayer.batchDraw();\n }\n\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the\n * ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore\n * Konva's batchDraw) on hidden/backgrounded/occluded tabs, so seat-status\n * deltas applied via setStatus() mutate the scene graph but never reach the\n * canvas until the tab is foregrounded. This flushes the cache-debounce and\n * paints every layer setStatus() can touch, immediately.\n *\n * Additive: the foreground path never calls this, so foreground behaviour is\n * byte-identical.\n */\n forceDraw(): void {\n // Flush any pending cache-debounce (setStatus coalesces bursts behind a\n // 150ms setTimeout) so a returning tab isn't left showing a stale bitmap.\n if (this.recacheTimer) {\n clearTimeout(this.recacheTimer);\n this.recacheTimer = null;\n // Fold coalesced deltas into a bitmap only if the CURRENT camera is still\n // on the cached overview rung. A status update can queue this timer and a\n // subsequent detail zoom can uncache the layer before forceDraw(); blindly\n // rebuilding here would disable pointer listening on live detail seats.\n if (this.effScale() < CACHE_THRESHOLD) {\n this.rebuildSeatCache();\n } else if (this.cached) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n }\n }\n // Synchronous paint of every layer setStatus() may repaint. Layer.draw()\n // renders on the calling thread, unlike batchDraw()'s rAF schedule.\n this.bgLayer.draw();\n this.seatLayer.draw();\n this.overlayLayer.draw();\n }\n\n private updateFreeTextVisibility(): void {\n const effectiveScale = this.effScale();\n for (const { objectId, node, categoryKey, kind } of this.freeTextById.values()) {\n const gaDimmed = categoryKey != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaCategoryDimmed(categoryKey);\n const gaOverviewHidden = objectId != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaById.get(objectId)?.sectionId != null\n && effectiveScale < CACHE_THRESHOLD;\n node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));\n }\n }\n\n private updateLabels(): void {\n const effectiveScale = this.effScale();\n const show = effectiveScale >= LABEL_SCALE;\n for (const [id, label] of this.boothLabelById) {\n const shape = this.circleById.get(id);\n label.visible(\n isBookableLabelLegibleAtScale(label.fontSize(), effectiveScale)\n && (shape?.opacity() ?? 1) >= 0.5,\n );\n }\n this.labelGroup.destroyChildren();\n this.seatLabelById.clear();\n if (!show) {\n this.overlayLayer.batchDraw();\n return;\n }\n // Visible chart rect (with a small margin) in chart coordinates.\n const s = this.stage.scaleX();\n const x0 = (-this.stage.x()) / s;\n const y0 = (-this.stage.y()) / s;\n const x1 = (this.stage.width() - this.stage.x()) / s;\n const y1 = (this.stage.height() - this.stage.y()) / s;\n\n let count = 0;\n for (const seat of this.seats) {\n // Booth labels already live beside their rectangular shape in seatLayer\n // (renderBoothUnit). Adding them again to the zoom-only overlay produces\n // the offset/doubled numbers visible at close zoom levels.\n if (seat.kind === 'booth') continue;\n if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;\n const shape = this.circleById.get(seat.id);\n if ((shape?.opacity() ?? 1) < 0.5) continue;\n const status = this.statusById.get(seat.id) ?? 'free';\n // Buyers see another buyer's hold as an unavailable lock, without its\n // inventory label. Organizers in manage mode retain the held unit's\n // identity so they can inspect or release it from the control room.\n const unavailable = status === 'booked'\n || (status === 'held' && !this.ownedHold.has(seat.id) && !this.opts.manageMode);\n if (unavailable) {\n // Status is geometry, not a letter: a centred lock for a temporary hold\n // and one quiet diagonal mark for sold. This stays aligned at every\n // zoom level and does not ask buyers to decode \"H\" or a large × glyph.\n const cue = new Group({ x: seat.x, y: seat.y, listening: false });\n if (status === 'held') {\n cue.add(new Rect({\n x: -4.2, y: -0.7, width: 8.4, height: 6.5, cornerRadius: 1.3,\n stroke: '#ffffff', strokeWidth: 1.25, listening: false,\n }));\n cue.add(new Line({\n points: [-2.4, -0.8, -2.4, -2.7, -1.2, -4, 0, -4.35, 1.2, -4, 2.4, -2.7, 2.4, -0.8],\n stroke: '#ffffff', strokeWidth: 1.2, lineCap: 'round', lineJoin: 'round', listening: false,\n }));\n } else {\n cue.add(new Line({\n points: [-4.2, 4.2, 4.2, -4.2], stroke: '#ffffff', strokeWidth: 1.8,\n lineCap: 'round', listening: false,\n }));\n }\n this.labelGroup.add(cue);\n if (++count >= MAX_LABELS) break;\n continue;\n }\n // Authored per-seat size scales the neutral default BEFORE auto-fit, so\n // the fit/shrink/legibility logic below still runs on top of it.\n const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const t = new Text({\n x: seat.x,\n y: seat.y,\n text: bookableMarkerLabel(seat.displayLabel ?? seat.label),\n fontSize: authoredFontSize,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n fill: shape ? this.seatLabelInk(seat, shape) : this.seatPreferredLabelInk(seat),\n listening: false,\n perfectDrawEnabled: false,\n });\n // Auto-fit: shrink long labels (e.g. \"T10-10\") so they never spill out of\n // the seat circle. Down to a legibility floor; below that the label is\n // dropped rather than rendered as an unreadable speck.\n const maxW = this.seatR * 2 - 3;\n if (t.width() > maxW) t.fontSize(Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, (authoredFontSize * maxW) / t.width()));\n // The minimum fitted font can still be wider than the physical marker\n // for verbose row labels. Never let text spill across adjacent seats;\n // keep the seat interactive and let the picker/tooltip expose its label.\n if (t.width() > maxW + 0.01) { t.destroy(); continue; }\n if (!isBookableLabelLegibleAtScale(t.fontSize(), effectiveScale)) { t.destroy(); continue; }\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n this.labelGroup.add(t);\n this.seatLabelById.set(seat.id, t);\n if (++count >= MAX_LABELS) break;\n }\n // Keep freshly-built seat labels upright under the iso layer skew.\n if (this.isoT > 0) this.applyUprightLabels();\n this.overlayLayer.batchDraw();\n }\n\n private handleResize(): void {\n const w = this.container.clientWidth || 1;\n const h = this.container.clientHeight || 1;\n if (w === this.stage.width() && h === this.stage.height()) return;\n this.stage.size({ width: w, height: h });\n // Keep the chart framed; refit is the least surprising behaviour on resize.\n this.zoomToFit();\n }\n\n private startFpsLoop(): void {\n const tick = (now: number) => {\n if (!this.lastFpsAt) this.lastFpsAt = now;\n this.frames++;\n const elapsed = now - this.lastFpsAt;\n if (elapsed >= 1000) {\n this.opts.onFps?.(Math.round((this.frames * 1000) / elapsed));\n this.frames = 0;\n this.lastFpsAt = now;\n }\n this.rafId = requestAnimationFrame(tick);\n };\n this.rafId = requestAnimationFrame(tick);\n }\n}\n\nexport function createRenderer(container: HTMLDivElement, opts?: RendererOptions): ISeatmapRenderer {\n return new SeatmapRenderer(container, opts);\n}\n","/**\n * Rendering constants that quality inspection must agree with.\n *\n * Keep these in core rather than inside the Konva renderer so headless catalog,\n * API, and MCP checks can evaluate the text that the buyer/designer will see.\n */\n\n/** Seat and table-seat labels are authored at this many chart units. */\nexport const SEAT_LABEL_FONT_SIZE = 7;\n\n/** Booth labels are authored at this many chart units. */\nexport const BOOTH_LABEL_FONT_SIZE = 10;\n\n/** GA area captions and their capacity sublabels. */\nexport const GA_LABEL_FONT_SIZE = 15;\nexport const GA_CAPACITY_LABEL_FONT_SIZE = 11;\n\n/**\n * GA category paint remains slightly translucent, but must still separate from\n * both supported canvas surfaces by the shared 3:1 graphical-object floor.\n */\nexport const GA_FILL_OPACITY = 0.85;\n\n/**\n * Small labels below this rendered CSS-pixel size are hidden by LOD instead of\n * being painted as unreadable specks.\n */\nexport const MIN_VISIBLE_BOOKABLE_LABEL_PX = 12;\n\n/** WCAG contrast for normal/small text. */\nexport const SMALL_TEXT_CONTRAST = 4.5;\n\n/** WCAG contrast for genuinely large text. */\nexport const LARGE_TEXT_CONTRAST = 3;\n\n/** Dark/light label candidates used only when a transient rendered state\n * changes the authored category fill (selected, held, unavailable, and so on). */\nexport const DARK_BOOKABLE_LABEL_INK = '#000000';\nexport const LIGHT_BOOKABLE_LABEL_INK = '#ffffff';\n\n/** 18pt normal text and 14pt bold text expressed as CSS pixels. */\nconst LARGE_NORMAL_TEXT_PX = 24;\nconst LARGE_BOLD_TEXT_PX = 18.67;\n\nexport function minimumTextContrast(renderedFontPx: number, fontWeight = 400): number {\n const isLarge = renderedFontPx >= LARGE_NORMAL_TEXT_PX\n || (fontWeight >= 700 && renderedFontPx >= LARGE_BOLD_TEXT_PX);\n return isLarge ? LARGE_TEXT_CONTRAST : SMALL_TEXT_CONTRAST;\n}\n\nexport function isBookableLabelLegibleAtScale(fontSize: number, effectiveScale: number): boolean {\n return fontSize * effectiveScale >= MIN_VISIBLE_BOOKABLE_LABEL_PX;\n}\n\n/**\n * Keep the public seat label as the inventory identity while rendering only\n * its terminal seat number inside the physical marker. Generated row seats use\n * `<row label>-<number>`; a custom label without that suffix remains unchanged.\n */\nexport function bookableMarkerLabel(publicLabel: string): string {\n return /-(\\d{1,5})$/.exec(publicLabel)?.[1] ?? publicLabel;\n}\n\nfunction luminance(value: string): number | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const channel = (offset: number) => {\n const encoded = Number.parseInt(match[1].slice(offset, offset + 2), 16) / 255;\n return encoded <= 0.04045 ? encoded / 12.92 : ((encoded + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4);\n}\n\n/** WCAG contrast for the actual opaque hex paints used by bookable labels. */\nexport function renderedTextContrast(ink: string, fill: string): number | null {\n const inkLuminance = luminance(ink);\n const fillLuminance = luminance(fill);\n if (inkLuminance == null || fillLuminance == null) return null;\n return (Math.max(inkLuminance, fillLuminance) + 0.05)\n / (Math.min(inkLuminance, fillLuminance) + 0.05);\n}\n\nfunction rgb(value: string): [number, number, number] | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const packed = Number.parseInt(match[1], 16);\n return [(packed >> 16) & 255, (packed >> 8) & 255, packed & 255];\n}\n\n/**\n * Resolve the opaque pixel under text painted over a translucent category\n * shape. Quality evidence must compare against this composite—not the raw\n * category colour or the canvas alone.\n */\nexport function compositeHexOver(\n foreground: string,\n background: string,\n opacity: number,\n): string {\n const front = rgb(foreground);\n const back = rgb(background);\n if (!front || !back) return background;\n const alpha = Math.max(0, Math.min(1, opacity));\n const channels = front.map((value, index) => Math.round(value * alpha + back[index] * (1 - alpha)));\n return `#${channels.map((value) => value.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Bookable fills can vary per category and per transient state, while a chart\n * exposes only one preferred label token. Preserve that preference whenever it\n * passes, then deterministically choose the strongest normal-text candidate.\n */\nexport function stateAwareBookableLabelInk(fill: string, preferred: string): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= SMALL_TEXT_CONTRAST) return preferred;\n const darkContrast = renderedTextContrast(DARK_BOOKABLE_LABEL_INK, fill) ?? 0;\n const lightContrast = renderedTextContrast(LIGHT_BOOKABLE_LABEL_INK, fill) ?? 0;\n if (darkContrast === 0 && lightContrast === 0) return preferred;\n return darkContrast >= lightContrast ? DARK_BOOKABLE_LABEL_INK : LIGHT_BOOKABLE_LABEL_INK;\n}\n\nconst OPAQUE_HEX = /^#[0-9a-f]{6}$/i;\n\n/** Is a solid hex fill light enough to read as a light surface? Feedback helpers\n * use this to pick the neutral section shell a label sits on. */\nexport function isLightFill(fill: string): boolean {\n const value = luminance(fill);\n return value != null && value > 0.5;\n}\n\n/**\n * Neutral section shell fills the renderer paints when a section has no custom\n * colour, mirrored here so contrast feedback can evaluate uncoloured sections.\n */\nexport const LIGHT_NEUTRAL_SECTION_FILL = '#e5e7eb';\nexport const DARK_NEUTRAL_SECTION_FILL = '#273142';\nexport function neutralSectionFill(canvasBackground: string): string {\n return isLightFill(canvasBackground) ? LIGHT_NEUTRAL_SECTION_FILL : DARK_NEUTRAL_SECTION_FILL;\n}\n\nexport interface LabelInkContrastSummary {\n /** Backgrounds that could be evaluated (valid preferred + valid fill hex). */\n total: number;\n /** Backgrounds where the preferred ink is auto-swapped for legibility. */\n overridden: number;\n /** `applies` = preferred survives everywhere; `overridden` = swapped\n * everywhere; `mixed` = some of each; `none` = nothing evaluable. */\n status: 'applies' | 'overridden' | 'mixed' | 'none';\n /** Fallback ink chosen where the preferred was overridden (black/white), or\n * null when nothing was overridden — names the swap in user-facing copy. */\n overrideInk: string | null;\n}\n\n/**\n * Feedback-only companion to {@link stateAwareBookableLabelInk}: does a preferred\n * label ink survive across a set of backgrounds, or does the shared auto-contrast\n * rule silently swap it for black/white on some of them? Reuses the exact same\n * per-fill decision so a report can never disagree with what the renderer paints.\n */\nexport function summarizeLabelInkContrast(\n preferred: string,\n backgrounds: Iterable<string>,\n): LabelInkContrastSummary {\n const preferredValid = OPAQUE_HEX.test(preferred.trim());\n const preferredHex = preferred.trim().toLowerCase();\n let total = 0;\n let overridden = 0;\n let overrideInk: string | null = null;\n for (const fill of backgrounds) {\n if (!preferredValid || !OPAQUE_HEX.test(fill.trim())) continue;\n total += 1;\n const ink = stateAwareBookableLabelInk(fill, preferred);\n if (ink.toLowerCase() !== preferredHex) {\n overridden += 1;\n overrideInk = ink;\n }\n }\n const status = total === 0 ? 'none'\n : overridden === 0 ? 'applies'\n : overridden === total ? 'overridden'\n : 'mixed';\n return { total, overridden, status, overrideInk };\n}\n","/**\n * Money formatting — the ONE place currency rendering happens.\n *\n * Ticket money is multi-currency: the org sets a default and each event can\n * override it (ISO 4217 code delivered with the event/chart payload). Until\n * those backend fields land, callers fall back to DEFAULT_CURRENCY, which is\n * kept at EUR so live buyer pages render exactly what they rendered when the\n * symbol was hardcoded. Flipping an org to USD/INR/… later is data, not code.\n *\n * Amounts are in MAJOR units (45 === €45) matching Category.price in\n * src/core/types.ts. If/when backend money fields arrive in minor units,\n * convert at the API boundary, not here.\n */\n\n// App-wide fallback when no org currency is available (unauthed/demo surfaces).\n// Owner decision 2026-07-08: USD default (orgs.currency also defaults to USD).\nexport const DEFAULT_CURRENCY = 'USD';\n\n/** BCP 47 locale used for number/date rendering; kept in sync by src/i18n. */\nlet displayLocale: string | undefined;\n\nexport function setMoneyLocale(locale: string | undefined): void {\n displayLocale = locale;\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction formatter(currency: string, digits: number | undefined): Intl.NumberFormat {\n const key = `${displayLocale ?? ''}|${currency}|${digits ?? 'auto'}`;\n let fmt = formatterCache.get(key);\n if (!fmt) {\n fmt = new Intl.NumberFormat(displayLocale, {\n style: 'currency',\n currency,\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n formatterCache.set(key, fmt);\n }\n return fmt;\n}\n\n/**\n * \"€45\" / \"$1,500\" / \"45 €\" (locale-dependent placement).\n * Whole amounts render without \".00\" (design shows \"$45\", \"$120\"); pass\n * `fractionDigits` for fixed precision (e.g. 3 for \"$0.045 / credit\").\n */\nexport function formatMoney(\n amount: number,\n currency: string = DEFAULT_CURRENCY,\n fractionDigits?: number,\n): string {\n const digits = fractionDigits ?? (Number.isInteger(amount) ? 0 : undefined);\n return formatter(currency, digits).format(amount);\n}\n\n/** Bare symbol for input adornments (\"€\", \"$\", \"₹\"). */\nexport function currencySymbol(currency: string = DEFAULT_CURRENCY): string {\n const part = formatter(currency, 0)\n .formatToParts(0)\n .find((p) => p.type === 'currency');\n return part?.value ?? currency;\n}\n","/**\n * English bundle — the reference dictionary every other locale is checked\n * against. Keys are added as pages route their strings through t() during\n * the design port (docs/design-port-plan.md); buyer-surface keys land first.\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const en: Dict = {\n // shared\n 'common.cancel': 'Cancel',\n 'common.close': 'Close',\n 'common.done': 'Done',\n 'common.copied': '✓ Copied',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Hold seats & checkout',\n 'picker.completeBooking': 'Complete booking',\n 'picker.seatsHeld': 'Seats held — {time}',\n 'picker.holdExpired': 'Your hold expired — the seats were released. Pick again.',\n 'picker.seatTaken': 'Seat {label} was just taken by another buyer.',\n 'picker.poweredBy': 'Powered by SeatLayer',\n 'picker.testMode': 'TEST MODE',\n 'picker.colorblind': 'Colorblind-friendly colors',\n 'picker.orphanHint': 'This leaves a single seat stranded — consider shifting one seat over.',\n 'picker.seats.one': '{count} seat',\n 'picker.seats.other': '{count} seats',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Seating map. Use arrow keys to move between seats, Enter to select.',\n 'map.seatsLeft': '{count} LEFT',\n 'map.fromPrice': 'FROM {price}',\n 'map.statusHeld': 'On hold',\n 'map.statusTaken': 'Taken',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Language',\n 'picker.zoomToFit': 'Zoom to fit',\n 'picker.seatCountLabel': 'seats',\n 'picker.capacity': 'capacity',\n 'picker.viewMode': 'View mode',\n 'picker.floor': 'Floor',\n 'picker.zoomLevel': 'Zoom level',\n 'picker.rungTip.zones': 'Venue overview — groups of sections such as North Stand or VIP',\n 'picker.rungTip.sections': 'Section blocks — category-mix fill + availability tint',\n 'picker.rungTip.seats': 'Individual seats — blocks melt into dots',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SEATS',\n 'picker.sectionSummaryAria': '{label} section summary',\n 'picker.closeSectionSummary': 'Close section summary',\n 'picker.seatsLeftInSection.one': '{count} seat left',\n 'picker.seatsLeftInSection.other': '{count} seats left',\n 'picker.overview': 'Overview',\n 'picker.tapSeatHint': 'Tap any seat to check its view',\n 'picker.chartSize': 'Chart size',\n 'picker.custom': 'Custom',\n 'picker.categories': 'Categories',\n 'picker.accessibility': 'Accessibility',\n 'picker.showAnyAccessible': 'Show any accessible seat',\n 'picker.any': 'Any',\n 'picker.yourSeats': 'Your seats',\n 'picker.emptySeats': 'Tap seats on the map',\n 'picker.emptySeatsWithGa': 'Tap seats on the map · tap a standing area for GA tickets',\n 'picker.oneFewer': 'One fewer',\n 'picker.oneMore': 'One more',\n 'picker.remove': 'Remove {label}',\n 'picker.ticketTierFor': 'Ticket tier for {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'View from seat {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'PREVIEW',\n 'picker.open360': 'Open 360° view',\n 'picker.sightline': '≈ {m} m to stage · clear sightline',\n 'picker.bookedDemo': 'Booked! (demo)',\n 'picker.bookButton.one': 'Book {count} ticket — {amount}',\n 'picker.bookButton.other': 'Book {count} tickets — {amount}',\n 'picker.simulateCrowd': 'Simulate crowd: {state}',\n 'picker.on': 'ON',\n 'picker.off': 'OFF',\n 'picker.panorama360': '360° venue photo',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m from stage',\n};\n","/**\n * i18n core — deliberately tiny and framework-free so the embed SDK can share\n * it without dragging in a runtime library (the 60KB-gzipped SDK budget is a\n * product contract).\n *\n * Scope (docs/design-port-plan.md): the buyer surface (picker, public event\n * page, SDK) ships fully translated in en/es/de/fr; dashboard pages route\n * their strings through t() as they are rebuilt but ship English this round.\n *\n * Keys are flat dot-namespaced strings (\"picker.holdSeats\"). Interpolation\n * uses {name} placeholders. Missing keys fall back to English, then to the\n * key itself — a page never crashes over a translation.\n */\n\nimport { setMoneyLocale } from '../lib/money';\nimport { en } from './locales/en';\n\nexport type Locale = 'en' | 'es' | 'de' | 'fr';\nexport const SUPPORTED_LOCALES: Locale[] = ['en', 'es', 'de', 'fr'];\n\nexport type Dict = Record<string, string>;\n\nconst bundles: Partial<Record<Locale, Dict>> = { en };\n\n/** Extra strings layered over the active bundle (SDK white-label overrides). */\nlet overrides: Dict = {};\n\nlet active: Locale = 'en';\n\n/** explicit setting → stored preference → browser language → en */\nexport function resolveLocale(explicit?: string | null, stored?: string | null): Locale {\n for (const candidate of [explicit, stored, typeof navigator !== 'undefined' ? navigator.language : null]) {\n if (!candidate) continue;\n const base = candidate.toLowerCase().split('-')[0] as Locale;\n if (SUPPORTED_LOCALES.includes(base)) return base;\n }\n return 'en';\n}\n\nexport function getLocale(): Locale {\n return active;\n}\n\n/**\n * Set the active locale. Locale bundles other than English are registered by\n * the surface that needs them (the picker imports its own es/de/fr bundles;\n * the dashboard stays English until its translations ship).\n */\nexport function setLocale(locale: Locale, bundle?: Dict): void {\n if (bundle) bundles[locale] = { ...bundles[locale], ...bundle };\n active = bundles[locale] ? locale : 'en';\n setMoneyLocale(active);\n if (typeof document !== 'undefined') document.documentElement.lang = active;\n}\n\nexport function setStringOverrides(next: Dict): void {\n overrides = next;\n}\n\nconst PLACEHOLDER = /\\{(\\w+)\\}/g;\n\nexport function t(key: string, vars?: Record<string, string | number>): string {\n const raw = overrides[key] ?? bundles[active]?.[key] ?? en[key] ?? key;\n if (!vars) return raw;\n return raw.replace(PLACEHOLDER, (_, name: string) => String(vars[name] ?? `{${name}}`));\n}\n\n/** \"1 seat\" / \"3 seats\" without hand-rolled concatenation. */\nexport function tCount(key: string, count: number, vars?: Record<string, string | number>): string {\n const rule = new Intl.PluralRules(active).select(count);\n const exact = overrides[`${key}.${rule}`] ?? bundles[active]?.[`${key}.${rule}`] ?? en[`${key}.${rule}`];\n const raw = exact ?? overrides[`${key}.other`] ?? bundles[active]?.[`${key}.other`] ?? en[`${key}.other`] ?? key;\n return raw.replace(PLACEHOLDER, (_, name: string) => String({ count, ...vars }[name] ?? `{${name}}`));\n}\n\nexport function formatDate(value: number | Date, opts?: Intl.DateTimeFormatOptions): string {\n return new Intl.DateTimeFormat(active, opts ?? { dateStyle: 'medium', timeStyle: 'short' }).format(value);\n}\n","/**\n * Orphan-seat detection for MANUAL selection — the client-side sibling of the\n * server's best-available orphan avoidance (workers/api/src/bestAvailable):\n * a \"stranded single\" is a free seat whose both same-row neighbors are\n * unavailable (non-free or currently selected). The picker uses this to show\n * a non-blocking hint; nothing is ever prevented.\n */\nimport type { ExpandedSeat, SeatStatus } from './types';\n\n/** Numeric seat index from the stable id (`${rowId}:${index}`). */\nfunction seatIndex(id: string): number {\n const n = Number(id.slice(id.lastIndexOf(':') + 1));\n return Number.isFinite(n) ? n : -1;\n}\n\n/**\n * Free seats stranded by the current selection: both same-row neighbors exist\n * and are unavailable, and at least one neighbor is part of `selectedIds` —\n * so pre-existing single gaps (caused by earlier buyers) never nag.\n * Booth units are ignored (no row adjacency).\n */\nexport function strandedSingles(\n seats: Iterable<ExpandedSeat>,\n statusOf: (seatId: string) => SeatStatus,\n selectedIds: ReadonlySet<string>,\n): ExpandedSeat[] {\n // Group by row, ordered by index, skipping booths.\n const rows = new Map<string, ExpandedSeat[]>();\n for (const s of seats) {\n if (s.kind === 'booth') continue;\n const list = rows.get(s.rowId);\n if (list) list.push(s);\n else rows.set(s.rowId, [s]);\n }\n\n const unavailable = (s: ExpandedSeat): boolean =>\n selectedIds.has(s.id) || statusOf(s.id) !== 'free';\n\n const out: ExpandedSeat[] = [];\n for (const list of rows.values()) {\n if (list.length < 3) continue;\n list.sort((a, b) => seatIndex(a.id) - seatIndex(b.id));\n for (let i = 1; i < list.length - 1; i++) {\n const seat = list[i];\n if (unavailable(seat)) continue; // not free (or selected) → not stranded\n const left = list[i - 1];\n const right = list[i + 1];\n // Neighbors must be physically adjacent (index gap of 1) — a labelled\n // aisle gap in the numbering doesn't strand anyone.\n if (seatIndex(seat.id) - seatIndex(left.id) !== 1 || seatIndex(right.id) - seatIndex(seat.id) !== 1) continue;\n if (!unavailable(left) || !unavailable(right)) continue;\n if (!selectedIds.has(left.id) && !selectedIds.has(right.id)) continue;\n out.push(seat);\n }\n }\n return out;\n}\n","/**\n * PickerController — the single, framework-agnostic buyer-picker core.\n *\n * Consolidates the transport + booking logic that was copy-pasted across\n * sdk/src/SeatingChart.ts, src/pages/PublicEventPage.tsx and PickerPage.tsx:\n * fetch the published chart, mount the Konva renderer, seed statuses from a REST\n * snapshot, keep them live over a WebSocket (reconnect w/ backoff, re-snapshot on\n * every open), and run the hold → book state machine (best-available, hold reuse,\n * per-label partial release, 409 semantics, server-authoritative hold expiry).\n *\n * The SDK, the live buyer page, and the demo picker all drive this one class;\n * presentation (confirm card, legend, cart, etc.) lives in the consumers.\n *\n * Transport is injected (PickerTransport) so the SDK can use its CORS-trivial\n * PubApi while the dashboard uses an adapter over src/lib/api.ts.\n */\nimport { createRenderer } from '../engine/SeatmapRenderer';\nimport { allObjects, expandChart } from '../core/layout';\nimport { applyHidden, computeSections } from '../core/sections';\nimport { strandedSingles } from '../core/orphans';\nimport { t } from '../i18n';\nimport type {\n CategoryTier,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n RendererCallbacks,\n SeatStatus,\n SectionObject,\n} from '../core/types';\nimport { gaAreasOf, gaUnitLabels } from '../core/ga';\n\nconst DEFAULT_MAX_SELECTION = 10;\nconst MAX_BACKOFF_MS = 15_000;\n\nexport interface PickerSeat {\n id: string;\n label: string;\n categoryKey: string;\n /** Price for the chosen tier when the category has tiers, else the base price. */\n price: number;\n /** Ticket tiers the seat's category offers (Adult/Child/…); absent when none. */\n tiers?: CategoryTier[];\n /** The chosen tier's id — defaults to the first tier; absent when no tiers. */\n tierId?: string;\n}\n\n/**\n * Rich hover payload for seat tooltips — the PickerSeat plus everything a\n * buyer-facing popover needs: category label + swatch color, live status and\n * the chart currency. Emitted by `onSeatHover` (null on hover-out).\n */\nexport interface SeatHoverDetails extends PickerSeat {\n categoryLabel: string;\n categoryColor: string;\n status: SeatStatus;\n currency: string;\n /** Human-readable spatial context for hover and confirmation UI. */\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: string;\n}\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\n/** An open hold — its id, the labels it covers, and the server's expiry time (ms epoch). */\nexport interface HoldInfo {\n holdId: string;\n labels: string[];\n expiresAt: number;\n /** The held seats with their chosen ticket tier — what the host books against. */\n seats: PickerSeat[];\n /** Server-authoritative commercial line items, including GA units and resolved prices. */\n items?: HoldServerItem[];\n}\n\n/** One category's slice of a section (dot + price + count) for the summary card. */\nexport interface SectionCategory {\n key: string;\n label: string;\n color: string;\n price: number;\n count: number;\n}\n\n/**\n * Big-venue section-summary — everything the tapped-section card renders: name,\n * its zone, live seats-left, price range, and the per-category breakdown.\n * Computed from the renderer's spatial section membership (Slice 5).\n */\nexport interface SectionSummary {\n id: string;\n label: string;\n /** Zone label (from ChartDoc.zones); '' when the section has no zone. */\n zoneLabel: string;\n /** Mix/section colour for the card's dot (section.color → zone colour → dominant category). */\n color: string;\n /** Free member seats right now. */\n seatsLeft: number;\n priceMin: number;\n priceMax: number;\n /** Per-category breakdown, cheapest first. */\n categories: SectionCategory[];\n}\n\ninterface HoldResponse {\n holdId: string;\n expiresAt: number;\n items?: HoldServerItem[];\n}\ninterface ResumeHoldResponse extends HoldResponse {\n items: HoldServerItem[];\n}\nexport interface HoldServerItem {\n label: string;\n objectId: string;\n objectType: 'seat' | 'booth' | 'ga';\n categoryKey: string;\n tierId: string | null;\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\nexport interface HoldSelectionRequest { label: string; tierId?: string | null }\ninterface BestAvailableResponse extends HoldResponse {\n labels: string[];\n}\n\n/** Swappable public-surface transport (SDK PubApi or a dashboard `api.pub.*` adapter). */\nexport interface PickerTransport {\n chart(key: string): Promise<{\n doc: ChartDoc;\n event: { key: string; name: string; salesClosed?: boolean; venue?: string | null; startsAt?: number | null; currency?: string; mode?: string };\n }>;\n objects(key: string): Promise<{ seats: Record<string, string>; hidden?: string[]; closed?: string[] }>;\n hold(key: string, selections: HoldSelectionRequest[], ttlMs?: number, replaceHoldId?: string): Promise<HoldResponse>;\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResponse>;\n release(key: string, labels: string[], holdId: string): Promise<unknown>;\n /** Optional capability-style lookup used to restore an active browser hold. */\n resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;\n /** Optional — the SDK omits booking (it hands the holdId to the host page). */\n book?(key: string, labels: string[], holdId: string, bookingRef: string): Promise<unknown>;\n /** Optional (P4) — push an active hold's expiry out (\"need more time?\"). */\n extend?(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends?: number }>;\n socketUrl(key: string): string;\n}\n\nexport interface PickerCallbacks extends RendererCallbacks {\n /** Selection changed (manual clicks or a server best-available pick). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /** A hold opened (manual hold or best-available). */\n onHold?: (hold: HoldInfo) => void;\n /** A prior active hold was restored from its opaque hold id. */\n onHoldRestored?: (hold: HoldInfo) => void;\n /** The open hold expired server-side (the controller has already released it). */\n onHoldExpired?: () => void;\n /** A booking completed with this ref. */\n onBook?: (bookingRef: string) => void;\n /** Any live seat-status change arrived (delta or snapshot) — e.g. to recount \"N left\". */\n onStatusChange?: () => void;\n /**\n * Mouse hover moved onto a seat (null on hover-out) — the seat enriched with\n * category label/color, resolved price and live status, ready for a tooltip.\n * Fires alongside the raw renderer-level `onHover`.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n /** The server declared the event closed (a 409 event_closed). */\n onSalesClosed?: () => void;\n /**\n * A section block was tapped at the far/zone rung — the controller has glided\n * the camera in and passes the computed summary (or null when cleared, e.g.\n * overview() / zoom-to-zones) so the host can show/hide the summary card.\n */\n onSectionFocus?: (summary: SectionSummary | null) => void;\n /** A deck was tapped in the 3D all-floors overview — host enters that floor in 2D. */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking selection advice (localized): currently the orphan-seat hint —\n * the selection would strand a single free seat between unavailable\n * neighbors. `null` clears a previously shown hint. Never prevents anything.\n */\n onHint?: (message: string | null) => void;\n onError?: (err: unknown) => void;\n}\n\nexport interface PickerOptions extends PickerCallbacks {\n transport: PickerTransport;\n eventKey: string;\n maxSelection?: number;\n /** Renderer confirm-card mode (host shows a confirm popover instead of instant cart add). */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (default from money.DEFAULT_CURRENCY). */\n currency?: string;\n /** Flash a pulse when a seat we didn't touch goes free→taken (live-activity cue). */\n flashOnLiveChange?: boolean;\n /** Start in colorblind-safe rendering (Okabe-Ito hues + hollow booked seats). */\n colorblindSafe?: boolean;\n /**\n * Keep painting seat-status deltas even while the tab is hidden/backgrounded.\n *\n * Default FALSE — the buyer widget stays efficient: it lets rAF stay paused\n * while hidden and does a single synchronous catch-up repaint on regain (the\n * visibilitychange handler resnapshots + forceDraw()s). Set TRUE only for an\n * always-live surface — the future organizer control-room board — where a\n * backgrounded monitor must keep repainting; then each delta calls\n * renderer.forceDraw() when the tab is hidden. Purely a paint hint; enforcement\n * and the WS protocol are identical either way.\n */\n keepLiveWhileHidden?: boolean;\n}\n\n/** Read `status`/`conflicts`/`reason` off any thrown error without importing a specific ApiError. */\nfunction errInfo(err: unknown): { status?: number; conflicts?: HoldConflict[]; reason?: string } {\n const e = (err ?? {}) as { status?: number; conflicts?: HoldConflict[]; reason?: string };\n return { status: e.status, conflicts: e.conflicts, reason: e.reason };\n}\n\n/** DO seat status → renderer status ('blocked' has no renderer analogue → 'not_for_sale'). */\nfunction mapStatus(s: string): SeatStatus {\n if (s === 'blocked') return 'not_for_sale';\n if (s === 'held' || s === 'booked' || s === 'free' || s === 'not_for_sale') return s;\n return 'free';\n}\n\nexport class PickerController {\n private readonly opts: PickerOptions;\n private readonly api: PickerTransport;\n private readonly key: string;\n private maxSelection: number;\n\n private renderer: ISeatmapRenderer | null = null;\n private _doc: ChartDoc | null = null;\n /** Section/zone ids hidden from buyers this event (3.3) — seats vanish, not grey. */\n private hidden = new Set<string>();\n /** Section/zone ids in the `closed` event-state (Phase 2) — seats stay, greyed\n * + not pickable. Kept separate from `hidden` (which strips them). */\n private closedSections = new Set<string>();\n\n /** label ⇄ id maps — backend speaks labels, the engine speaks ids. */\n private labelToId = new Map<string, string>();\n private labelToSeat = new Map<string, ExpandedSeat>();\n /** seatId → chosen ticket-tier id (absent ⇒ the category's first/default tier). */\n private seatTiers = new Map<string, string>();\n /** id → seat, for the section-summary breakdown (renderer members are ids). */\n private seatById = new Map<string, ExpandedSeat>();\n /** id → buyer-facing spatial metadata used by every tooltip/confirm surface. */\n private seatContext = new Map<string, { sectionLabel?: string; rowLabel?: string; seatNumber?: string }>();\n private allIds: string[] = [];\n\n // realtime socket\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private attempt = 0;\n private closed = false;\n /** Bound visibilitychange listener (buyer catch-up on tab regain). Kept on the\n * instance so destroy() can detach it; null when not attached (guards double\n * mounts / non-DOM environments). */\n private onVisibilityChange: (() => void) | null = null;\n\n // hold state\n private hold_: HoldInfo | null = null;\n private liveStatuses = new Map<string, string>();\n private currency = 'USD';\n private expiryTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: PickerOptions) {\n this.opts = options;\n this.api = options.transport;\n this.key = options.eventKey;\n this.maxSelection = options.maxSelection ?? DEFAULT_MAX_SELECTION;\n }\n\n get doc(): ChartDoc | null {\n return this._doc;\n }\n\n /** The chart with hidden sections' seats removed — what buyers actually see. */\n private visibleDoc(): ChartDoc {\n return this._doc ? applyHidden(this._doc, this.hidden) : ({ objects: [] } as unknown as ChartDoc);\n }\n\n /** Adopt a new hidden set; rebuild the visible chart only if it differs. */\n private syncHidden(ids: string[]): boolean {\n const next = ids.filter((x): x is string => typeof x === 'string');\n if (next.length === this.hidden.size && next.every((id) => this.hidden.has(id))) return false;\n this.hidden = new Set(next);\n this.renderer?.setChart(this.visibleDoc());\n return true;\n }\n\n /** Adopt a new closed-section set; restyle (grey + non-pickable) if it differs.\n * Cheap restyle — no chart rebuild — so mid-sale open/close repaints live. */\n private syncClosed(ids: string[] | undefined): boolean {\n const next = (ids ?? []).filter((x): x is string => typeof x === 'string');\n if (next.length === this.closedSections.size && next.every((id) => this.closedSections.has(id))) return false;\n this.closedSections = new Set(next);\n this.renderer?.setClosedSections?.(next);\n return true;\n }\n\n /** Whether a section is currently in the `closed` state (card must not open). */\n isSectionClosed(id: string): boolean {\n return this.closedSections.has(id);\n }\n currentHold(): HoldInfo | null {\n return this.hold_;\n }\n getRenderer(): ISeatmapRenderer | null {\n return this.renderer;\n }\n seatByLabel(label: string): ExpandedSeat | undefined {\n return this.labelToSeat.get(label);\n }\n idForLabel(label: string): string | undefined {\n return this.labelToId.get(label);\n }\n\n /** Fetch chart, build label maps, mount the renderer, seed statuses, go live. */\n async render(host: HTMLDivElement): Promise<{\n doc: ChartDoc;\n salesClosed: boolean;\n eventName: string;\n venue?: string | null;\n startsAt?: number | null;\n currency?: string;\n /** 'test' ⇒ sandbox event (hosts show a TEST MODE ribbon). */\n mode?: string;\n } | null> {\n if (this.renderer) return null; // already rendered — never mount twice on one controller\n this.closed = false;\n let res;\n try {\n res = await this.api.chart(this.key);\n } catch (err) {\n this.emitError(err);\n return null;\n }\n // destroy() may have run while the chart fetch was in flight (StrictMode\n // double-mount, or a fast key change) — bail before mounting anything.\n if (this.closed) return null;\n this._doc = res.doc;\n\n this.labelToId = new Map();\n this.labelToSeat = new Map();\n this.seatById = new Map();\n this.seatContext = new Map();\n this.allIds = [];\n const chartObjects = new Map(allObjects(res.doc).map((object) => [object.id, object] as const));\n const membership = computeSections(res.doc);\n const sectionLabels = new Map(\n [...membership.sections, ...(membership.ungrouped ? [membership.ungrouped] : [])].map((section) => [section.id, section.label] as const),\n );\n for (const s of expandChart(res.doc)) {\n this.labelToId.set(s.label, s.id);\n this.labelToSeat.set(s.label, s);\n this.seatById.set(s.id, s);\n this.allIds.push(s.id);\n const source = chartObjects.get(s.rowId);\n const sourceLabel = source && 'label' in source && typeof source.label === 'string' ? source.label : undefined;\n const rowLabel = s.kind === 'booth' ? undefined : sourceLabel;\n const labelParts = s.label.split('-');\n const seatNumber = rowLabel && s.label.startsWith(`${rowLabel}-`)\n ? s.label.slice(rowLabel.length + 1)\n : s.kind === 'booth'\n ? s.label\n : labelParts[labelParts.length - 1] ?? s.label;\n this.seatContext.set(s.id, {\n sectionLabel: sectionLabels.get(membership.objectToSection.get(s.rowId) ?? ''),\n rowLabel,\n seatNumber,\n });\n }\n\n // The organizer's currency travels with the chart payload; it wins over any\n // option passed at construction (the SDK host may not know it up front).\n const currency = res.event.currency ?? this.opts.currency;\n this.currency = currency ?? 'USD';\n const renderer = createRenderer(host, {\n maxSelection: this.maxSelection,\n confirmSelection: this.opts.confirmSelection,\n currency,\n onSelect: (seat) => {\n this.opts.onSelect?.(seat);\n this.emitSelectionChange();\n },\n onDeselect: (seat) => {\n this.opts.onDeselect?.(seat);\n this.emitSelectionChange();\n },\n onSelectionLimit: this.opts.onSelectionLimit,\n onHover: (seat) => {\n this.opts.onHover?.(seat);\n if (this.opts.onSeatHover) this.opts.onSeatHover(seat ? this.describeSeat(seat) : null);\n },\n onFocusSeat: this.opts.onFocusSeat,\n onViewChange: this.opts.onViewChange,\n onGAClick: this.opts.onGAClick,\n // Section tap at the far/zone rung → glide in + surface the summary card.\n onSectionTap: (id) => this.handleSectionTap(id),\n onDeckTap: (floorId) => this.handleDeckTap(floorId),\n onFps: this.opts.onFps,\n });\n if (this.closed) {\n renderer.destroy(); // destroyed during createRenderer — don't leak the stage\n return null;\n }\n this.renderer = renderer;\n\n // Pull live state (seat statuses + hidden section/zone ids) BEFORE the first\n // paint so hidden sections never flash in. Falls back to the raw chart if the\n // snapshot is briefly unavailable — the WS re-snapshot then reconciles.\n let seats: Record<string, string> | null = null;\n let closedIds: string[] = [];\n try {\n const objs = await this.api.objects(this.key);\n this.hidden = new Set(objs.hidden ?? []);\n closedIds = (objs.closed ?? []).filter((x): x is string => typeof x === 'string');\n seats = objs.seats;\n } catch {\n /* transient — connect()'s onopen re-snapshots */\n }\n if (this.closed) {\n renderer.destroy();\n this.renderer = null;\n return null;\n }\n renderer.setChart(this.visibleDoc());\n if (this.opts.colorblindSafe) renderer.setColorblindSafe?.(true);\n // Closed sections are applied AFTER setChart (which resets state) so their\n // grey + non-pickable treatment lands on the first paint, no flash.\n this.closedSections = new Set(closedIds);\n if (closedIds.length) renderer.setClosedSections?.(closedIds);\n if (seats) this.applySeatsMap(seats);\n this.attachVisibilityListener();\n this.connect();\n return {\n doc: res.doc,\n salesClosed: !!res.event.salesClosed,\n eventName: res.event.name,\n venue: res.event.venue,\n startsAt: res.event.startsAt,\n currency,\n // 'test' ⇒ sandbox event: hosts render a TEST MODE ribbon (Phase 11).\n mode: res.event.mode ?? 'live',\n };\n }\n\n // ---- selection ------------------------------------------------------------\n\n getSelection(): PickerSeat[] {\n if (!this.renderer) return [];\n return this.renderer.getSelection().map((s) => this.toSeat(s));\n }\n /** Enriched metadata for a seat confirmation card or tooltip. */\n seatDetails(seatId: string): SeatHoverDetails | null {\n const seat = this.seatById.get(seatId);\n return seat ? this.describeSeat(seat) : null;\n }\n clearSelection(): void {\n this.renderer?.clearSelection();\n this.emitSelectionChange();\n }\n deselect(ids: string[]): void {\n this.renderer?.deselect(ids);\n this.emitSelectionChange();\n }\n setMaxSelection(maxSelection: number): void {\n this.maxSelection = Math.max(0, Math.floor(maxSelection));\n this.renderer?.setMaxSelection?.(this.maxSelection);\n }\n select(ids: string[]): PickerSeat[] {\n const added = this.renderer?.select?.(ids) ?? [];\n if (added.length) this.emitSelectionChange();\n return added.map((seat) => this.toSeat(seat));\n }\n\n // ---- booking machine ------------------------------------------------------\n\n /**\n * Hold the current selection (or a given label set). The controller does the\n * renderer/hold side (409 → deselect + repaint the taken seats held) and then\n * re-throws so the caller can choose the banner copy. Returns null only when\n * there's nothing to hold.\n */\n async hold(labelsArg?: string[], ttlMs?: number): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n const labels = labelsArg ?? r.getSelection().map((s) => s.label);\n const existingGA = (this.hold_?.items ?? []).filter((item) => item.objectType === 'ga');\n const combinedLabels = [...new Set([...existingGA.map((item) => item.label), ...labels])];\n if (!combinedLabels.length) return null;\n\n // Reuse an existing hold that exactly covers this selection (re-holding 409s).\n if (this.hold_ && this.holdCovers(combinedLabels)) return this.hold_;\n try {\n const selections = combinedLabels.map((label) => {\n const ga = existingGA.find((item) => item.label === label);\n if (ga) return { label, tierId: ga.tierId };\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return { label, ...(resolved?.tierId ? { tierId: resolved.tierId } : {}) };\n });\n const result = await this.api.hold(this.key, selections, ttlMs, this.hold_?.holdId);\n this.setHold({ holdId: result.holdId, labels: combinedLabels, expiresAt: result.expiresAt, items: result.items });\n return this.hold_;\n } catch (err) {\n this.handle409Conflicts(err);\n throw err;\n }\n }\n\n /** Restore an active server hold without creating or extending inventory. */\n async resumeHold(holdId: string): Promise<HoldInfo | null> {\n if (this.closed || !holdId || !this.api.resume) return null;\n const result = await this.api.resume(this.key, holdId);\n if (this.closed) return null;\n const labels = [...new Set(result.items.map((item) => item.label))];\n if (!labels.length) return null;\n this.setHold(\n { holdId: result.holdId, labels, expiresAt: result.expiresAt, items: result.items },\n 'restored',\n );\n return this.hold_;\n }\n\n /**\n * P4 \"need more time?\": extend the OPEN hold's server-side expiry and re-arm\n * the client expiry timer to match (via setHold), so the controller doesn't\n * fire a false expiry and start polling. Returns the new hold, or null if\n * there's no open hold or the transport can't extend / the server refused\n * (hold gone, expired, or at its renewal cap). Never throws for the refusal\n * case — the caller decides the copy.\n */\n async extendHold(ttlMs?: number): Promise<HoldInfo | null> {\n const current = this.hold_;\n if (!current || !this.api.extend) return null;\n try {\n const result = await this.api.extend(this.key, current.holdId, ttlMs);\n if (this.hold_?.holdId !== current.holdId) return this.hold_; // superseded meanwhile\n // Keep the same labels/items — only the expiry moved. setHold re-arms the timer.\n this.setHold({ holdId: current.holdId, labels: current.labels, expiresAt: result.expiresAt, items: current.items });\n return this.hold_;\n } catch {\n return null;\n }\n }\n\n /** Public GA inventory derived from the live synthetic-unit status stream. */\n /**\n * Live seats-left per category key (status 'free' right now). Recompute on\n * onStatusChange — this is what a price panel's \"N left\" counters read.\n */\n categoryAvailability(): Record<string, number> {\n const out: Record<string, number> = {};\n const closedMembers = this.closedMemberIds();\n for (const [id, s] of this.seatById) {\n if (closedMembers.has(id)) continue; // closed sections aren't on sale\n if ((this.getStatus(id) ?? 'free') === 'free') {\n out[s.categoryKey] = (out[s.categoryKey] ?? 0) + 1;\n }\n }\n return out;\n }\n\n /** Seat ids belonging to a currently-closed section (excluded from counts). */\n private closedMemberIds(): Set<string> {\n const out = new Set<string>();\n const r = this.renderer;\n if (!r || !this.closedSections.size) return out;\n for (const id of this.closedSections) for (const sid of (r.sectionMembers?.(id) ?? [])) out.add(sid);\n return out;\n }\n\n getGAAreas(): { id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string; tiers?: CategoryTier[] }[] {\n const doc = this.visibleDoc();\n if (!doc) return [];\n return gaAreasOf(doc).map((area) => {\n const category = doc.categories.find((candidate) => candidate.key === area.categoryKey);\n return {\n id: area.id,\n label: area.label,\n capacity: Math.max(0, Math.floor(area.capacity)),\n available: gaUnitLabels(area).filter((label) => (this.liveStatuses.get(label) ?? 'free') === 'free').length,\n categoryKey: area.categoryKey,\n tiers: category?.tiers,\n price: category?.tiers?.[0]?.price ?? category?.price ?? 0,\n currency: this.currency,\n };\n });\n }\n\n /** Select a quantity from one GA area and hold it atomically. */\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldInfo | null> {\n const doc = this.visibleDoc();\n if (!doc || !Number.isFinite(qty) || qty < 1) return null;\n const area = gaAreasOf(doc).find((candidate) => candidate.id === areaId);\n if (!area) return null;\n const labels = gaUnitLabels(area)\n .filter((label) => !this.hold_?.labels.includes(label) && (this.liveStatuses.get(label) ?? 'free') === 'free')\n .slice(0, Math.floor(qty));\n if (labels.length !== Math.floor(qty)) return null;\n const selections = new Map<string, { label: string; tierId?: string | null }>();\n for (const item of this.hold_?.items ?? []) selections.set(item.label, { label: item.label, tierId: item.tierId });\n if (this.hold_ && !this.hold_?.items?.length) {\n for (const seat of this.hold_.seats) selections.set(seat.label, { label: seat.label, ...(seat.tierId ? { tierId: seat.tierId } : {}) });\n }\n for (const seat of this.renderer?.getSelection() ?? []) {\n const resolved = this.labelToSeat.get(seat.label);\n const chosen = resolved ? this.toSeat(resolved) : null;\n selections.set(seat.label, { label: seat.label, ...(chosen?.tierId ? { tierId: chosen.tierId } : {}) });\n }\n for (const label of labels) selections.set(label, { label, ...(options.tierId ? { tierId: options.tierId } : {}) });\n const combined = [...selections.values()];\n const result = await this.api.hold(this.key, combined, options.ttlMs, this.hold_?.holdId);\n this.setHold({ holdId: result.holdId, labels: combined.map((s) => s.label), expiresAt: result.expiresAt, items: result.items });\n return this.hold_;\n }\n\n /** Server-picks `qty` best free seats and holds them atomically. Throws on failure. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n // Drop any prior auto-hold first.\n if (this.hold_ && !(await this.release())) return null;\n try {\n const result = await this.api.bestAvailable(this.key, qty, categoryKey);\n r.clearSelection();\n const ids = result.labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) r.setStatus(ids, 'held');\n this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt, items: result.items });\n const seats = result.labels\n .map((l) => this.labelToSeat.get(l))\n .filter((s): s is ExpandedSeat => !!s)\n .map((s) => this.toSeat(s));\n this.opts.onSelectionChange?.(seats);\n return this.hold_;\n } catch (err) {\n const { status, reason } = errInfo(err);\n if (status === 409 && reason === 'event_closed') this.opts.onSalesClosed?.();\n throw err;\n }\n }\n\n /**\n * Complete a booking. Requires a transport that supports book() (the SDK\n * deliberately does not). `bookingRef` MUST be a real reference from the caller.\n * `labelsArg` lets the caller book its own cart (the live page's confirm-flow\n * cart can hold best-available seats that aren't in the renderer selection);\n * defaults to the renderer selection. Reuses an existing exact-match hold, else\n * holds first. Returns the labels booked, or null on failure (conflicts painted).\n */\n async book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null> {\n const r = this.renderer;\n if (!r) return null;\n if (!this.api.book) throw new Error('picker: transport has no book() — hold-only mode');\n const labels = labelsArg ?? r.getSelection().map((s) => s.label);\n if (!labels.length) return null;\n\n let holdId: string | undefined;\n try {\n if (this.hold_ && this.holdCovers(labels)) {\n holdId = this.hold_.holdId; // already held server-side — re-holding would 409\n } else {\n const replaceHoldId = this.hold_?.holdId;\n const h = await this.api.hold(\n this.key,\n labels.map((label) => {\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return { label, ...(resolved?.tierId ? { tierId: resolved.tierId } : {}) };\n }),\n undefined,\n replaceHoldId,\n );\n holdId = h.holdId;\n this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });\n }\n await this.api.book(this.key, labels, holdId, bookingRef);\n } catch (err) {\n const { status, conflicts, reason } = errInfo(err);\n this.clearHold();\n if (status === 409 && reason === 'event_closed') {\n this.opts.onSalesClosed?.();\n } else if (status === 409 && conflicts?.length) {\n // Paint the taken seats, deselect them, release the still-free remainder.\n const takenLabels = new Set(conflicts.map((c) => c.label));\n const takenIds = [...takenLabels].map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (takenIds.length) {\n r.setStatus(takenIds, 'booked');\n r.deselect(takenIds);\n }\n const stillFree = labels.filter((l) => !takenLabels.has(l));\n if (stillFree.length && holdId) void this.api.release(this.key, stillFree, holdId).catch(() => {});\n this.emitSelectionChange();\n } else if (holdId) {\n // Non-conflict failure after a hold landed — release it so seats aren't stranded.\n void this.api.release(this.key, labels, holdId).catch(() => {});\n }\n throw err;\n }\n // Success — optimistically paint booked, deselect just the booked seats\n // (not the whole selection — the cart may be an explicit subset), clear hold.\n const ids = labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n r.setStatus(ids, 'booked');\n r.deselect(ids);\n }\n this.clearHold();\n this.emitSelectionChange();\n this.opts.onBook?.(bookingRef);\n return labels;\n }\n\n /** Release the whole open hold (if any), repaint those seats free. */\n async release(): Promise<boolean> {\n const hold = this.hold_;\n if (!hold) return true;\n try {\n const result = await this.api.release(this.key, hold.labels, hold.holdId);\n if (!this.releaseConfirmed(result, hold.labels)) {\n await this.resnapshot();\n return false;\n }\n } catch (err) {\n this.emitError(err);\n return false;\n }\n if (this.hold_?.holdId !== hold.holdId) return true;\n this.clearHold();\n const ids = hold.labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n this.renderer?.deselect(ids);\n this.renderer?.setStatus(ids, 'free');\n }\n return true;\n }\n\n /**\n * Release just some labels from the open hold, keeping the rest held (used when\n * a buyer removes one seat chip). Clears the hold entirely once it empties.\n */\n async releaseLabels(labels: string[]): Promise<boolean> {\n const hold = this.hold_;\n if (!hold) return true;\n const drop = labels.filter((l) => hold.labels.includes(l));\n if (!drop.length) return true;\n try {\n const result = await this.api.release(this.key, drop, hold.holdId);\n if (!this.releaseConfirmed(result, drop)) {\n await this.resnapshot();\n return false;\n }\n } catch (err) {\n this.emitError(err);\n return false;\n }\n if (this.hold_?.holdId !== hold.holdId) return true;\n const remaining = hold.labels.filter((l) => !drop.includes(l));\n const remainingItems = hold.items?.filter((item) => !drop.includes(item.label));\n if (remaining.length) this.setHold({ ...hold, labels: remaining, items: remainingItems });\n else this.clearHold();\n const ids = drop.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n this.renderer?.deselect(ids);\n this.renderer?.setStatus(ids, 'free');\n }\n return true;\n }\n\n /** New transports return the exact labels released; tolerate older adapters. */\n private releaseConfirmed(result: unknown, requested: string[]): boolean {\n const released = (result as { released?: unknown } | null)?.released;\n return !Array.isArray(released) || requested.every((label) => released.includes(label));\n }\n\n // ---- renderer proxies (so consumers don't reach through) ------------------\n\n setStatus(ids: string[], status: SeatStatus): void {\n this.renderer?.setStatus(ids, status);\n }\n getStatus(id: string): SeatStatus | undefined {\n return this.renderer?.getStatus(id);\n }\n flashSeat(id: string, color?: string): void {\n this.renderer?.flashSeat(id, color);\n }\n zoomIn(): void {\n this.renderer?.zoomIn();\n }\n zoomOut(): void {\n this.renderer?.zoomOut();\n }\n zoomToFit(): void {\n this.renderer?.zoomToFit();\n }\n worldToScreen(p: { x: number; y: number }): { x: number; y: number } {\n return this.renderer?.worldToScreen(p) ?? { x: 0, y: 0 };\n }\n setSelectionFocus(seatId: string | null): void {\n this.renderer?.setSelectionFocus?.(seatId);\n }\n setAccessibilityFilter(types: string[] | null): void {\n this.renderer?.setAccessibilityFilter?.(types as never);\n }\n\n // ---- multi-floor (Batch 5) ------------------------------------------------\n\n /** Floors for the buyer's switcher (>1 ⇒ show it). Single-floor ⇒ one entry. */\n getFloors(): { id: string; name: string }[] {\n return this.renderer?.getFloors?.() ?? [];\n }\n getActiveFloorId(): string {\n return this.renderer?.getActiveFloorId?.() ?? '';\n }\n /** Switch the shown floor (2D), then re-apply live seat statuses onto it. */\n setFloor(id: string): void {\n const r = this.renderer;\n if (!r?.setActiveFloor || id === r.getActiveFloorId?.()) return;\n r.setStacked?.(false); // leaving any 3D stack — back to a single floor\n r.setActiveFloor(id);\n void this.resnapshot(); // re-paint statuses on the newly-rendered floor\n this.emitSelectionChange();\n }\n\n /** 3D all-floors stacked overview ⇄ active floor. Re-applies statuses after. */\n setStacked(on: boolean): void {\n const r = this.renderer;\n if (!r?.setStacked || on === r.isStacked?.()) return;\n r.setStacked(on);\n void this.resnapshot(); // re-paint statuses across the rebuilt view\n }\n isMultiFloor(): boolean {\n return (this._doc?.floors?.length ?? 0) > 1;\n }\n\n /** Tap-a-deck-to-enter: leave the 3D stack, drop to flat 2D on `floorId`, and\n * tell the host so it can sync its 2D/3D toggle + floor-switcher state. */\n private handleDeckTap(floorId: string): void {\n const r = this.renderer;\n if (!r) return;\n r.setViewMode?.('flat');\n r.setStacked?.(false);\n r.setActiveFloor?.(floorId);\n void this.resnapshot();\n this.emitSelectionChange();\n this.opts.onDeckTap?.(floorId);\n }\n\n // ---- big-venue: sections / rungs / projection (Slice 5) -------------------\n\n /** Switch the map projection (2D flat ⇄ 3D isometric). No-op on a flat renderer. */\n setViewMode(mode: 'flat' | 'isometric'): void {\n this.renderer?.setViewMode?.(mode);\n }\n getViewMode(): 'flat' | 'isometric' {\n return this.renderer?.getViewMode?.() ?? 'flat';\n }\n /** Current LOD rung (for the ZONES/SECTIONS/SEATS pill). */\n getRung(): LodRung {\n return this.renderer?.getRung?.() ?? 'seats';\n }\n /** Jump to a rung; ZONES clears any focused summary (back to overview). */\n setRung(rung: LodRung): void {\n if (rung === 'zones') {\n this.overview();\n return;\n }\n this.renderer?.setRung?.(rung);\n }\n\n /** Price-band filter (F4): dim free seats whose category is outside `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter(keys: string[] | null): void {\n this.renderer?.setCategoryFilter?.(keys);\n }\n\n /** An explicit buyer price-filter action should not only dim the rest of the\n * chart: clear any older section drill-in and guide the camera to the seats\n * that remain relevant. Clearing the filter glides back to the full chart. */\n focusCategoryFilter(keys: string[] | null): void {\n const renderer = this.renderer;\n if (!renderer) return;\n renderer.clearSectionFocus?.();\n this.opts.onSectionFocus?.(null);\n // Multi-floor: the wanted categories may live on another deck entirely.\n // The renderer only knows the active floor's seats, so without switching\n // first the camera has nothing to frame and the filter is a silent no-op.\n if (keys?.length) {\n const target = this.floorForCategories(keys);\n if (target) this.setFloor(target);\n }\n if (renderer.focusCategories) renderer.focusCategories(keys);\n else renderer.zoomToFit();\n }\n\n /** The floor a buyer means when filtering to `keys`: the active floor when it\n * carries any of those categories, else the first floor that does (null =\n * stay put). Row overrides and GA areas count — a category can exist on a\n * floor only via a per-seat override. */\n private floorForCategories(keys: string[]): string | null {\n const doc = this._doc;\n if (!doc?.floors || doc.floors.length < 2) return null;\n const wanted = new Set(keys);\n const carries = (objects: ChartObject[]): boolean =>\n objects.some((o) =>\n (o.type === 'row'\n && (wanted.has(o.categoryKey)\n || (o.overrides ?? []).some((ov) => ov.categoryKey != null && wanted.has(ov.categoryKey))))\n || (o.type === 'gaArea' && wanted.has(o.categoryKey)),\n );\n const activeId = this.getActiveFloorId();\n const active = doc.floors.find((f) => f.id === activeId);\n if (active && carries(active.objects)) return null;\n return doc.floors.find((f) => carries(f.objects))?.id ?? null;\n }\n\n /** World-space rect currently visible + full chart bounds (F3 minimap frame). */\n getViewport(): { visible: { x: number; y: number; width: number; height: number }; bounds: { x: number; y: number; width: number; height: number } } | null {\n const r = this.renderer;\n if (!r?.getVisibleWorldRect || !r.getWorldBounds) return null;\n return { visible: r.getVisibleWorldRect(), bounds: r.getWorldBounds() };\n }\n /** Glide in on a section and surface its summary (same path as a section tap). */\n focusSection(id: string): void {\n this.handleSectionTap(id);\n }\n /** Zoom back out to the whole chart and clear the section-summary card + focus. */\n overview(): void {\n this.renderer?.clearSectionFocus?.();\n this.renderer?.zoomToFit();\n this.opts.onSectionFocus?.(null);\n }\n\n /** Glide the camera into a tapped section and emit its computed summary. Uses\n * the AXS focus treatment (dim + backdrop) when the engine supports it; a\n * closed section is framed but never opens a buyer card. */\n private handleSectionTap(id: string): void {\n const r = this.renderer;\n if (!r) return;\n if (r.focusSection) r.focusSection(id);\n else r.focusRegion?.(id);\n if (this.isSectionClosed(id)) {\n this.opts.onSectionFocus?.(null); // closed: no purchase card\n return;\n }\n this.opts.onSectionFocus?.(this.sectionSummary(id));\n }\n\n /**\n * Build a section summary from the renderer's spatial membership: section +\n * zone labels, live seats-left, price range, and the per-category breakdown.\n */\n private sectionSummary(id: string): SectionSummary | null {\n const r = this.renderer;\n const doc = this._doc;\n if (!r || !doc) return null;\n const sec = doc.objects.find(\n (o): o is SectionObject => o.type === 'section' && o.id === id,\n );\n if (!sec) return null;\n\n const memberIds = r.sectionMembers?.(id) ?? [];\n const byCat = new Map<string, number>();\n let seatsLeft = 0;\n for (const sid of memberIds) {\n const seat = this.seatById.get(sid);\n if (!seat) continue;\n byCat.set(seat.categoryKey, (byCat.get(seat.categoryKey) ?? 0) + 1);\n if (r.getStatus(sid) === 'free') seatsLeft++;\n }\n\n const categories: SectionCategory[] = [...byCat.entries()]\n .map(([key, count]) => {\n const cat = doc.categories.find((c) => c.key === key);\n return {\n key,\n count,\n label: cat?.label ?? key,\n color: cat?.color ?? '#6e7bff',\n price: cat?.price ?? 0,\n };\n })\n .sort((a, b) => a.price - b.price);\n\n const prices = categories.map((c) => c.price);\n const zone = sec.zone ? doc.zones?.find((z) => z.id === sec.zone) : undefined;\n const color = sec.color ?? zone?.color ?? categories[0]?.color ?? '#6e7bff';\n\n return {\n id,\n label: sec.label,\n zoneLabel: zone?.label ?? '',\n color,\n seatsLeft,\n priceMin: prices.length ? prices[0] : 0,\n priceMax: prices.length ? prices[prices.length - 1] : 0,\n categories,\n };\n }\n\n destroy(): void {\n this.closed = true;\n this.detachVisibilityListener();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.expiryTimer) {\n clearTimeout(this.expiryTimer);\n this.expiryTimer = null;\n }\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n /* ignore */\n }\n this.ws = null;\n }\n this.renderer?.destroy();\n this.renderer = null;\n }\n\n // ---- internals ------------------------------------------------------------\n\n private toSeat(s: ExpandedSeat): PickerSeat {\n const tiers = this.tiersFor(s.categoryKey);\n if (!tiers) {\n return { id: s.id, label: s.label, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey) };\n }\n const chosen = tiers.find((t) => t.id === this.seatTiers.get(s.id)) ?? tiers[0];\n return {\n id: s.id,\n label: s.label,\n categoryKey: s.categoryKey,\n price: chosen.price,\n tiers,\n tierId: chosen.id,\n };\n }\n /** Tooltip payload for a hovered seat — see PickerCallbacks.onSeatHover. */\n private describeSeat(s: ExpandedSeat): SeatHoverDetails {\n const cat = this._doc?.categories.find((c) => c.key === s.categoryKey);\n return {\n ...this.toSeat(s),\n categoryLabel: cat?.label ?? s.categoryKey,\n categoryColor: cat?.color ?? '#6e7bff',\n status: this.renderer?.getStatus(s.id) ?? 'free',\n currency: this.currency,\n ...this.seatContext.get(s.id),\n };\n }\n\n private priceFor(categoryKey: string): number {\n return this._doc?.categories.find((c) => c.key === categoryKey)?.price ?? 0;\n }\n private tiersFor(categoryKey: string): CategoryTier[] | undefined {\n const t = this._doc?.categories.find((c) => c.key === categoryKey)?.tiers;\n return t && t.length ? t : undefined;\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). Re-emits the\n * selection so the host's cart + the eventual hold carry the new tier + price.\n * `tierId = null` reverts to the category's first (default) tier. No-op if the\n * seat's category has no tiers or the id isn't one of them.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n const seat = this.seatById.get(seatId);\n if (!seat) return;\n const tiers = this.tiersFor(seat.categoryKey);\n if (!tiers) return;\n if (tierId == null) this.seatTiers.delete(seatId);\n else if (tiers.some((t) => t.id === tierId)) this.seatTiers.set(seatId, tierId);\n else return;\n this.emitSelectionChange();\n if (this.hold_) this.hold_ = { ...this.hold_, seats: this.seatsForLabels(this.hold_.labels) };\n }\n\n /** PickerSeats (with chosen tier) for a set of held labels. */\n private seatsForLabels(labels: string[]): PickerSeat[] {\n const out: PickerSeat[] = [];\n for (const l of labels) {\n const s = this.labelToSeat.get(l);\n if (s) out.push(this.toSeat(s));\n }\n return out;\n }\n private emitSelectionChange(): void {\n this.opts.onSelectionChange?.(this.getSelection());\n this.emitOrphanHint();\n }\n\n /** Whether the last emitted hint was non-null (avoids clearing repeatedly). */\n private hintShown = false;\n\n /**\n * Orphan-seat advice on manual selection: when the buyer's current picks\n * strand one (or more) single free seats between unavailable same-row\n * neighbors, surface a localized, non-blocking hint. Cleared (null) as soon\n * as the selection stops stranding anyone.\n */\n private emitOrphanHint(): void {\n if (!this.opts.onHint) return;\n const r = this.renderer;\n if (!r) return;\n const selected = new Set(r.getSelection().map((s) => s.id));\n const stranded = selected.size\n ? strandedSingles(this.seatById.values(), (id) => r.getStatus(id), selected)\n : [];\n if (stranded.length > 0) {\n this.hintShown = true;\n this.opts.onHint(t('picker.orphanHint'));\n } else if (this.hintShown) {\n this.hintShown = false;\n this.opts.onHint(null);\n }\n }\n\n /** Toggle colorblind-safe rendering at runtime (see PickerOptions.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.renderer?.setColorblindSafe?.(on);\n }\n private emitError(err: unknown): void {\n if (this.opts.onError) this.opts.onError(err);\n else console.error('[picker]', err);\n }\n\n private holdCovers(labels: string[]): boolean {\n const h = this.hold_;\n if (!h || h.labels.length !== labels.length || !labels.every((l) => h.labels.includes(l))) return false;\n const tiers = new Map((h.items ?? []).map((item) => [item.label, item.tierId]));\n return labels.every((label) => {\n const seat = this.labelToSeat.get(label);\n const currentTier = seat ? this.toSeat(seat).tierId ?? null : null;\n return !tiers.has(label) || tiers.get(label) === currentTier;\n });\n }\n\n private handle409Conflicts(err: unknown): void {\n const { status, conflicts } = errInfo(err);\n if (status !== 409 || !conflicts?.length) return;\n const r = this.renderer;\n if (!r) return;\n const takenIds = conflicts.map((c) => this.labelToId.get(c.label)).filter((v): v is string => !!v);\n if (takenIds.length) {\n r.deselect(takenIds);\n r.setStatus(takenIds, 'held');\n }\n this.emitSelectionChange();\n }\n\n /** Set the open hold + (re)arm the server-authoritative expiry timer. */\n private setHold(\n hold: Omit<HoldInfo, 'seats'> & { seats?: PickerSeat[] },\n source: 'created' | 'restored' = 'created',\n ): void {\n // Always resolve seats (with chosen tier) from the held labels so the host's\n // onHold — and any later book — carries the tier the buyer picked per seat.\n const full: HoldInfo = { ...hold, seats: this.seatsForLabels(hold.labels) };\n this.hold_ = full;\n this.renderer?.setOwnedHold?.(\n full.labels.map((label) => this.labelToId.get(label)).filter((id): id is string => !!id),\n );\n if (this.expiryTimer) clearTimeout(this.expiryTimer);\n const ms = Math.max(0, full.expiresAt - Date.now());\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), ms);\n if (source === 'restored') this.opts.onHoldRestored?.(full);\n else this.opts.onHold?.(full);\n }\n private clearHold(): void {\n this.hold_ = null;\n this.renderer?.setOwnedHold?.(null);\n if (this.expiryTimer) {\n clearTimeout(this.expiryTimer);\n this.expiryTimer = null;\n }\n }\n private async expireActiveHold(): Promise<void> {\n const hold = this.hold_;\n if (!hold) return;\n try {\n const snap = await this.api.objects(this.key);\n if (this.hold_?.holdId !== hold.holdId) return;\n this.applySeatsMap(snap.seats);\n } catch {\n // Do not report expiry from a disconnected/stale client. Reconcile once\n // the authoritative snapshot becomes reachable.\n if (this.hold_?.holdId === hold.holdId) {\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 2_000);\n }\n return;\n }\n if (this.hold_?.holdId !== hold.holdId) return; // booked snapshot cleared it\n if (hold.labels.some((label) => this.liveStatuses.get(label) === 'held')) {\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 1_000);\n return;\n }\n this.clearHold();\n this.opts.onHoldExpired?.();\n }\n\n private applySeatsMap(seats: Record<string, string>): void {\n const r = this.renderer;\n if (!r) return;\n this.liveStatuses = new Map(Object.entries(seats));\n if (this.allIds.length) r.setStatus(this.allIds, 'free');\n // setChart() rebuilds renderer state (floor/hidden-section changes), so\n // restore the buyer-ownership layer before repainting held statuses.\n r.setOwnedHold?.(\n (this.hold_?.labels ?? [])\n .map((label) => this.labelToId.get(label))\n .filter((id): id is string => !!id),\n );\n const byStatus: Record<SeatStatus, string[]> = { free: [], held: [], booked: [], not_for_sale: [] };\n for (const [label, st] of Object.entries(seats)) {\n const id = this.labelToId.get(label);\n if (id) byStatus[mapStatus(st)].push(id);\n }\n (['held', 'booked', 'not_for_sale'] as SeatStatus[]).forEach((st) => {\n if (byStatus[st].length) r.setStatus(byStatus[st], st);\n });\n this.opts.onStatusChange?.();\n this.clearBookedHoldIfSettled();\n }\n\n private clearBookedHoldIfSettled(): void {\n if (this.hold_?.labels.every((label) => this.liveStatuses.get(label) === 'booked')) this.clearHold();\n }\n\n private async resnapshot(): Promise<void> {\n try {\n const objs = await this.api.objects(this.key);\n this.applySeatsMap(objs.seats);\n } catch {\n /* transient — the socket delta stream keeps us fresh */\n }\n }\n\n /**\n * Re-pull the status snapshot on demand. Live surfaces rarely need this (the\n * socket keeps them fresh); local/mock transports with no socket call it\n * after they mutate state (e.g. the demo books a hold) so the renderer and\n * every onStatusChange consumer repaint from the new truth.\n */\n async refresh(): Promise<void> {\n await this.resnapshot();\n }\n\n // ---- realtime socket ------------------------------------------------------\n\n /**\n * Buyer catch-up on tab regain. While a tab is hidden Chrome pauses rAF, so\n * seat-status deltas that arrived over the WS mutated the scene graph but the\n * canvas colors never repainted. When the tab becomes visible again we (1)\n * resnapshot to pull authoritative state for anything the socket may have\n * missed while backgrounded, then (2) forceDraw() a synchronous repaint so the\n * seat colors are correct immediately rather than on the next incidental draw.\n *\n * Attached once per mount; guarded against double-attach and non-DOM\n * environments; detached in destroy() (no leaks).\n */\n private attachVisibilityListener(): void {\n if (this.onVisibilityChange) return; // already attached (guard double mount)\n if (typeof document === 'undefined' || typeof document.addEventListener !== 'function') return;\n const handler = (): void => {\n if (this.closed) return;\n if (document.visibilityState !== 'visible') return;\n // Re-fetch authoritative state, then paint it synchronously.\n void this.resnapshot().then(() => {\n if (!this.closed) this.renderer?.forceDraw();\n });\n };\n this.onVisibilityChange = handler;\n document.addEventListener('visibilitychange', handler);\n }\n\n private detachVisibilityListener(): void {\n if (!this.onVisibilityChange) return;\n if (typeof document !== 'undefined' && typeof document.removeEventListener === 'function') {\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\n }\n this.onVisibilityChange = null;\n }\n\n private connect(): void {\n if (this.closed) return;\n // A transport may be fully local (demo/mock) — an empty socketUrl means\n // \"no live feed\"; skip the connection instead of retrying forever.\n const url = this.api.socketUrl(this.key);\n if (!url) return;\n let ws: WebSocket;\n try {\n ws = new WebSocket(url);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n this.attempt = 0;\n void this.resnapshot();\n };\n ws.onmessage = (e) => {\n let msg: unknown;\n try {\n msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n } catch {\n return;\n }\n const r = this.renderer;\n if (!r || !msg || typeof msg !== 'object') return;\n const m = msg as { type?: string; hidden?: string[]; closed?: string[]; seats?: Record<string, string>; changes?: { label: string; status: string }[] };\n // Reconcile hidden sections whenever they arrive (dedicated 'hidden' message\n // OR a snapshot that carries them). Only rebuilds the chart when it changed.\n if (Array.isArray(m.hidden) && this.syncHidden(m.hidden)) {\n void this.resnapshot(); // repaint statuses onto the rebuilt chart\n this.opts.onStatusChange?.();\n }\n // Reconcile closed sections (Phase 2). Cheap grey restyle, no chart rebuild —\n // so flipping a section open/closed mid-sale repaints for connected buyers.\n if (Array.isArray(m.closed) && this.syncClosed(m.closed)) {\n this.opts.onStatusChange?.();\n }\n if (m.type === 'hidden') return; // dedicated hidden message carries no seats\n if (m.seats && typeof m.seats === 'object') {\n this.applySeatsMap(m.seats);\n } else if (Array.isArray(m.changes)) {\n for (const ch of m.changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const id = this.labelToId.get(ch.label);\n if (!id) continue;\n const next = mapStatus(ch.status);\n // Flash a live free→taken change — but not the buyer's OWN just-held\n // seats (a manual hold leaves them 'free' locally, so the server's\n // held-delta would otherwise flash them as if someone else grabbed them).\n if (\n this.opts.flashOnLiveChange &&\n next !== 'free' &&\n r.getStatus(id) === 'free' &&\n !this.hold_?.labels.includes(ch.label)\n ) {\n // Pulse color mirrors the manager board's status language:\n // amber for a hold landing, red for a booking.\n r.flashSeat(id, next === 'held' ? '#f4b740' : '#f43f5e');\n }\n r.setStatus([id], next);\n }\n // Stay-live-while-hidden (opt-in, default OFF). setStatus paints via\n // batchDraw (rAF), which Chrome pauses on a hidden tab — so an always-on\n // board (the future organizer control room) would freeze while\n // backgrounded. When enabled, force a synchronous repaint so a hidden\n // board keeps painting. The buyer widget leaves this off and relies on\n // the visibilitychange catch-up instead.\n if (\n this.opts.keepLiveWhileHidden &&\n typeof document !== 'undefined' &&\n document.visibilityState === 'hidden'\n ) {\n r.forceDraw();\n }\n this.clearBookedHoldIfSettled();\n this.opts.onStatusChange?.();\n }\n };\n ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.scheduleReconnect();\n };\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives reconnect */\n }\n };\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n}\n","/**\n * Synthetic view-from-seat panorama, generated from chart geometry alone.\n *\n * Draws a 2048×1024 equirectangular texture of a dark hall with the stage\n * placed at the correct bearing and angular size for THIS seat — closer seats\n * see a bigger stage, off-center seats see it at an angle. Used whenever the\n * organizer hasn't uploaded a real photo/360 for the seat; both go through the\n * same viewer.\n *\n * Equirectangular mapping: x = (yaw + 180°)/360° · W, y = (90° − pitch)/180° · H,\n * where yaw 0 = the direction the camera faces by default.\n */\n\nimport type { ExpandedSeat, Point } from '../core/types';\n\nconst W = 2048;\nconst H = 1024;\n/** Chart units → meters, for plausible eye-level proportions (seatSpacing 24 ≈ 0.55m). */\nconst UNIT = 0.55 / 24;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\nexport interface PanoramaResult {\n url: string;\n /** Meters from the stage, for the caption. */\n distanceM: number;\n}\n\nexport function generateSeatPanorama(\n seat: ExpandedSeat,\n focalPoint: Point,\n neighborSeats: ExpandedSeat[],\n): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distU = Math.hypot(dx, dy);\n const distM = Math.max(2, distU * UNIT);\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.42, '#11172a');\n sky.addColorStop(0.5, '#1a2238');\n sky.addColorStop(0.56, '#10141f');\n sky.addColorStop(1, '#07090f');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // ---- stage, centered at yaw 0 (the viewer opens facing it) -------------\n // Angular size from real proportions: stage ~8m wide, ~1m platform + 6m set.\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(45, (Math.atan2(5, distM) * 180) / Math.PI);\n const stageBasePitch = Math.max(-30, (-Math.atan2(1.1, distM) * 180) / Math.PI);\n\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n\n // glow behind the stage\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 10, W / 2, (sy0 + sy1) / 2, (sx1 - sx0) * 1.1);\n glow.addColorStop(0, 'rgba(129, 140, 248, 0.5)');\n glow.addColorStop(0.5, 'rgba(99, 102, 241, 0.16)');\n glow.addColorStop(1, 'rgba(99, 102, 241, 0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - (sx1 - sx0) * 0.6, sy0 - (sy1 - sy0) * 1.2, (sx1 - sx0) * 2.2, (sy1 - sy0) * 3.4);\n\n // stage box + lit backdrop\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.75;\n ctx.fillStyle = backdrop;\n const inset = (sx1 - sx0) * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + (sy1 - sy0) * 0.12, sx1 - sx0 - inset * 2, (sy1 - sy0) * 0.62);\n ctx.globalAlpha = 1;\n // stage lip\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - (sy1 - sy0) * 0.1, sx1 - sx0, (sy1 - sy0) * 0.1);\n\n // performer silhouettes, scaled by distance\n const performerH = (sy1 - sy0) * 0.45;\n ctx.fillStyle = 'rgba(8, 10, 16, 0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + (sx1 - sx0) * fx;\n const py = sy1 - (sy1 - sy0) * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - performerH * 0.82, performerH * 0.16, 0, Math.PI * 2); // head\n ctx.fill();\n ctx.fillRect(px - performerH * 0.14, py - performerH * 0.68, performerH * 0.28, performerH * 0.68); // body\n }\n\n // spotlight beams from above the stage\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + (sx1 - sx0) * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.lineTo(bx - (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // ---- rig lights along the ceiling all around ---------------------------\n ctx.fillStyle = 'rgba(199, 210, 254, 0.8)';\n for (let i = 0; i < 26; i++) {\n const x = (i / 26) * W;\n const y = pitchToY(55 + (i % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, 3.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // ---- audience: heads of nearby seats, at their true bearings -----------\n // Bearing relative to the stage direction so yaw 0 keeps facing the stage.\n const stageBearing = Math.atan2(dx, -dy); // screen coords, -y is \"up\" the hall\n ctx.fillStyle = 'rgba(16, 20, 30, 0.95)';\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const d = Math.hypot(ox, oy) * UNIT;\n if (d < 0.3 || d > 14) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const headPitch = (-Math.atan2(0.35, d) * 180) / Math.PI; // heads slightly below eye level\n const headR = Math.min(46, 260 / (d / UNIT / 24 + 1.2) / 4);\n const hx = yawToX(yaw);\n const hy = pitchToY(headPitch);\n ctx.beginPath();\n ctx.arc(hx, hy, headR, 0, Math.PI * 2);\n ctx.fill();\n ctx.beginPath(); // shoulders\n ctx.ellipse(hx, hy + headR * 1.4, headR * 1.7, headR * 0.9, 0, Math.PI, 0, true);\n ctx.fill();\n }\n\n // subtle vignette at the poles (hides equirect pinching)\n const poleFade = ctx.createLinearGradient(0, 0, 0, H);\n poleFade.addColorStop(0, 'rgba(0,0,0,0.85)');\n poleFade.addColorStop(0.12, 'rgba(0,0,0,0)');\n poleFade.addColorStop(0.88, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.85)');\n ctx.fillStyle = poleFade;\n ctx.fillRect(0, 0, W, H);\n\n return { url: canvas.toDataURL('image/jpeg', 0.82), distanceM: Math.round(distM) };\n}\n\n// ---------------------------------------------------------------------------\n// Compact forward-view thumbnail — a cheap (480×270) rectilinear preview of\n// what this seat faces, for inline display inside the buyer's confirm card.\n// Unlike the full equirectangular panorama it maps a ~100°×60° forward field\n// of view directly (no 360 squish), so it reads as a real POV at a glance and\n// costs a fraction of the full render. Same geometry → the two stay consistent.\n// ---------------------------------------------------------------------------\n\nconst TW = 480;\nconst TH = 270;\nconst HALF_HFOV = 50; // degrees left/right of the stage direction\nconst HALF_VFOV = 30; // degrees up/down of the horizon\n\nconst yawToTX = (yawDeg: number) => ((yawDeg + HALF_HFOV) / (2 * HALF_HFOV)) * TW;\nconst pitchToTY = (pitchDeg: number) => ((HALF_VFOV - pitchDeg) / (2 * HALF_VFOV)) * TH;\n\nexport function generateSeatThumb(seat: ExpandedSeat, focalPoint: Point, _neighborSeats?: ExpandedSeat[]): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = TW;\n canvas.height = TH;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distM = Math.max(2, Math.hypot(dx, dy) * UNIT);\n\n // hall shell (ceiling → wall → floor), horizon at mid-height\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.44, '#141b30');\n sky.addColorStop(0.5, '#1b2440');\n sky.addColorStop(0.58, '#10141f');\n sky.addColorStop(1, '#070910');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n // stage geometry (identical formulas to the full panorama)\n const stageHalfYaw = Math.min(HALF_HFOV - 2, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(HALF_VFOV - 2, (Math.atan2(5, distM) * 180) / Math.PI);\n const stageBasePitch = Math.max(-HALF_VFOV + 2, (-Math.atan2(1.1, distM) * 180) / Math.PI);\n const sx0 = yawToTX(-stageHalfYaw);\n const sx1 = yawToTX(stageHalfYaw);\n const sy0 = pitchToTY(stageTopPitch);\n const sy1 = pitchToTY(stageBasePitch);\n const sw = sx1 - sx0;\n const sh = sy1 - sy0;\n\n // glow\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.1);\n glow.addColorStop(0, 'rgba(129,140,248,0.5)');\n glow.addColorStop(0.5, 'rgba(99,102,241,0.15)');\n glow.addColorStop(1, 'rgba(99,102,241,0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - sw * 0.6, sy0 - sh * 1.2, sw * 2.2, sh * 3.4);\n\n // stage box + lit backdrop + lip\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sw, sh);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.78;\n ctx.fillStyle = backdrop;\n const inset = sw * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + sh * 0.12, sw - inset * 2, sh * 0.62);\n ctx.globalAlpha = 1;\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - sh * 0.1, sw, sh * 0.1);\n\n // performer silhouettes\n const ph = sh * 0.45;\n ctx.fillStyle = 'rgba(8,10,16,0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + sw * fx;\n const py = sy1 - sh * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - ph * 0.82, ph * 0.16, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillRect(px - ph * 0.14, py - ph * 0.68, ph * 0.28, ph * 0.68);\n }\n\n // spotlight beams\n ctx.globalAlpha = 0.15;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + sw * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.lineTo(bx - sw * 0.09, sy1);\n ctx.lineTo(bx + sw * 0.09, sy1);\n ctx.lineTo(bx + 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // a few rig lights across the ceiling\n ctx.fillStyle = 'rgba(199,210,254,0.75)';\n for (let i = 0; i < 8; i++) {\n ctx.beginPath();\n ctx.arc(((i + 0.5) / 8) * TW, pitchToTY(HALF_VFOV - 4 - (i % 2) * 3), 2.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // seat-back rows in the foreground for depth\n ctx.fillStyle = 'rgba(10,13,20,0.9)';\n ctx.fillRect(0, TH - 26, TW, 26);\n ctx.fillStyle = 'rgba(30,37,54,0.9)';\n for (let i = 0; i < 9; i++) ctx.fillRect(i * (TW / 9) + 6, TH - 22, TW / 9 - 12, 14);\n\n return { url: canvas.toDataURL('image/jpeg', 0.8), distanceM: Math.round(distM) };\n}\n","/**\n * Locale bundle loader — keeps non-English translations OUT of the initial\n * bundle (the 60 KB SDK budget is a product contract) and code-splits each\n * locale so a page/SDK only downloads the language it actually uses.\n *\n * `loadLocale('de')` dynamic-imports the German dictionary, registers it via\n * setLocale(), and resolves once it's active. English is built in, so\n * `loadLocale('en')` is synchronous and never fetches. Unknown/unsupported\n * codes fall back to English without throwing.\n */\nimport { setLocale, resolveLocale, type Dict, type Locale } from './index';\n\n/** Dynamic importers per non-English locale (English ships in the core). */\nconst LOADERS: Record<Exclude<Locale, 'en'>, () => Promise<{ default: Dict }>> = {\n es: () => import('./locales/es').then((m) => ({ default: m.es })),\n de: () => import('./locales/de').then((m) => ({ default: m.de })),\n fr: () => import('./locales/fr').then((m) => ({ default: m.fr })),\n};\n\nconst loaded = new Set<Locale>(['en']);\n\n/**\n * Resolve `code` to a supported locale, load its bundle if needed, and make it\n * active. Returns the locale that ended up active (English on any failure).\n */\nexport async function loadLocale(code?: string | null): Promise<Locale> {\n const locale = resolveLocale(code);\n if (locale === 'en' || loaded.has(locale)) {\n setLocale(locale);\n return locale;\n }\n try {\n const mod = await LOADERS[locale]();\n setLocale(locale, mod.default);\n loaded.add(locale);\n return locale;\n } catch {\n setLocale('en');\n return 'en';\n }\n}\n"],"mappings":"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","names":["t","t","objects","t","rgb","KImage","active","t"]}
|
|
1
|
+
{"version":3,"sources":["../src/i18n/locales/es.ts","../src/i18n/locales/de.ts","../src/i18n/locales/fr.ts","../src/index.ts","../src/core/types.ts","../src/core/complexGeometry.ts","../src/core/sectionPath.ts","../src/core/layout.ts","../src/core/ga.ts","../src/core/sections.ts","../src/engine/SeatmapRenderer.ts","../src/core/chartRenderRules.ts","../src/lib/money.ts","../src/i18n/locales/en.ts","../src/i18n/index.ts","../src/core/orphans.ts","../src/picker/PickerController.ts","../src/view/generatePanorama.ts","../src/i18n/bundles.ts"],"sourcesContent":["/**\n * Spanish (es) bundle — neutral/international Spanish translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const es: Dict = {\n // shared\n 'common.cancel': 'Cancelar',\n 'common.close': 'Cerrar',\n 'common.done': 'Listo',\n 'common.copied': '✓ Copiado',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Retener asientos y comprar',\n 'picker.completeBooking': 'Completar reserva',\n 'picker.seatsHeld': 'Asientos retenidos — {time}',\n 'picker.holdExpired': 'Tu retención expiró — los asientos fueron liberados. Elige de nuevo.',\n 'picker.seatTaken': 'El asiento {label} fue tomado por otro comprador.',\n 'picker.poweredBy': 'Con la tecnología de SeatLayer',\n 'picker.testMode': 'MODO DE PRUEBA',\n 'picker.colorblind': 'Colores aptos para daltonismo',\n 'picker.orphanHint': 'Esto deja un asiento aislado — considera desplazarte un asiento.',\n 'picker.seats.one': '{count} asiento',\n 'picker.seats.other': '{count} asientos',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.statusHeld': 'En espera',\n 'map.statusTaken': 'Ocupado',\n 'map.fromPrice': 'DESDE {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Idioma',\n 'picker.zoomToFit': 'Ajustar zoom',\n 'picker.seatCountLabel': 'asientos',\n 'picker.capacity': 'capacidad',\n 'picker.viewMode': 'Modo de vista',\n 'picker.floor': 'Piso',\n 'picker.zoomLevel': 'Nivel de zoom',\n 'picker.rungTip.zones': 'Vista general — grupos de secciones como Grada norte o VIP',\n 'picker.rungTip.sections': 'Bloques de sección — mezcla de categorías + matiz de disponibilidad',\n 'picker.rungTip.seats': 'Asientos individuales — los bloques se convierten en puntos',\n 'picker.rungLabel.zones': 'ZONAS',\n 'picker.rungLabel.sections': 'SECCIONES',\n 'picker.rungLabel.seats': 'ASIENTOS',\n 'picker.sectionSummaryAria': 'Resumen de sección {label}',\n 'picker.closeSectionSummary': 'Cerrar resumen de sección',\n 'picker.seatsLeftInSection.one': '{count} asiento disponible',\n 'picker.seatsLeftInSection.other': '{count} asientos disponibles',\n 'picker.overview': 'Descripción general',\n 'picker.tapSeatHint': 'Toca cualquier asiento para ver su vista',\n 'picker.chartSize': 'Tamaño del gráfico',\n 'picker.custom': 'Personalizado',\n 'picker.categories': 'Categorías',\n 'picker.accessibility': 'Accesibilidad',\n 'picker.showAnyAccessible': 'Mostrar cualquier asiento accesible',\n 'picker.any': 'Cualquiera',\n 'picker.yourSeats': 'Tus asientos',\n 'picker.emptySeats': 'Toca asientos en el mapa',\n 'picker.emptySeatsWithGa': 'Toca asientos en el mapa · toca un área de pie para entradas de entrada general',\n 'picker.oneFewer': 'Uno menos',\n 'picker.oneMore': 'Uno más',\n 'picker.remove': 'Eliminar {label}',\n 'picker.ticketTierFor': 'Categoría de entrada para {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'Vista desde el asiento {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VISTA PREVIA',\n 'picker.open360': 'Abrir vista de 360°',\n 'picker.sightline': '≈ {m} m al escenario · visión despejada',\n 'picker.bookedDemo': '¡Reservado! (demostración)',\n 'picker.bookButton.one': 'Reservar {count} entrada — {amount}',\n 'picker.bookButton.other': 'Reservar {count} entradas — {amount}',\n 'picker.simulateCrowd': 'Simular multitud: {state}',\n 'picker.on': 'ACTIVADO',\n 'picker.off': 'DESACTIVADO',\n 'picker.panorama360': 'Foto de 360° del lugar',\n 'picker.illustrationCaption': 'ilustración · ≈ {m} m del escenario',\n 'picker.restrictedView': 'Visibilidad restringida',\n 'picker.obstructedView': 'Visibilidad obstruida',\n 'picker.premiumSeat': 'Asiento premium',\n 'picker.hideLimitedView': 'Ocultar asientos con visibilidad limitada',\n};\n","/**\n * German bundle — native-quality translations of the English reference dictionary.\n * Keys are identical to en.ts; values are translated to German (de).\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const de: Dict = {\n // shared\n 'common.cancel': 'Abbrechen',\n 'common.close': 'Schließen',\n 'common.done': 'Fertig',\n 'common.copied': '✓ Kopiert',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Plätze reservieren & Kasse',\n 'picker.completeBooking': 'Buchung abschließen',\n 'picker.seatsHeld': 'Plätze reserviert — {time}',\n 'picker.holdExpired': 'Ihre Reservierung ist abgelaufen — die Plätze wurden freigegeben. Bitte erneut auswählen.',\n 'picker.seatTaken': 'Platz {label} wurde gerade von einem anderen Käufer gebucht.',\n 'picker.poweredBy': 'Bereitgestellt von SeatLayer',\n 'picker.testMode': 'TESTMODUS',\n 'picker.colorblind': 'Farbenblind-freundliche Farben',\n 'picker.orphanHint': 'Dadurch bleibt ein einzelner Platz übrig — rücken Sie ggf. einen Platz weiter.',\n 'picker.seats.one': '{count} Platz',\n 'picker.seats.other': '{count} Plätze',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Sitzplan. Mit Pfeiltasten zwischen Plätzen navigieren, Eingabe zum Auswählen.',\n 'map.seatsLeft': '{count} FREI',\n 'map.statusHeld': 'Reserviert',\n 'map.statusTaken': 'Vergeben',\n 'map.fromPrice': 'AB {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Sprache',\n 'picker.zoomToFit': 'Auf Größe anpassen',\n 'picker.seatCountLabel': 'Plätze',\n 'picker.capacity': 'Kapazität',\n 'picker.viewMode': 'Ansichtsmodus',\n 'picker.floor': 'Etage',\n 'picker.zoomLevel': 'Zoomstufe',\n 'picker.rungTip.zones': 'Übersicht — Bereichsgruppen wie Nordtribüne oder VIP',\n 'picker.rungTip.sections': 'Bereichs-Blöcke — Kategoriesortierung + Verfügbarkeitstönung',\n 'picker.rungTip.seats': 'Einzelne Plätze — Blöcke lösen sich zu Punkten auf',\n 'picker.rungLabel.zones': 'ZONEN',\n 'picker.rungLabel.sections': 'BEREICHE',\n 'picker.rungLabel.seats': 'PLÄTZE',\n 'picker.sectionSummaryAria': 'Bereichszusammenfassung {label}',\n 'picker.closeSectionSummary': 'Bereichszusammenfassung schließen',\n 'picker.seatsLeftInSection.one': '{count} Platz verfügbar',\n 'picker.seatsLeftInSection.other': '{count} Plätze verfügbar',\n 'picker.overview': 'Übersicht',\n 'picker.tapSeatHint': 'Tippen Sie auf einen Platz, um die Ansicht zu prüfen',\n 'picker.chartSize': 'Kartengröße',\n 'picker.custom': 'Benutzerdefiniert',\n 'picker.categories': 'Kategorien',\n 'picker.accessibility': 'Barrierefreiheit',\n 'picker.showAnyAccessible': 'Jeden barrierefreien Platz anzeigen',\n 'picker.any': 'Beliebig',\n 'picker.yourSeats': 'Ihre Plätze',\n 'picker.emptySeats': 'Tippen Sie auf die Plätze auf der Karte',\n 'picker.emptySeatsWithGa': 'Tippen Sie auf die Plätze auf der Karte · tippen Sie auf einen Stehbereich für Stehplatztickets',\n 'picker.oneFewer': 'Einen weniger',\n 'picker.oneMore': 'Einen mehr',\n 'picker.remove': '{label} entfernen',\n 'picker.ticketTierFor': 'Ticketklasse für {label}',\n 'picker.total': 'Gesamt: {amount}',\n 'picker.viewFromSeat': 'Ansicht von Platz {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VORSCHAU',\n 'picker.open360': 'Öffnen Sie die 360°-Ansicht',\n 'picker.sightline': '≈ {m} m zur Bühne · freie Sicht',\n 'picker.bookedDemo': 'Gebucht! (Demo)',\n 'picker.bookButton.one': '{count} Ticket buchen — {amount}',\n 'picker.bookButton.other': '{count} Tickets buchen — {amount}',\n 'picker.simulateCrowd': 'Menschenmenge simulieren: {state}',\n 'picker.on': 'AN',\n 'picker.off': 'AUS',\n 'picker.panorama360': '360°-Veranstaltungsfotos',\n 'picker.illustrationCaption': 'Illustration · ≈ {m} m von der Bühne',\n 'picker.restrictedView': 'Eingeschränkte Sicht',\n 'picker.obstructedView': 'Sichtbehinderung',\n 'picker.premiumSeat': 'Premium-Platz',\n 'picker.hideLimitedView': 'Plätze mit eingeschränkter Sicht ausblenden',\n};\n","/**\n * French (fr) bundle — native French translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const fr: Dict = {\n // shared\n 'common.cancel': 'Annuler',\n 'common.close': 'Fermer',\n 'common.done': 'Terminé',\n 'common.copied': '✓ Copié',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Réserver les sièges et valider',\n 'picker.completeBooking': 'Terminer la réservation',\n 'picker.seatsHeld': 'Sièges réservés — {time}',\n 'picker.holdExpired': 'Votre réservation a expiré — les sièges ont été libérés. Sélectionnez à nouveau.',\n 'picker.seatTaken': 'Le siège {label} vient d\\'être réservé par un autre acheteur.',\n 'picker.poweredBy': 'Propulsé par SeatLayer',\n 'picker.testMode': 'MODE TEST',\n 'picker.colorblind': 'Couleurs adaptées au daltonisme',\n 'picker.orphanHint': \"Cela laisse un siège isolé — pensez à vous décaler d'un siège.\",\n 'picker.seats.one': '{count} siège',\n 'picker.seats.other': '{count} sièges',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Plan de salle. Utilisez les flèches pour naviguer entre les sièges, Entrée pour sélectionner.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.statusHeld': 'En attente',\n 'map.statusTaken': 'Pris',\n 'map.fromPrice': 'DÈS {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Langue',\n 'picker.zoomToFit': 'Ajuster le zoom',\n 'picker.seatCountLabel': 'sièges',\n 'picker.capacity': 'capacité',\n 'picker.viewMode': 'Mode d\\'affichage',\n 'picker.floor': 'Étage',\n 'picker.zoomLevel': 'Niveau de zoom',\n 'picker.rungTip.zones': 'Vue générale — groupes de sections comme Tribune nord ou VIP',\n 'picker.rungTip.sections': 'Blocs de sections — mélange de catégories + teinte de disponibilité',\n 'picker.rungTip.seats': 'Sièges individuels — les blocs se transforment en points',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SIÈGES',\n 'picker.sectionSummaryAria': 'Résumé de la section {label}',\n 'picker.closeSectionSummary': 'Fermer le résumé de la section',\n 'picker.seatsLeftInSection.one': '{count} siège restant',\n 'picker.seatsLeftInSection.other': '{count} sièges restants',\n 'picker.overview': 'Vue d\\'ensemble',\n 'picker.tapSeatHint': 'Appuyez sur un siège pour vérifier sa vue',\n 'picker.chartSize': 'Taille du plan',\n 'picker.custom': 'Personnalisé',\n 'picker.categories': 'Catégories',\n 'picker.accessibility': 'Accessibilité',\n 'picker.showAnyAccessible': 'Afficher un siège accessible',\n 'picker.any': 'N\\'importe quel',\n 'picker.yourSeats': 'Vos sièges',\n 'picker.emptySeats': 'Appuyez sur les sièges sur le plan',\n 'picker.emptySeatsWithGa': 'Appuyez sur les sièges sur le plan · appuyez sur une zone debout pour les billets GA',\n 'picker.oneFewer': 'Un de moins',\n 'picker.oneMore': 'Un de plus',\n 'picker.remove': 'Supprimer {label}',\n 'picker.ticketTierFor': 'Catégorie de billet pour {label}',\n 'picker.total': 'Total : {amount}',\n 'picker.viewFromSeat': 'Vue depuis le siège {label}',\n 'picker.real360': 'VRAI 360°',\n 'picker.preview': 'APERÇU',\n 'picker.open360': 'Ouvrir la vue à 360°',\n 'picker.sightline': '≈ {m} m de la scène · vue dégagée',\n 'picker.bookedDemo': 'Réservé ! (démo)',\n 'picker.bookButton.one': 'Réserver {count} billet — {amount}',\n 'picker.bookButton.other': 'Réserver {count} billets — {amount}',\n 'picker.simulateCrowd': 'Simuler la foule : {state}',\n 'picker.on': 'ACTIVÉ',\n 'picker.off': 'DÉSACTIVÉ',\n 'picker.panorama360': 'Photo panoramique 360° du lieu',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m de la scène',\n 'picker.restrictedView': 'Visibilité réduite',\n 'picker.obstructedView': 'Vue obstruée',\n 'picker.premiumSeat': 'Place premium',\n 'picker.hideLimitedView': 'Masquer les places à visibilité réduite',\n};\n","/**\n * @seatlayer/core — the shared, framework-agnostic seat-rendering engine.\n *\n * Pure TypeScript + Konva (HTML canvas). No React, no framework. This is the\n * brain shared by the SeatLayer dashboard and every SDK wrapper. It is synced\n * byte-for-byte from the main app via `scripts/sync-core.mjs` until the app\n * migrates to consume this package directly.\n */\nexport * from './core/types';\nexport * from './core/layout';\nexport * from './core/ga';\nexport * from './core/sections';\nexport * from './engine/SeatmapRenderer';\nexport * from './picker/PickerController';\nexport * from './view/generatePanorama';\nexport * from './i18n';\nexport * from './i18n/bundles';\nexport * from './lib/money';\n","/**\n * SeatMap chart document — the single source of truth shared by the\n * Designer (authoring) and the Renderer (buyer picker).\n *\n * Coordinates are abstract units (roughly \"pixels at scale 1\"); the renderer\n * fits the chart to its container.\n * Rows are PARAMETRIC (origin + count + spacing + curve + rotation) — never\n * store per-seat coordinates in the document; expansion happens in layout.ts.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface CubicPath {\n start: Point;\n control1: Point;\n control2: Point;\n end: Point;\n}\n\n/** A real closed section boundary. `outline` remains its sampled collision and\n * persistence fallback; this path is the smooth authoring/buyer paint source. */\nexport type SectionPathSegment =\n | { kind: 'line'; end: Point }\n | { kind: 'arc'; center: Point; radius: number; clockwise: boolean; end: Point }\n | { kind: 'bezier'; control1: Point; control2: Point; end: Point };\n\nexport interface SectionOutlinePath {\n version: 1;\n closed: true;\n start: Point;\n segments: SectionPathSegment[];\n}\n\nexport interface Category {\n key: string;\n label: string;\n color: string;\n /** Base price — used when the category has no explicit tiers. */\n price?: number;\n /** Durable evidence for semantic/display facts proposed while converting a\n * private reference into sellable inventory. */\n referenceCategorySource?: ReferenceCategorySource;\n /**\n * Ticket tiers (Adult / Child / Senior…). When present, a buyer picks a tier\n * per seat in this category and the tier's price applies; the first tier is the\n * default. Per-category (not per-seat) pricing — see Batch 3.5. Empty/absent =\n * a single price (the `price` above).\n */\n tiers?: CategoryTier[];\n}\n\nexport interface ReferenceCategorySource {\n assetId: string;\n /** Original sampled section color. `Category.color` is the approved output\n * color and may differ only with separately recorded evidence. */\n sourceColor: string;\n /** Every exact sampled color normalized into the same original 4-bit/channel\n * segmentation class. Older documents may contain only `sourceColor`. */\n sourceColors?: string[];\n /** Logical sections whose generated inventory uses this category. */\n logicalSectionIds?: string[];\n /** Source-color grouping is deterministic; a semantic regrouping needs its\n * own confirmed assignment evidence. */\n assignmentDerivation?: 'source-color-class' | 'confirmed-logical-sections';\n assignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription?: string;\n /** Optional legend/commercial swatch stated by the source. This remains\n * immutable provenance when the approved accessible output color differs. */\n sourcePaletteColor?: string;\n sourcePaletteColorEvidence?: 'user-confirmed' | 'authoritative-source';\n sourcePaletteColorSourceDescription?: string;\n labelEvidence: 'user-confirmed' | 'authoritative-source';\n labelSourceDescription: string;\n priceEvidence: 'user-confirmed' | 'authoritative-source';\n priceSourceDescription: string;\n outputColorEvidence?: 'user-confirmed' | 'authoritative-source';\n outputColorSourceDescription?: string;\n}\n\n/** One ticket tier within a category: a named price (Adult, Child, Senior…). */\nexport interface CategoryTier {\n id: string;\n name: string;\n price: number;\n}\n\n/**\n * Accessibility accommodations a seat can carry. Mirrors the taxonomy real\n * venues (and seats.io) expose so buyers can filter for exactly what they need\n * and organizers can mark seats precisely. `wheelchair` is the legacy default.\n */\nexport type AccessibilityType =\n | 'wheelchair'\n | 'companion'\n | 'semi-ambulatory'\n | 'hearing'\n | 'sign-language'\n | 'plus-size'\n | 'lift-armrest';\n\nexport interface AccessibilityMeta {\n key: AccessibilityType;\n /** Full descriptive label (designer checkbox, picker legend). */\n label: string;\n /** Compact label for chips/badges. */\n short: string;\n /** Single-glyph badge shown on seat chips + filter chips. */\n icon: string;\n}\n\n/** Ordered taxonomy — drives the designer seat panel and the picker filters. */\nexport const ACCESSIBILITY_TYPES: AccessibilityMeta[] = [\n { key: 'wheelchair', label: 'Wheelchair space', short: 'Wheelchair', icon: '♿' },\n { key: 'companion', label: 'Companion seat', short: 'Companion', icon: '🧑🤝🧑' },\n { key: 'semi-ambulatory', label: 'Semi-ambulatory (limited mobility)', short: 'Limited mobility', icon: '🦯' },\n { key: 'hearing', label: 'Assistive listening', short: 'Hearing', icon: '🦻' },\n { key: 'sign-language', label: 'Sign-language view', short: 'Sign language', icon: '🤟' },\n { key: 'plus-size', label: 'Plus-size seat', short: 'Plus-size', icon: '💺' },\n { key: 'lift-armrest', label: 'Lift-up armrest', short: 'Lift armrest', icon: '↕️' },\n];\n\nconst ACCESSIBILITY_LABEL = new Map(ACCESSIBILITY_TYPES.map((a) => [a.key, a]));\n\n/** Metadata for one accessibility key (undefined for unknown keys). */\nexport function accessibilityMeta(key: AccessibilityType): AccessibilityMeta | undefined {\n return ACCESSIBILITY_LABEL.get(key);\n}\n\n/**\n * Outer-ring colour per accommodation. Shared by the buyer picker and the\n * designer canvas so an accessible seat reads with the same hue in both — the\n * seat's first-listed type wins. `wheelchair` blue is the default fallback.\n */\nexport const ACCESSIBILITY_RING_COLOR: Record<AccessibilityType, string> = {\n wheelchair: '#3b82f6',\n companion: '#8b5cf6',\n 'semi-ambulatory': '#0ea5e9',\n hearing: '#14b8a6',\n 'sign-language': '#f59e0b',\n 'plus-size': '#ec4899',\n 'lift-armrest': '#22c55e',\n};\n\n/** Ring colour for a seat's accessibility set (first-listed type wins). */\nexport function accessibilityRingColor(types: AccessibilityType[] | undefined): string {\n const primary = types?.[0];\n return (primary && ACCESSIBILITY_RING_COLOR[primary]) || '#3b82f6';\n}\n\nexport interface SeatOverride {\n /** 0-based seat index within the row. */\n index: number;\n /** Physical seat absent (pillar, sound desk) — numbering gap preserved. */\n skip?: boolean;\n /** Position nudge in chart units. */\n dx?: number;\n dy?: number;\n /** Replace the computed label entirely. */\n label?: string;\n /** Buyer-facing copy only. Booking/API identity remains row id + slot index\n * internally and the legacy `label` externally for backwards compatibility. */\n displayLabel?: string;\n categoryKey?: string;\n /** @deprecated legacy flag — read as `['wheelchair']`; write `accessibility`. */\n accessible?: boolean;\n /** Accessibility accommodations of this seat (empty/absent = none). */\n accessibility?: AccessibilityType[];\n /** Commercial selling/view attributes are deliberately not accessibility. */\n commercial?: SeatCommercialAttributes;\n /** Seat-specific view photo; falls back to the row photo. */\n viewFromSeatUrl?: string;\n /** Per-seat label size/color override; falls back to the row/theme default.\n * Size is clamped to LABEL_STYLE_MIN_SIZE..MAX_SIZE; color is passed through\n * the shared auto-contrast rule at paint time (see {@link LabelStyle}). */\n labelStyle?: LabelStyle;\n}\n\nexport interface SeatCommercialAttributes {\n restrictedView?: boolean;\n obstructedView?: boolean;\n premium?: boolean;\n note?: string;\n}\n\n/**\n * Per-object label ink + size overrides layered on top of the chart-wide Theme\n * defaults (rowLabelColor / textColor for rows, the section-name ink for\n * sections). Both fields are optional: an absent field means \"inherit the theme\n * default\". `color` is a preferred hex — renderers still pass it through the\n * shared auto-contrast rule (`stateAwareBookableLabelInk`), so a choice that\n * would be illegible over the seat/section background is switched to black or\n * white at paint time. `size` is a font size in chart units, clamped to\n * LABEL_STYLE_MIN_SIZE..LABEL_STYLE_MAX_SIZE by the shared ops.\n */\nexport interface LabelStyle {\n size?: number;\n color?: string;\n}\n\n/** Clamp bounds for a per-object label `size`, shared by ops, MCP, and UI. */\nexport const LABEL_STYLE_MIN_SIZE = 8;\nexport const LABEL_STYLE_MAX_SIZE = 24;\n\nexport interface LabelPresentation {\n visible?: boolean;\n /** Exact Designer-owned label anchor; public semantic MCP schemas omit it. */\n position?: Point;\n rotation?: number;\n style?: 'plain' | 'pill';\n /** Per-object size/color override for this row's or section's label. */\n labelStyle?: LabelStyle;\n}\n\n/** Brand/venue theming — applied by the renderer in both designer and picker. */\nexport interface ChartTheme {\n /** Canvas background color (default dark: #0e1117-ish radial). */\n background?: string;\n /** Preferred text color for the numbers inside seat markers. */\n seatLabelColor?: string;\n /** Preferred color for row identifiers such as A, B, C. Falls back to textColor. */\n rowLabelColor?: string;\n /** Selection ring / accent color (default white ring + brand accent). */\n selectionColor?: string;\n /** Décor (stage/shape) default fill. */\n decorFill?: string;\n /** Free-text color default. */\n textColor?: string;\n /** Font family (CSS stack) for all rendered text — row labels, seat numbers, sections, décor text. */\n fontFamily?: string;\n /** Seat size multiplier on the base radius (0.7–1.6, default 1) — bigger seats fit longer labels. */\n seatScale?: number;\n // ---- White-label branding (applied by the buyer picker chrome) ----\n /** Brand accent color — recolors buttons, links, the hold pill, selection UI. */\n accent?: string;\n /** Ink color for text on the accent (e.g. button labels). Default light. */\n accentInk?: string;\n /** Organizer logo shown in the picker header (data/R2 URL). Falls back to the name. */\n logoUrl?: string;\n /** Brand/venue name shown in the picker header when no event name is set. */\n brandName?: string;\n /** Paid-tier flag: hide the \"Powered by SeatMap\" badge. */\n hideBadge?: boolean;\n}\n\nexport interface RowObject {\n type: 'row';\n id: string;\n /** Row label, e.g. \"A\". Seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing row name. `label` remains the legacy inventory prefix. */\n displayLabel?: string;\n labelPresentation?: LabelPresentation;\n /** Position of the FIRST seat. */\n origin: Point;\n /** Degrees, clockwise. 0 = seats laid out along +x. */\n rotation: number;\n /**\n * Total arc sweep in degrees across the whole row. 0 = straight.\n * Positive bends away from +y (concave toward the focal point when the\n * row faces it). Typical theatre rows: 10–40.\n */\n curve: number;\n seatCount: number;\n /** Distance between adjacent seat centers, in chart units. */\n seatSpacing: number;\n /** Optional exact cubic centreline. Normal code owns these coordinates and\n * distributes seats by arc length; MCP/model inputs never submit them. */\n path?: CubicPath;\n categoryKey: string;\n /** Deterministic provenance for rows fitted from confirmed reference\n * inventory. It enables revision-safe replacement without touching manually\n * authored rows or accepting client coordinates. */\n referenceInventorySource?: ReferenceInventorySource;\n /** Semantic parameters for a row produced by the shared Arc/Fan operation.\n * Designer can reopen these parameters while every segment in the group\n * still carries the same generation signature. Public MCP tools never accept\n * the stored center/angles as arbitrary model-authored coordinates. */\n arcFanGeneration?: {\n kind: 'arc-fan-v1';\n groupId: string;\n center: Point;\n innerRadius: number;\n rowCount: number;\n rowGap: number;\n startAngle: number;\n endAngle: number;\n seatPitch: number;\n fit: 'seat-pitch' | 'fixed-count';\n seatsPerRow?: number;\n facing: 'inward' | 'outward';\n taperDegrees: number;\n skewDegrees: number;\n aisleGaps: { left: number; center: number; right: number };\n rowLabelStart: number;\n seatLabelStart: number;\n rowIndex: number;\n segmentIndex: number;\n };\n /** First seat number (default 1). */\n seatLabelStart?: number;\n /** Seat numbering within the row (default ltr, step 1). */\n seatNumbering?: {\n /** ltr / rtl number from an end; `center` numbers outward from the middle\n * (centre seat lowest — the premium-centre theatre convention). */\n direction: 'ltr' | 'rtl' | 'center';\n /** 2 = odd/even numbering (1,3,5… — start at 2 for evens). */\n step?: 1 | 2;\n };\n /**\n * Per-seat exceptions, keyed by seat index (0-based position in the row).\n * `skip` removes the physical seat but keeps the numbering gap (theatre\n * convention: a pillar eats A-3; A-4 stays A-4).\n */\n overrides?: SeatOverride[];\n /**\n * Organizer-supplied equirectangular 360 (or wide photo) shown as the\n * view-from-seat for every seat in this row. When absent, the picker\n * generates a synthetic panorama from chart geometry.\n */\n viewFromSeatUrl?: string;\n /** Default commercial attributes inherited by seats without an override. */\n commercial?: SeatCommercialAttributes;\n}\n\nexport interface GAAreaObject {\n type: 'gaArea';\n id: string;\n label: string;\n /** Closed polygon, in chart units. */\n points: Point[];\n /** Explicit aisles/pillars/cutouts excluded from the sellable GA surface. */\n holes?: Point[][];\n capacity: number;\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * Durable evidence link for sellable objects generated from a private reference.\n * The client supplies facts and stable logical-section ids, never coordinates.\n */\nexport interface ReferenceAccessibilitySource {\n placementDerivation: 'server-synthesized-row-edges';\n groupLogicalSectionIds: string[];\n assignmentEvidence: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription: string;\n counts: Array<{\n type: AccessibilityType;\n count: number;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n }>;\n}\n\nexport interface ReferenceInventorySource {\n assetId: string;\n logicalSectionId: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n /** Distinguishes directly supplied inventory from a user-approved server\n * distribution based only on an aggregate capacity. */\n derivation?: 'explicit-inventory' | 'server-synthesized-from-aggregate';\n /** Evidence for the aggregate figure; synthesized rows remain\n * `user-confirmed` and are never mislabeled as source-extracted. */\n aggregateEvidence?: 'user-confirmed' | 'authoritative-source';\n /** Separate evidence for assigning standing inventory to this logical\n * section. Aggregate evidence alone cannot prove section placement. */\n sectionAssignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n sectionAssignmentSourceDescription?: string;\n /** Aggregate row synthesis may propose numbering, but persistence requires\n * the applying user/agent to confirm that policy explicitly. */\n numberingEvidence?: 'user-confirmed';\n numberingSourceDescription?: string;\n /** Evidence and deterministic placement contract for synthesized accessible\n * units in this logical section. */\n accessibility?: ReferenceAccessibilitySource;\n}\n\n/** Durable evidence that a visible source-backed section shell intentionally\n * carries no generated sellable inventory in this reference configuration. */\nexport interface ReferenceInventoryExclusionSource {\n assetId: string;\n logicalSectionId: string;\n reason: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n}\n\n/** Non-bookable décor: stage, walls, exits. */\nexport interface ShapeObject {\n type: 'shape';\n id: string;\n kind: 'rect' | 'ellipse' | 'polygon';\n label?: string;\n /** For rect/ellipse: bounding box. For a stage polygon: the base (pre-shape) box, so its kind can be regenerated. */\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n /** For polygon. */\n points?: Point[];\n fill?: string;\n /** Degrees clockwise about the shape's center (default 0). Applied at render time. */\n rotation?: number;\n /**\n * Semantic tag driving special rendering. `'stage'` gets the gradient +\n * prominent uppercase label treatment; a décor landmark role (bar, exit…)\n * gets a quieter label. Loose string to avoid a circular import with\n * stage.ts / decor.ts (see StageKind / DecorRole there).\n */\n role?: string;\n /** For a stage: which `StageKind` its polygon was generated from. */\n stageKind?: string;\n}\n\n/** Seats arranged around a table; bookable per-seat or as a whole. */\nexport interface TableObject {\n type: 'table';\n id: string;\n /** e.g. \"T1\" — seat labels are `${label}-${n}`. */\n label: string;\n center: Point;\n shape: 'round' | 'rect';\n /** Seats around the perimeter (round) or along the enabled edges (rect). */\n seatCount: number;\n /** Rect tables: which edges get seats (default ['top','bottom']). */\n sides?: Array<'top' | 'bottom' | 'left' | 'right'>;\n rotation: number;\n /** Round tables. */\n radius?: number;\n /**\n * Round tables: the arc (in degrees) the seats occupy, default 360 (full\n * ring). Below 360 leaves an open side — e.g. a service gap for waiters, a\n * head table facing the room, or clearance against a wall. The opening is\n * centred on the `rotation` direction; seats spread across the rest.\n */\n seatArc?: number;\n /** Rect tables. */\n width?: number;\n height?: number;\n categoryKey: string;\n /** Whole-table booking: buyers get all seats or none (per-event override later). */\n bookAsWhole?: boolean;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/** A booth: one bookable unit rendered as a block (trade shows, VIP boxes). */\nexport interface BoothObject {\n type: 'booth';\n id: string;\n label: string;\n center: Point;\n width: number;\n height: number;\n rotation: number;\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * A named region of the venue (Balcony Left, Floor B…). Sections are outlines\n * only — objects belong to a section spatially (center inside the outline),\n * keeping the document flat (no nesting; simpler for tools and for AI edits).\n * Renderer: far zoom shows section shapes/labels instead of seats; clicking\n * a section zooms into it.\n */\nexport interface SectionObject {\n type: 'section';\n id: string;\n label: string;\n /** Buyer-facing section name; logical/id fields remain stable. */\n displayLabel?: string;\n labelPresentation?: LabelPresentation;\n /**\n * Stable management/inventory identity shared by disconnected visual\n * components of one logical section. When absent, `id` is the logical id.\n * Each component keeps its own `id` and reference provenance so rendering,\n * editing, measured diffs, and source restoration remain exact.\n */\n logicalSectionId?: string;\n /** Shared semantic Arc/Fan group wrapped by this section. The section id is\n * preserved when the fan parameters are reopened and regenerated. */\n arcFanGroupId?: string;\n /** Closed polygon, chart units. */\n outline: Point[];\n /** Optional true line/arc/cubic boundary. `outline` is a deterministic sample\n * of this path and remains authoritative for membership, validation, and\n * clients that predate curved section rendering. */\n outlinePath?: SectionOutlinePath;\n /** Explicit aisle/cutout polygons excluded from rendering, hit-testing, and membership. */\n holes?: Point[][];\n /** Durable opaque link to the private reference component. Unlike generator\n * provenance, this survives manual geometry edits so a measured diff can\n * report drift and server-owned code can restore the source contour. */\n referenceSource?: {\n assetId: string;\n regionId: string;\n };\n /** Evidence-backed reason this source section remains a visible shell without\n * synthesized sellable inventory (press, closed technical zone, etc.). */\n referenceInventoryExclusion?: ReferenceInventoryExclusionSource;\n /** Deterministic generator provenance for editable reference/parametric shells. */\n geometry?: {\n kind: 'rectangle' | 'tapered' | 'bezier' | 'contour';\n sourceRegionId?: string;\n contourMethod?: 'pixel-edge-loops-rdp' | 'shared-edge-vector-fit-v1';\n simplificationTolerancePx?: number;\n vectorFitErrorPx?: number;\n sharedEdgeCount?: number;\n };\n /** Optional tint override (defaults to a neutral fill / dominant category mix). */\n color?: string;\n /** Zone this section belongs to (id into `ChartDoc.zones`). Far-zoom nav + pricing group. */\n zone?: string;\n /**\n * Tier height. 0 = floor (default). Higher values lift the section in the\n * picker's isometric (\"3D\") view, drawn on extruded side faces. Same field a\n * future multi-floor mode reuses — authored in 2D, never drawn by the user.\n */\n elevation?: number;\n /** Uniform scale about the outline centroid (1 = as drawn). Scales members too. */\n scale?: number;\n /** 0–1: how strongly member-row curves are bent toward a common arc fitted to the outline. */\n smoothing?: number;\n /** Degrees clockwise about the outline centroid (default 0). Rotates members too. */\n rotation?: number;\n}\n\n/**\n * A group of sections (Lower Bowl, Upper Bowl, Floor…). One concept, three jobs:\n * the farthest-zoom navigation unit, a pricing group, and (Batch 3) a timed-\n * release unit. Kept as a flat list on the doc; sections point back by `zone` id.\n */\nexport interface ZoneDef {\n id: string;\n label: string;\n color?: string;\n}\n\n/**\n * Selection layer — a hit-test/dim filter in the designer, NOT z-order management.\n * Fixed set of four; derived from object type via `layerOf()` (no per-object field yet).\n */\nexport type SelectionLayer = 'interactive' | 'background' | 'foreground' | 'surroundings';\n\n/** Derive an object's selection layer from its type. */\nexport function layerOf(obj: ChartObject): SelectionLayer {\n switch (obj.type) {\n case 'row':\n case 'table':\n case 'gaArea':\n case 'booth':\n case 'section':\n return 'interactive';\n // stage / décor live on 'shape'; free text + decor images are background furniture.\n case 'shape':\n case 'text':\n case 'decorImage':\n return 'background';\n default:\n return 'interactive';\n }\n}\n\n/** Free-standing text on the chart (aisle names, door labels…). */\nexport interface TextObject {\n type: 'text';\n id: string;\n text: string;\n position: Point;\n fontSize: number;\n rotation: number;\n color?: string;\n}\n\n/**\n * A raster/vector decor graphic drawn IN the chart, beneath the seats and\n * sections (ice rink, basketball court, stage art, pitch markings). Purely\n * visual venue context — never bookable, never hit-tested, so it never steals a\n * seat click. `href` is a self-contained data URL (image or SVG) produced by the\n * same client-side downscale used for row photos, so it travels with the doc and\n * caches as a single bitmap blit (zero per-frame cost). Placed by top-left\n * (x,y) + size, rotated about its centre — the same handles a shape rect uses.\n */\nexport interface DecorImageObject {\n type: 'decorImage';\n id: string;\n /** Image or SVG data URL. */\n href: string;\n x: number;\n y: number;\n width: number;\n height: number;\n /** Degrees clockwise about the image centre (default 0). */\n rotation?: number;\n /** 0–1 (default 1). Multiplied by any chart-theme dimming at render time. */\n opacity?: number;\n /** Optional caption for the designer inspector / accessibility (not drawn). */\n label?: string;\n}\n\nexport type ChartObject =\n | RowObject\n | GAAreaObject\n | ShapeObject\n | TableObject\n | BoothObject\n | TextObject\n | SectionObject\n | DecorImageObject;\n\n/**\n * One floor / level of a multi-floor venue (Batch 5). Each floor owns its own\n * geometry, stage focal point, and trace image; categories/zones/tiers stay\n * chart-global (one event, one inventory). A single-floor chart has NO `floors`\n * — its `objects[]` is the whole venue — so all existing charts are untouched.\n */\nexport interface Floor {\n id: string;\n name: string;\n objects: ChartObject[];\n focalPoint: Point;\n backgroundImage?: ChartDoc['backgroundImage'];\n}\n\nexport interface ReferenceCalibration {\n type: 'two-point';\n /** Points in immutable source-image pixels, selected by a human or trusted detector. */\n sourceA: Point;\n sourceB: Point;\n /** Verified real-world distance between the two source points. */\n distance: number;\n unit: 'm' | 'ft' | 'chart-unit';\n /** Derived and stored for deterministic geometry compilers. */\n pixelsPerUnit: number;\n}\n\n/** Coordinate-free physical scale derived by server code from a confirmed\n * semantic feature. Unlike manual two-point calibration, no source points pass\n * through an MCP client or language model. */\nexport interface ReferenceDerivedScale {\n method: 'confirmed-focal-axis-v1';\n feature: 'focal-long-axis' | 'focal-short-axis';\n distance: number;\n unit: 'm' | 'ft';\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n chartUnitsPerUnit: number;\n}\n\nexport interface ChartReferenceImage {\n /** Stable private reference asset. New cloud-authored charts use this. */\n assetId?: string;\n /** Legacy/self-contained source. Optional when assetId is present. */\n url?: string;\n center: Point;\n /** Rendered width in chart units (height follows the cropped image aspect). */\n width: number;\n opacity: number;\n rotation?: number;\n visible?: boolean;\n layer?: 'below' | 'above';\n locked?: boolean;\n /** Normalized source crop; defaults to the full image. */\n crop?: { x: number; y: number; width: number; height: number };\n calibration?: ReferenceCalibration;\n /** Server-derived semantic calibration without source-image coordinates. */\n derivedScale?: ReferenceDerivedScale;\n}\n\nexport interface ChartDoc {\n version: 1;\n name: string;\n venueType: 'SIMPLE' | 'MIXED';\n /** The stage / point every seat looks at. Anchors seat-view + sightlines.\n * Multi-floor: mirrors floor 0; each floor also carries its own focalPoint. */\n focalPoint: Point;\n categories: Category[];\n /** Section groupings for far-zoom navigation + pricing (optional; sections reference by id). */\n zones?: ZoneDef[];\n /** Multi-floor venues (Batch 5): present ⇒ floors[] is the source of truth;\n * absent ⇒ single-floor and `objects` below is the whole chart. `objects`\n * is kept mirroring floor 0 so single-floor readers never branch. */\n floors?: Floor[];\n objects: ChartObject[];\n /** Floor-plan photo the organizer traces over (designer-only aid, also rendered dimly in picker if kept). */\n backgroundImage?: ChartReferenceImage;\n /** Brand/venue theming (colors); categories carry their own colors separately. */\n theme?: ChartTheme;\n /** Parametric-template provenance: present ⇒ the chart came from a capacity-\n * adjustable template family, and the designer offers a capacity control that\n * regenerates it at a new target seat count (Batch 4 \"curated singles + resize\"). */\n template?: { family: string; targetSeats: number };\n}\n\n// ---------------------------------------------------------------------------\n// Expanded (render-time) model — produced by layout.ts, consumed by the engine\n// ---------------------------------------------------------------------------\n\nexport interface ExpandedSeat {\n /** Stable id: `${rowId}:${index}` */\n id: string;\n /** Public label: `${rowLabel}-${seatNumber}` */\n label: string;\n /** Buyer-facing copy; absent on legacy charts, where `label` is displayed. */\n displayLabel?: string;\n x: number;\n y: number;\n rowId: string;\n categoryKey: string;\n /** 'booth' units render as blocks (dimensions looked up via rowId = booth id). */\n kind?: 'seat' | 'booth';\n /** True when the seat has any accessibility accommodation — renderer rings/dims these. */\n accessible?: boolean;\n /** Specific accessibility accommodations (absent = none) — picker badges/filters these. */\n accessibility?: AccessibilityType[];\n commercial?: SeatCommercialAttributes;\n /** Organizer-supplied view-from-seat image (inherited from the row). */\n viewUrl?: string;\n /** Per-seat label size/color override; absent = inherit the row/theme default. */\n labelStyle?: LabelStyle;\n}\n\nexport type SeatStatus = 'free' | 'held' | 'booked' | 'not_for_sale';\n\n// ---------------------------------------------------------------------------\n// Renderer engine public API — implemented in src/engine/SeatmapRenderer.ts\n// ---------------------------------------------------------------------------\n\nexport interface RendererCallbacks {\n onSelect?: (seat: ExpandedSeat) => void;\n onDeselect?: (seat: ExpandedSeat) => void;\n /** Buyer tried to add a seat after the active selection cap was reached. */\n onSelectionLimit?: (maxSelection: number) => void;\n /** seat is null when the pointer leaves any seat. */\n onHover?: (seat: ExpandedSeat | null) => void;\n /** Keyboard focus moved to a seat (arrow-key navigation) — for screen-reader announcements. */\n onFocusSeat?: (seat: ExpandedSeat | null) => void;\n /** Called ~1×/sec with the measured frames-per-second. */\n onFps?: (fps: number) => void;\n /** Fired when a GA area is clicked (quantity picking is UI-side). */\n onGAClick?: (areaId: string) => void;\n /**\n * Fired when a tap lands on a section outline while seats are NOT the active\n * rung (i.e. zoomed out, section/zone LOD). The host glides in + shows a\n * section-summary card instead of trying to select a 4px seat (Slice 5).\n */\n onSectionTap?: (sectionId: string) => void;\n /**\n * Fired when a seat/deck is tapped in the 3D all-floors stacked overview — the\n * host drops back to the flat 2D map on that floor (\"tap a deck to enter\").\n */\n onDeckTap?: (floorId: string) => void;\n /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */\n onViewChange?: () => void;\n /**\n * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on\n * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,\n * with the FULL current selection (selectable seats only). The host toolbar\n * reads this to drive bulk block/unblock. Never fires when manageMode is off.\n */\n onMarquee?: (seats: ExpandedSeat[]) => void;\n}\n\n/** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */\nexport type LodRung = 'zones' | 'sections' | 'seats';\n\nexport interface RendererOptions extends RendererCallbacks {\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** Only these statuses are clickable (default ['free']). */\n selectableStatuses?: SeatStatus[];\n /**\n * Opt-in host behaviour flag — the renderer's own click/selection logic is\n * unchanged (it still selects + fires `onSelect` immediately, so the seat\n * highlights right away). When true, the host (e.g. PublicEventPage) treats\n * that `onSelect` as a pending candidate and shows a confirm card instead of\n * pushing straight into the cart; `deselect([seat.id])` on Cancel un-highlights.\n */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (\"FROM …\"); defaults to money.DEFAULT_CURRENCY.\n * Locale for grouping/symbol placement comes from the active i18n locale. */\n currency?: string;\n /**\n * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode\n * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /\n * pinch / tap and every existing code path are byte-identical when this is\n * false (every manage branch is gated on it). Default false.\n */\n manageMode?: boolean;\n /**\n * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung\n * draws a rubber-band marquee that bulk-selects the seats it covers (emitting\n * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger\n * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below\n * the seats rung (zoom in first). No effect unless `manageMode` is also set.\n */\n marqueeSelect?: boolean;\n}\n\nexport type RenderedLabelHiddenReason =\n | 'below-minimum-size'\n | 'outside-viewport'\n | 'dimmed-or-unavailable'\n | 'clutter-or-fit'\n | 'renderer-hidden';\n\n/** Browser-renderer evidence used by visual QA and catalog release gates. */\nexport interface RenderedBookableLabelEvidence {\n seatId: string;\n label: string;\n kind: 'seat' | 'booth';\n categoryKey: string;\n sectionId?: string;\n zoneId?: string;\n status: SeatStatus;\n selected: boolean;\n visible: boolean;\n renderedFontPx: number;\n fill: string;\n ink: string;\n opacity: number;\n /** Direct Konva shape bounds and the production near-miss rescue combined. */\n pointerTarget: {\n active: boolean;\n directWidthPx: number;\n directHeightPx: number;\n effectiveMinimumPx: number;\n };\n /** Centre of the painted unit, even when its text is intentionally hidden. */\n screenCenter: { x: number; y: number };\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: RenderedLabelHiddenReason;\n}\n\nexport interface RenderedHierarchyLabelEvidence {\n id: string;\n kind: 'section' | 'zone';\n role: 'name' | 'availability' | 'price';\n label: string;\n visible: boolean;\n renderedFontPx: number;\n opacity: number;\n fill: string;\n ink: string;\n /** Independent geometric containment check for section-owned text. */\n fitsContainer?: boolean;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RenderedFreeTextEvidence {\n objectId: string;\n kind: 'free-text' | 'stage' | 'table' | 'decor' | 'ga-label' | 'ga-capacity';\n text: string;\n visible: boolean;\n renderedFontPx: number;\n ink: string;\n background: string;\n opacity: number;\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden';\n}\n\nexport interface RenderedGAAreaEvidence {\n areaId: string;\n label: string;\n capacity: number;\n categoryKey: string;\n /** Owning logical section when the rendered GA surface is section-contained. */\n sectionId?: string;\n visible: boolean;\n interactive: boolean;\n opacity: number;\n fill: string;\n effectiveBackground: string;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RendererQualityEvidence {\n viewport: { width: number; height: number };\n canvasBackground: string;\n effectiveScale: number;\n rung: LodRung;\n minimumVisibleLabelPx: number;\n totalLabelledBookableUnits: number;\n visibleLabels: number;\n hiddenLabels: number;\n /** Seats/table-seats/booths plus the full GA capacity. */\n totalBookableUnits: number;\n selectionRingSeatIds: string[];\n selectionRingColor: string;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n /** Exact scene-graph proof for the clean section-first overview contract. */\n overviewStyle: {\n visibleSectionShells: number;\n categoryPaintedSectionShells: number;\n visibleCategoryDetailOutlines: number;\n visibleSectionRowHints: number;\n visibleSectionAvailabilityLabels: number;\n visibleSectionGADetails: number;\n };\n labels: RenderedBookableLabelEvidence[];\n gaAreas: RenderedGAAreaEvidence[];\n hierarchyLabels: RenderedHierarchyLabelEvidence[];\n freeTextLabels: RenderedFreeTextEvidence[];\n}\n\nexport interface ISeatmapRenderer {\n /** Replace the chart. Resets selection and statuses, zooms to fit.\n * `opts.floorId` picks which floor to render on a multi-floor chart (Batch 5). */\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void;\n /** Bulk status update; re-renders affected seats only. */\n setStatus(seatIds: string[], status: SeatStatus): void;\n /**\n * Mark the active buyer's own held seats. They remain server-status `held`,\n * but render with the buyer selection treatment instead of the anonymous\n * unavailable treatment used for another buyer's hold.\n */\n setOwnedHold?(seatIds: string[] | null): void;\n /**\n * Mark one selected seat as the buyer's pending confirmation candidate.\n * The candidate receives a strong focus halo while unrelated seats recede;\n * pass null after Select/Cancel. This is visual only and never mutates the\n * renderer selection.\n */\n setSelectionFocus?(seatId: string | null): void;\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()\n * (used by setStatus and friends) schedules the actual paint on the next rAF\n * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded\n * tabs — so a seat-status delta updates the scene graph but the pixels never\n * change until the tab is foregrounded again. forceDraw() paints the affected\n * layers immediately (Layer.draw() is synchronous) and flushes any pending\n * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in\n * always-live board) can guarantee the canvas reflects current state\n * regardless of tab visibility. No-op difference in the foreground.\n */\n forceDraw(): void;\n getStatus(seatId: string): SeatStatus;\n getSelection(): ExpandedSeat[];\n clearSelection(): void;\n /** Update the buyer selection cap without rebuilding the chart or camera. */\n setMaxSelection?(maxSelection: number): void;\n /**\n * Programmatically restore free seats (for example an Undo action). Added\n * seats respect the active cap and do not reopen a confirmation popover.\n */\n select?(seatIds: string[]): ExpandedSeat[];\n /**\n * Dynamically update organizer-only interaction without rebuilding the\n * renderer. No buyer surface calls this; every behavior remains gated by\n * `manageMode` exactly as it is at construction time.\n */\n setManageInteraction?(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void;\n /** Organizer-only section heat overlay. Values are normalized 0..1. */\n setSectionHeat?(scores: Record<string, number> | null): void;\n /**\n * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).\n * They select the matching SELECTABLE seats (respecting `selectableStatuses`\n * + closed sections), union with the current selection, and return the seats\n * they added — the SDK SeatManager expands category/row/section picks to\n * labels and drives one batched block/unblock from them.\n */\n selectAllSelectable?(): ExpandedSeat[];\n selectByLabels?(labels: string[]): ExpandedSeat[];\n /** Exact-render QA only: select one server-chosen unit without label ambiguity. */\n setEvidenceSelection?(seatId: string): boolean;\n /** Selectable seats belonging to a section OR zone id (no selection side-effect). */\n getSelectableInSection?(sectionId: string): ExpandedSeat[];\n /** Programmatic deselect of specific seats (e.g. chip × in the cart). */\n deselect(seatIds: string[]): void;\n /**\n * Brief attention pulse on a seat (a ring that expands + fades once) — used to\n * signal live activity, e.g. a seat \"just taken\" by another buyer via a WS\n * delta. Purely visual; no state change. `color` overrides the default.\n */\n flashSeat(seatId: string, color?: string): void;\n /**\n * Brief organizer attention pulse around a whole section. This is a visual\n * overlay only: it never changes section geometry, hit targets, selection, or\n * the active camera. Useful for grouped realtime operations at venue overview.\n */\n flashSection?(sectionId: string, color?: string): void;\n zoomToFit(): void;\n /** Zoom in one step about the viewport center, clamped to the usual zoom bounds. */\n zoomIn(): void;\n /** Zoom out one step about the viewport center, clamped to the usual zoom bounds. */\n zoomOut(): void;\n /** Individually status-managed seats/table-seats/booths; excludes GA capacity. */\n seatCount(): number;\n /** Seats/table-seats/booths plus the full capacity of rendered GA areas. */\n bookableCount(): number;\n /**\n * Maps a chart-space point (or a seat, by its x/y) to container-relative\n * screen pixels, using the current stage scale/position. Lets host UI anchor\n * DOM overlays (confirm card, tooltip) over a live seat and re-anchor them\n * on `onViewChange`.\n */\n worldToScreen(point: Point): { x: number; y: number };\n /** When on, dim non-accessible free seats so accessible seats stand out. */\n setAccessibleFilter(on: boolean): void;\n /**\n * Dim free seats that lack ANY of these accessibility types. `null` clears the\n * filter; `[]` means \"any accessible seat\" (same as setAccessibleFilter(true)).\n */\n setAccessibilityFilter(types: AccessibilityType[] | null): void;\n /** Legend hover-highlight: dim free seats of other categories (null clears). */\n setCategoryHighlight?(key: string | null): void;\n /** Price-band filter (F4): dim free seats whose category is NOT in `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter?(keys: string[] | null): void;\n /** Smoothly frame the currently available seats in these categories. `null`\n * returns to the full chart. Used after an explicit buyer price-filter action. */\n focusCategories?(keys: string[] | null): void;\n /** Dim the seats of these section/zone ids (organizer manager: held-back inventory). */\n setDimmedSections?(ids: string[] | null): void;\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, section stays rendered.\n * `null`/empty clears. (Distinct from the buyer's applyHidden seat-strip.)\n */\n setClosedSections?(ids: string[] | null): void;\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * behind this section, and glide the camera to frame it. Seat-picking is gated\n * until seats are large enough on screen (≥ LABEL_SCALE). Slice 5 / Phase 2 §4.\n */\n focusSection?(id: string): void;\n /** Clear an AXS section focus (restore full-bowl brightness + drop backdrop). */\n clearSectionFocus?(): void;\n /** The currently AXS-focused section id, or null. */\n getFocusedSection?(): string | null;\n /** World-space rect currently visible in the viewport (minimap viewport frame). */\n getVisibleWorldRect?(): { x: number; y: number; width: number; height: number };\n /** Axis-aligned world bounds of all seats + section outlines (minimap frame). */\n getWorldBounds?(): { x: number; y: number; width: number; height: number };\n /**\n * Colorblind-safe mode: category hues switch to an Okabe-Ito palette and\n * booked seats render hollow (a non-color cue), so seat state never relies\n * on hue alone. Off (the default) renders exactly as before.\n */\n setColorblindSafe?(on: boolean): void;\n /**\n * Switch the projection. `'flat'` = normal top-down; `'isometric'` = the \"3D\"\n * view (affine skew/rotate + elevation lift), hit-testing preserved in screen\n * space. Purely visual — the chart is authored flat. Animated unless reduced-motion.\n */\n setViewMode?(mode: 'flat' | 'isometric'): void;\n /** Current projection (defaults to 'flat' when unimplemented). */\n getViewMode?(): 'flat' | 'isometric';\n /** Multi-floor (Batch 5): switch the shown floor; list floors; read the active id. */\n setActiveFloor?(floorId: string): void;\n getFloors?(): { id: string; name: string }[];\n getActiveFloorId?(): string;\n /** Render all floors stacked (3D overview) vs the active floor. No-op single-floor. */\n setStacked?(on: boolean): void;\n isStacked?(): boolean;\n /**\n * Section id whose outline contains a container-relative screen point (or null).\n * Feeds the far-zoom \"tap a section to zoom in\" flow (Slice 5).\n */\n sectionAt?(clientPoint: Point): string | null;\n /** Seat ids belonging to a section — for the section-summary card (Slice 5). */\n sectionMembers?(id: string): string[];\n /**\n * Smoothly glide (pan+zoom) the camera to frame a section (by id) or a world-\n * space bounds rect over a calm easeInOutCubic glide. `prefers-reduced-motion` snaps.\n * A pointer-down (grab/pan) cancels an in-flight glide. Slice 5 \"glide in\".\n */\n focusRegion?(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void;\n /** Current LOD rung derived from zoom (for the ZONES/SECTIONS/SEATS pill). */\n getRung?(): LodRung;\n /** Jump the camera to a rung's zoom band, centred on the chart (glided). */\n setRung?(rung: LodRung): void;\n /** Read actual browser-rendered label visibility, size, fill, ink and state.\n * Pure diagnostic: it never changes chart or renderer state. */\n getRenderedQualityEvidence(): RendererQualityEvidence;\n destroy(): void;\n}\n\n/** localStorage key the Designer writes and the Picker reads. */\nexport const CHART_STORAGE_KEY = 'seatmap.chart';\n","import type { CubicPath, Point } from './types';\n\nexport type SectionShellMode = 'auto' | 'rectangle' | 'tapered' | 'bezier';\n\nexport function cubicPoint(path: CubicPath, t: number): Point {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n return {\n x: a * path.start.x + b * path.control1.x + c * path.control2.x + d * path.end.x,\n y: a * path.start.y + b * path.control1.y + c * path.control2.y + d * path.end.y,\n };\n}\n\n/** Equal-arc-length points on a cubic path, including both endpoints. */\nexport function distributeAlongCubic(path: CubicPath, count: number, resolution = 192): Point[] {\n if (!Number.isInteger(count) || count < 1) throw new Error('Path point count must be a positive integer');\n if (count === 1) return [cubicPoint(path, 0.5)];\n const samples = Array.from({ length: resolution + 1 }, (_, index) => cubicPoint(path, index / resolution));\n const lengths = new Float64Array(samples.length);\n for (let index = 1; index < samples.length; index += 1) {\n const dx = samples[index].x - samples[index - 1].x;\n const dy = samples[index].y - samples[index - 1].y;\n lengths[index] = lengths[index - 1] + Math.hypot(dx, dy);\n }\n const total = lengths[lengths.length - 1];\n if (total <= 1e-9) return Array.from({ length: count }, () => ({ ...path.start }));\n const output: Point[] = [];\n let segment = 1;\n for (let index = 0; index < count; index += 1) {\n const target = (total * index) / (count - 1);\n while (segment < lengths.length - 1 && lengths[segment] < target) segment += 1;\n const before = lengths[segment - 1];\n const after = lengths[segment];\n const ratio = after === before ? 0 : (target - before) / (after - before);\n output.push({\n x: samples[segment - 1].x + (samples[segment].x - samples[segment - 1].x) * ratio,\n y: samples[segment - 1].y + (samples[segment].y - samples[segment - 1].y) * ratio,\n });\n }\n return output;\n}\n\nfunction add(a: Point, b: Point): Point { return { x: a.x + b.x, y: a.y + b.y }; }\nfunction sub(a: Point, b: Point): Point { return { x: a.x - b.x, y: a.y - b.y }; }\nfunction mul(a: Point, scale: number): Point { return { x: a.x * scale, y: a.y * scale }; }\nfunction distance(a: Point, b: Point): number { return Math.hypot(a.x - b.x, a.y - b.y); }\nfunction lerp(a: Point, b: Point, t: number): Point { return add(a, mul(sub(b, a), t)); }\n\nfunction sample(path: CubicPath, count = 13): Point[] {\n return Array.from({ length: count }, (_, index) => cubicPoint(path, index / (count - 1)));\n}\n\nfunction pointOnSampledPath(points: Point[], t: number): Point {\n const scaled = Math.max(0, Math.min(1, t)) * (points.length - 1);\n const index = Math.min(points.length - 2, Math.floor(scaled));\n return lerp(points[index], points[index + 1], scaled - index);\n}\n\nfunction sampledPathSegment(points: Point[], from: number, to: number): Point[] {\n const start = Math.max(0, Math.min(1, from));\n const end = Math.max(start, Math.min(1, to));\n const output = [pointOnSampledPath(points, start)];\n for (let index = 1; index < points.length - 1; index += 1) {\n const t = index / (points.length - 1);\n if (t > start + 1e-9 && t < end - 1e-9) output.push(points[index]);\n }\n output.push(pointOnSampledPath(points, end));\n return output;\n}\n\ninterface SectionFrame {\n p0: Point;\n p1: Point;\n p2: Point;\n p3: Point;\n normal: Point;\n depth: number;\n}\n\nfunction orientSectionFrame(corners: Point[], focal: Point): SectionFrame {\n const edges: Array<[number, number]> = [[0, 1], [1, 2], [2, 3], [3, 0]];\n let nearEdge = 0;\n let nearDistance = Number.POSITIVE_INFINITY;\n edges.forEach(([a, b], index) => {\n const d = distance(lerp(corners[a], corners[b], 0.5), focal);\n if (d < nearDistance) {\n nearDistance = d;\n nearEdge = index;\n }\n });\n const p0 = corners[nearEdge];\n const p1 = corners[(nearEdge + 1) % 4];\n const p2 = corners[(nearEdge + 2) % 4];\n const p3 = corners[(nearEdge + 3) % 4];\n const nearMid = lerp(p0, p1, 0.5);\n const inward = sub(focal, nearMid);\n const inwardLength = Math.max(1e-9, Math.hypot(inward.x, inward.y));\n return {\n p0,\n p1,\n p2,\n p3,\n normal: mul(inward, 1 / inwardLength),\n depth: (distance(p0, p3) + distance(p1, p2)) / 2,\n };\n}\n\nfunction bezierSectionPaths(frame: SectionFrame): { nearPath: CubicPath; farPath: CubicPath } {\n const { p0, p1, p2, p3, normal, depth } = frame;\n const nearSpan = sub(p1, p0);\n const farSpan = sub(p2, p3);\n const nearCurve = depth * 0.22;\n const farCurve = depth * 0.12;\n return {\n nearPath: {\n start: p0,\n control1: add(add(p0, mul(nearSpan, 1 / 3)), mul(normal, nearCurve)),\n control2: add(add(p0, mul(nearSpan, 2 / 3)), mul(normal, nearCurve)),\n end: p1,\n },\n farPath: {\n start: p2,\n control1: add(add(p3, mul(farSpan, 2 / 3)), mul(normal, farCurve)),\n control2: add(add(p3, mul(farSpan, 1 / 3)), mul(normal, farCurve)),\n end: p3,\n },\n };\n}\n\n/**\n * Convert a server-mapped rectangle into an editable complex shell. The four\n * corners must be clockwise. No caller-supplied control points are accepted.\n */\nexport function buildSectionShell(corners: Point[], focal: Point, requested: SectionShellMode): {\n mode: Exclude<SectionShellMode, 'auto'>;\n outline: Point[];\n} {\n if (corners.length !== 4) throw new Error('A section shell requires four mapped bounds corners');\n const center = corners.reduce((sum, point) => add(sum, point), { x: 0, y: 0 });\n center.x /= 4;\n center.y /= 4;\n const width = distance(corners[0], corners[1]);\n const height = distance(corners[0], corners[3]);\n const mode = requested === 'auto'\n ? (width > height * 1.25 && distance(center, focal) > height ? 'bezier' : 'tapered')\n : requested;\n if (mode === 'rectangle') return { mode, outline: corners.map((point) => ({ ...point })) };\n\n // Rotate corners so local p0→p1 is the edge nearest the focal point and\n // p3→p2 is the far edge, while preserving clockwise winding.\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n\n if (mode === 'tapered') {\n const inset = 0.14;\n return {\n mode,\n outline: [\n add(p0, mul(sub(p1, p0), inset)),\n add(p0, mul(sub(p1, p0), 1 - inset)),\n p2,\n p3,\n ],\n };\n }\n\n const { nearPath, farPath } = bezierSectionPaths(frame);\n return { mode, outline: [...sample(nearPath), ...sample(farPath).slice(1)] };\n}\n\n/** Server-owned straight aisle cutouts spanning the near/far edges. */\nexport function buildAisleHoles(\n corners: Point[],\n focal: Point,\n count: number,\n mode: Exclude<SectionShellMode, 'auto'>,\n): Point[][] {\n if (corners.length !== 4) throw new Error('Aisle generation requires four mapped bounds corners');\n if (!Number.isInteger(count) || count < 0 || count > 3) throw new Error('Aisle count must be an integer from 0 to 3');\n if (count === 0) return [];\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n const paths = mode === 'bezier' ? bezierSectionPaths(frame) : null;\n // For curved shells, interpolate the same sampled polylines stored in the\n // document. Exact cubic points between samples can sit fractionally outside\n // their chord approximation and fail topology validation/hit clipping.\n const nearSamples = paths ? sample(paths.nearPath) : null;\n const farLateralSamples = paths ? sample(paths.farPath).reverse() : null;\n const widthFraction = Math.min(0.055, 0.18 / (count + 1));\n return Array.from({ length: count }, (_, index) => {\n const t = (index + 1) / (count + 1);\n const left = t - widthFraction / 2;\n const right = t + widthFraction / 2;\n if (nearSamples && farLateralSamples) {\n return [\n ...sampledPathSegment(nearSamples, left, right),\n ...sampledPathSegment(farLateralSamples, left, right).reverse(),\n ];\n }\n return [lerp(p0, p1, left), lerp(p0, p1, right), lerp(p3, p2, right), lerp(p3, p2, left)];\n });\n}\n","import type { Point, SectionOutlinePath, SectionPathSegment } from './types';\n\nconst TAU = Math.PI * 2;\n\nfunction finitePoint(point: Point): boolean {\n return Number.isFinite(point.x) && Number.isFinite(point.y);\n}\n\nfunction distance(left: Point, right: Point): number {\n return Math.hypot(left.x - right.x, left.y - right.y);\n}\n\nfunction arcSweep(start: number, end: number, clockwise: boolean): number {\n let delta = end - start;\n if (clockwise) {\n while (delta < 0) delta += TAU;\n while (delta >= TAU) delta -= TAU;\n } else {\n while (delta > 0) delta -= TAU;\n while (delta <= -TAU) delta += TAU;\n }\n return delta;\n}\n\nexport function sectionPathSegmentEnd(segment: SectionPathSegment): Point {\n return segment.end;\n}\n\n/** Validate finite, continuous closed-path geometry without trusting renderer\n * behaviour. Arc endpoints must lie on their declared circle. */\nexport function validSectionOutlinePath(path: SectionOutlinePath): boolean {\n if (path.version !== 1 || path.closed !== true || !finitePoint(path.start)\n || !Array.isArray(path.segments) || path.segments.length < 2 || path.segments.length > 512) return false;\n let current = path.start;\n for (const segment of path.segments) {\n if (!segment || !finitePoint(segment.end)) return false;\n if (segment.kind === 'line') {\n if (distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'bezier') {\n if (!finitePoint(segment.control1) || !finitePoint(segment.control2)\n || distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'arc') {\n if (!finitePoint(segment.center) || !Number.isFinite(segment.radius) || segment.radius <= 1e-6\n || Math.abs(distance(current, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || Math.abs(distance(segment.end, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || distance(current, segment.end) <= 1e-9) return false;\n } else return false;\n current = segment.end;\n }\n return distance(current, path.start) <= 1e-4;\n}\n\nfunction cubicPoint(start: Point, segment: Extract<SectionPathSegment, { kind: 'bezier' }>, t: number): Point {\n const mt = 1 - t;\n return {\n x: mt ** 3 * start.x + 3 * mt ** 2 * t * segment.control1.x\n + 3 * mt * t ** 2 * segment.control2.x + t ** 3 * segment.end.x,\n y: mt ** 3 * start.y + 3 * mt ** 2 * t * segment.control1.y\n + 3 * mt * t ** 2 * segment.control2.y + t ** 3 * segment.end.y,\n };\n}\n\n/** Deterministic polygon sample used by validation, hit testing, diff, and old\n * clients. The returned loop omits the duplicate closing point. */\nexport function sampleSectionOutlinePath(path: SectionOutlinePath, maxStep = 2): Point[] {\n if (!validSectionOutlinePath(path)) throw new Error('Section outline path is invalid');\n const step = Math.max(0.25, maxStep);\n const points: Point[] = [{ ...path.start }];\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') {\n points.push({ ...segment.end });\n } else if (segment.kind === 'arc') {\n const startAngle = Math.atan2(current.y - segment.center.y, current.x - segment.center.x);\n const endAngle = Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x);\n const sweep = arcSweep(startAngle, endAngle, segment.clockwise);\n const count = Math.max(2, Math.ceil(Math.abs(sweep) * segment.radius / step));\n for (let index = 1; index <= count; index += 1) {\n const angle = startAngle + sweep * index / count;\n points.push({\n x: segment.center.x + Math.cos(angle) * segment.radius,\n y: segment.center.y + Math.sin(angle) * segment.radius,\n });\n }\n } else {\n const controlLength = distance(current, segment.control1)\n + distance(segment.control1, segment.control2)\n + distance(segment.control2, segment.end);\n const count = Math.max(2, Math.ceil(controlLength / step));\n for (let index = 1; index <= count; index += 1) points.push(cubicPoint(current, segment, index / count));\n }\n current = segment.end;\n }\n if (distance(points[points.length - 1], points[0]) <= 1e-4) points.pop();\n return points;\n}\n\nexport function translateSectionOutlinePath(path: SectionOutlinePath, dx: number, dy: number): SectionOutlinePath {\n const translate = (point: Point): Point => ({ x: point.x + dx, y: point.y + dy });\n return transformSectionOutlinePath(path, translate);\n}\n\n/** Apply a similarity transform. Callers provide the point transform and the\n * absolute radius scale; reflections toggle arc direction. */\nexport function transformSectionOutlinePath(\n path: SectionOutlinePath,\n transform: (point: Point) => Point,\n radiusScale = 1,\n reflected = false,\n): SectionOutlinePath {\n return {\n ...path,\n start: transform(path.start),\n segments: path.segments.map((segment) => segment.kind === 'line'\n ? { ...segment, end: transform(segment.end) }\n : segment.kind === 'arc'\n ? {\n ...segment,\n center: transform(segment.center),\n radius: segment.radius * Math.abs(radiusScale),\n clockwise: reflected ? !segment.clockwise : segment.clockwise,\n end: transform(segment.end),\n }\n : {\n ...segment,\n control1: transform(segment.control1),\n control2: transform(segment.control2),\n end: transform(segment.end),\n }),\n };\n}\n\n/** Reverse a closed path without changing its painted boundary. */\nexport function reverseSectionOutlinePath(path: SectionOutlinePath): SectionOutlinePath {\n const starts: Point[] = [];\n let current = path.start;\n for (const segment of path.segments) {\n starts.push(current);\n current = segment.end;\n }\n const segments: SectionPathSegment[] = [];\n for (let index = path.segments.length - 1; index >= 0; index -= 1) {\n const segment = path.segments[index];\n const end = starts[index];\n if (segment.kind === 'line') segments.push({ kind: 'line', end: { ...end } });\n else if (segment.kind === 'arc') segments.push({\n kind: 'arc', center: { ...segment.center }, radius: segment.radius,\n clockwise: !segment.clockwise, end: { ...end },\n });\n else segments.push({\n kind: 'bezier', control1: { ...segment.control2 }, control2: { ...segment.control1 }, end: { ...end },\n });\n }\n return { version: 1, closed: true, start: { ...path.start }, segments };\n}\n","/**\n * Pure geometry helpers — no Konva, no DOM. Turns the parametric chart\n * document into concrete seat coordinates and computes bounding boxes.\n */\n\nimport type {\n AccessibilityType,\n BoothObject,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n Floor,\n LabelStyle,\n Point,\n RowObject,\n SeatOverride,\n TableObject,\n} from './types';\nimport { distributeAlongCubic } from './complexGeometry';\nimport { translateSectionOutlinePath } from './sectionPath';\n\n/** Resolve a seat override's accessibility, honouring the legacy boolean flag. */\nfunction overrideAccessibility(o: SeatOverride | undefined): AccessibilityType[] {\n if (!o) return [];\n if (o.accessibility && o.accessibility.length) return o.accessibility;\n return o.accessible ? ['wheelchair'] : [];\n}\n\nconst DEG = Math.PI / 180;\n/** Seat visual radius (mirrors the renderer) — used only for bounds padding. */\nconst SEAT_R = 9;\n/** How far outside a table's body its seats sit. */\nconst TABLE_SEAT_OFFSET = 16;\n\n/** Rotate a local point clockwise by `deg` (screen coords, +y down) then translate. */\nfunction place(lx: number, ly: number, deg: number, origin: Point): { x: number; y: number } {\n const a = deg * DEG;\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n return {\n x: origin.x + lx * cos - ly * sin,\n y: origin.y + lx * sin + ly * cos,\n };\n}\n\n/**\n * Expand a parametric row into seat positions.\n *\n * Straight (curve === 0): seat i sits at local (i·spacing, 0).\n *\n * Curved: seats lie on a circular arc. Per-seat angular step is\n * `curve/(seatCount-1)`; radius is derived so the chord between neighbours\n * equals seatSpacing → radius = spacing / (2·sin(step/2)). Seat 0 sits at the\n * bottom of the arc (local origin) with the circle centre directly above it at\n * (0,-radius); increasing index sweeps toward +x while the ends rise toward -y,\n * i.e. positive curve is concave toward -y (a row wrapping a stage above it).\n * Local points are then rotated by `rotation` and translated to `origin`.\n *\n * Numbering (labels only, never geometry): `seatNumbering.direction === 'rtl'`\n * numbers from the far physical end; `step === 2` produces odd/even numbering\n * (start at 1 → 1,3,5…; start at 2 → 2,4,6…).\n */\n/** Base (pre-override) seat centre per index — shared by expandRow + designer edit mode. */\nfunction rowSeatPositions(row: RowObject): Point[] {\n const { seatCount, seatSpacing, curve, rotation, origin } = row;\n const out: Point[] = [];\n if (row.path) return distributeAlongCubic(row.path, seatCount);\n if (seatCount <= 1) {\n if (seatCount === 1) out.push({ x: origin.x, y: origin.y });\n return out;\n }\n if (curve === 0) {\n for (let i = 0; i < seatCount; i++) out.push(place(i * seatSpacing, 0, rotation, origin));\n return out;\n }\n const arcStep = (curve / (seatCount - 1)) * DEG; // radians per seat\n const radius = seatSpacing / (2 * Math.sin(Math.abs(arcStep) / 2));\n // Centre above seat 0. φ measured from the downward vertical, growing with index.\n for (let i = 0; i < seatCount; i++) {\n const phi = i * arcStep;\n const lx = radius * Math.sin(phi);\n const ly = -radius + radius * Math.cos(phi); // ≤ 0 → ends rise toward -y\n out.push(place(lx, ly, rotation, origin));\n }\n return out;\n}\n\nfunction overrideMap(row: RowObject): Map<number, SeatOverride> {\n const m = new Map<number, SeatOverride>();\n if (row.overrides) for (const o of row.overrides) m.set(o.index, o);\n return m;\n}\n\n/**\n * Every seat slot of a row INCLUDING skipped ones (designer seat-edit mode uses\n * this to draw un-skip handles). Overrides (dx/dy/label/categoryKey) are applied\n * but a skipped slot is flagged, not omitted.\n */\nexport interface RowSeatSlot {\n index: number;\n x: number;\n y: number;\n label: string;\n displayLabel: string;\n categoryKey: string;\n skipped: boolean;\n accessible: boolean;\n accessibility: AccessibilityType[];\n commercial?: RowObject['commercial'];\n viewUrl?: string;\n labelStyle?: LabelStyle;\n}\n\nexport function expandRowSlots(row: RowObject): RowSeatSlot[] {\n const start = row.seatLabelStart ?? 1;\n const dir = row.seatNumbering?.direction ?? 'ltr';\n const step = row.seatNumbering?.step ?? 1;\n const n = row.seatCount;\n let seatNumber: (i: number) => number;\n if (dir === 'center') {\n // Number outward from the middle: rank seats by distance from centre\n // (inner-left wins ties), so the centre seat gets `start`.\n const rank = new Array<number>(n);\n Array.from({ length: n }, (_, i) => i)\n .sort((a, b) => Math.abs(2 * a - (n - 1)) - Math.abs(2 * b - (n - 1)) || a - b)\n .forEach((idx, k) => (rank[idx] = k));\n seatNumber = (i) => start + rank[i] * step;\n } else {\n seatNumber = (i) => start + (dir === 'rtl' ? n - 1 - i : i) * step;\n }\n const ov = overrideMap(row);\n return rowSeatPositions(row).map((p, i) => {\n const o = ov.get(i);\n const accessibility = overrideAccessibility(o);\n const inventoryLabel = o?.label ?? `${row.label}-${seatNumber(i)}`;\n const displayPrefix = row.displayLabel ?? row.label;\n const commercial = { ...row.commercial, ...o?.commercial };\n return {\n index: i,\n x: p.x + (o?.dx ?? 0),\n y: p.y + (o?.dy ?? 0),\n label: inventoryLabel,\n displayLabel: o?.displayLabel ?? `${displayPrefix}-${seatNumber(i)}`,\n categoryKey: o?.categoryKey ?? row.categoryKey,\n skipped: !!o?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n commercial: Object.values(commercial).some((value) => value !== undefined && value !== false && value !== '') ? commercial : undefined,\n viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl,\n labelStyle: o?.labelStyle,\n };\n });\n}\n\nexport function expandRow(row: RowObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n for (const slot of expandRowSlots(row)) {\n if (slot.skipped) continue; // physical seat absent; numbering gap preserved\n seats.push({\n id: `${row.id}:${slot.index}`,\n label: slot.label,\n displayLabel: slot.displayLabel === slot.label ? undefined : slot.displayLabel,\n x: slot.x,\n y: slot.y,\n rowId: row.id,\n categoryKey: slot.categoryKey,\n accessible: slot.accessible || undefined,\n accessibility: slot.accessibility.length ? slot.accessibility : undefined,\n commercial: slot.commercial,\n viewUrl: slot.viewUrl,\n labelStyle: slot.labelStyle,\n });\n }\n return seats;\n}\n\n/**\n * Expand a table into its perimeter seats.\n *\n * Round: seats spread evenly on a circle of radius `radius + 16`, the first at\n * angle `rotation` (degrees, clockwise from +x). Rect: seats line the top and\n * bottom edges (split evenly, any remainder to the top), 16u outside the edge,\n * the whole set rotated about the table centre.\n */\nexport function expandTable(t: TableObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n const n = Math.max(0, Math.round(t.seatCount));\n if (n === 0) return seats;\n\n const mk = (i: number, x: number, y: number): ExpandedSeat => ({\n id: `${t.id}:${i}`,\n label: `${t.label}-${i + 1}`,\n x,\n y,\n rowId: t.id,\n categoryKey: t.categoryKey,\n });\n\n if (t.shape === 'round') {\n const R = (t.radius ?? 40) + TABLE_SEAT_OFFSET;\n const base = t.rotation * DEG;\n const arc = Math.max(0, Math.min(360, t.seatArc ?? 360));\n if (arc >= 360 || n === 1) {\n // Full ring (or a lone seat) — evenly spaced around the whole table.\n for (let i = 0; i < n; i++) {\n const a = base + (i / n) * 2 * Math.PI;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n // Open side: seats fill the arc, leaving a gap centred on `rotation` (the\n // opening — face it toward the aisle/wall). Seats span edge-to-edge of the\n // seated arc so people flank the gap.\n const arcRad = arc * DEG;\n const halfGap = (2 * Math.PI - arcRad) / 2;\n const start = base + halfGap;\n for (let i = 0; i < n; i++) {\n const a = start + (i / (n - 1)) * arcRad;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n\n // Rect: seats line the enabled edges. Round-robin the count across sides in\n // canonical order so they stay balanced; top/bottom run along width, left/\n // right along height, all 16u outside and rotated with the table.\n const w = t.width ?? 80;\n const h = t.height ?? 50;\n const enabled: NonNullable<TableObject['sides']> =\n t.sides && t.sides.length ? t.sides : ['top', 'bottom'];\n const order = (['top', 'bottom', 'left', 'right'] as const).filter((s) => enabled.includes(s));\n if (!order.length) return seats;\n const counts = new Map<(typeof order)[number], number>(order.map((s) => [s, 0]));\n for (let i = 0; i < n; i++) {\n const s = order[i % order.length];\n counts.set(s, counts.get(s)! + 1);\n }\n let idx = 0;\n for (const side of order) {\n const count = counts.get(side)!;\n for (let j = 0; j < count; j++) {\n let localX: number;\n let localY: number;\n if (side === 'top') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = -h / 2 - TABLE_SEAT_OFFSET;\n } else if (side === 'bottom') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = h / 2 + TABLE_SEAT_OFFSET;\n } else if (side === 'left') {\n localX = -w / 2 - TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n } else {\n localX = w / 2 + TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n }\n const p = place(localX, localY, t.rotation, t.center);\n seats.push(mk(idx++, p.x, p.y));\n }\n }\n return seats;\n}\n\n/** Expand a booth into its single bookable block unit. */\nexport function expandBooth(b: BoothObject): ExpandedSeat[] {\n return [\n {\n id: `${b.id}:0`,\n label: b.label,\n x: b.center.x,\n y: b.center.y,\n rowId: b.id,\n categoryKey: b.categoryKey,\n kind: 'booth',\n },\n ];\n}\n\n/** Ray-cast point-in-polygon test — odd crossings ⇒ inside. */\nexport function pointInPolygon(p: Point, poly: Point[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x;\n const yi = poly[i].y;\n const xj = poly[j].x;\n const yj = poly[j].y;\n const hit = yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;\n if (hit) inside = !inside;\n }\n return inside;\n}\n\nfunction pointOnPolygonBoundary(p: Point, poly: Point[]): boolean {\n return poly.some((start, index) => {\n const end = poly[(index + 1) % poly.length];\n const cross = (p.y - start.y) * (end.x - start.x) - (p.x - start.x) * (end.y - start.y);\n if (Math.abs(cross) > 1e-7) return false;\n const dot = (p.x - start.x) * (end.x - start.x) + (p.y - start.y) * (end.y - start.y);\n const lengthSquared = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;\n return dot >= -1e-7 && dot <= lengthSquared + 1e-7;\n });\n}\n\nexport function pointInPolygonWithHoles(p: Point, outer: Point[], holes: Point[][] | undefined): boolean {\n return pointInPolygon(p, outer)\n && !(holes ?? []).some((hole) => pointInPolygon(p, hole) || pointOnPolygonBoundary(p, hole));\n}\n\n/** Stable interior label anchor that cannot land inside a polygon cutout. */\nexport function polygonLabelPoint(outer: Point[], holes: Point[][] | undefined): Point {\n if (!outer.length) return { x: 0, y: 0 };\n const xs = outer.map((point) => point.x);\n const ys = outer.map((point) => point.y);\n const bounds = { minX: Math.min(...xs), maxX: Math.max(...xs), minY: Math.min(...ys), maxY: Math.max(...ys) };\n const centroid = polygonCentroid(outer);\n if (pointInPolygonWithHoles(centroid, outer, holes)) return centroid;\n let best = outer[0];\n let bestScore = -Infinity;\n const rings = [outer, ...(holes ?? [])];\n for (let row = 1; row < 24; row += 1) {\n for (let column = 1; column < 24; column += 1) {\n const point = {\n x: bounds.minX + ((bounds.maxX - bounds.minX) * column) / 24,\n y: bounds.minY + ((bounds.maxY - bounds.minY) * row) / 24,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) continue;\n const score = Math.min(...rings.flatMap((ring) => ring.map((start, index) => {\n const end = ring[(index + 1) % ring.length];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const denominator = dx * dx + dy * dy;\n const projection = denominator\n ? ((point.x - start.x) * dx + (point.y - start.y) * dy) / denominator\n : 0;\n const t = Math.max(0, Math.min(1, projection));\n return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));\n })));\n if (score > bestScore) { best = point; bestScore = score; }\n }\n }\n return best;\n}\n\n/** Average of polygon vertices (v1 centroid — good enough for labels/membership). */\nfunction polygonCentroid(pts: Point[]): Point {\n if (!pts.length) return { x: 0, y: 0 };\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p.x;\n y += p.y;\n }\n return { x: x / pts.length, y: y / pts.length };\n}\n\n/**\n * Visual centre of any object — used for spatial section membership and for\n * rotating an object about its centre. Rows: centroid of expanded seats (or\n * origin when empty); tables/booths: centre; GA/section: polygon centroid;\n * shape: bbox centre; text: its position.\n */\nexport function objectCenter(o: ChartObject): Point {\n switch (o.type) {\n case 'row': {\n const seats = expandRow(o);\n if (!seats.length) return { x: o.origin.x, y: o.origin.y };\n let x = 0;\n let y = 0;\n for (const s of seats) {\n x += s.x;\n y += s.y;\n }\n return { x: x / seats.length, y: y / seats.length };\n }\n case 'table':\n case 'booth':\n return { x: o.center.x, y: o.center.y };\n case 'gaArea':\n return polygonCentroid(o.points);\n case 'section':\n return polygonCentroid(o.outline);\n case 'text':\n return { x: o.position.x, y: o.position.y };\n case 'shape':\n if (o.points && o.points.length) return polygonCentroid(o.points);\n if (o.x != null && o.y != null && o.width != null && o.height != null) {\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n return { x: o.x ?? 0, y: o.y ?? 0 };\n case 'decorImage':\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n}\n\n/**\n * Normalized floor list (Batch 5): a multi-floor chart's `floors`, or a synthetic\n * single floor wrapping a single-floor chart's `objects`. Every consumer that needs\n * to reason about floors goes through this so single-floor charts stay untouched.\n */\nexport function floorsOf(doc: ChartDoc): Floor[] {\n if (doc.floors && doc.floors.length) return doc.floors;\n return [{ id: 'floor-0', name: 'Main', objects: doc.objects, focalPoint: doc.focalPoint, backgroundImage: doc.backgroundImage }];\n}\n\n/** Objects of one floor by id (defaults to the first floor). */\nexport function floorObjects(doc: ChartDoc, floorId?: string): ChartObject[] {\n const floors = floorsOf(doc);\n return (floorId ? floors.find((f) => f.id === floorId) : floors[0])?.objects ?? [];\n}\n\n/** Every object across ALL floors — the whole venue (single-floor = `doc.objects`). */\nexport function allObjects(doc: ChartDoc): ChartObject[] {\n return doc.floors && doc.floors.length ? doc.floors.flatMap((f) => f.objects) : doc.objects;\n}\n\n/** A copy of an object translated by (dx, dy) — every coordinate field shifted. */\nfunction translateObject(o: ChartObject, dx: number, dy: number): ChartObject {\n const p = (pt: Point): Point => ({ x: pt.x + dx, y: pt.y + dy });\n const pts = (a: Point[]): Point[] => a.map(p);\n switch (o.type) {\n case 'row':\n return { ...o, origin: p(o.origin) };\n case 'table':\n case 'booth':\n return { ...o, center: p(o.center) };\n case 'gaArea':\n return { ...o, points: pts(o.points), ...(o.holes ? { holes: o.holes.map(pts) } : {}) };\n case 'section':\n return {\n ...o,\n outline: pts(o.outline),\n ...(o.outlinePath ? { outlinePath: translateSectionOutlinePath(o.outlinePath, dx, dy) } : {}),\n ...(o.holes ? { holes: o.holes.map(pts) } : {}),\n };\n case 'text':\n return { ...o, position: p(o.position) };\n case 'shape':\n return {\n ...o,\n ...(o.points ? { points: pts(o.points) } : {}),\n ...(o.x != null ? { x: o.x + dx } : {}),\n ...(o.y != null ? { y: o.y + dy } : {}),\n };\n case 'decorImage':\n return { ...o, x: o.x + dx, y: o.y + dy };\n }\n}\n\n/**\n * Multi-floor 3D stack (Batch 5): flatten every floor into ONE doc with floor `i`\n * lifted by `i * spread` in −y, so the isometric view shows the floors as stacked\n * decks (ground at the bottom). Returns a single-floor doc (no `floors`). Meant\n * only for the 3D overview render — 2D still shows one floor via `floorObjects`.\n */\nexport function stackFloors(doc: ChartDoc, spread = 900): ChartDoc {\n if (!doc.floors || doc.floors.length < 2) return doc;\n const objects: ChartObject[] = [];\n doc.floors.forEach((f, i) => {\n const dy = -i * spread;\n for (const o of f.objects) objects.push(dy === 0 ? o : translateObject(o, 0, dy));\n });\n return { ...doc, objects, floors: undefined };\n}\n\n/** Expand every seat-bearing object across all floors (rows, tables, booths). */\nexport function expandChart(doc: ChartDoc): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n for (const obj of allObjects(doc)) {\n if (obj.type === 'row') out.push(...expandRow(obj));\n else if (obj.type === 'table') out.push(...expandTable(obj));\n else if (obj.type === 'booth') out.push(...expandBooth(obj));\n }\n return out;\n}\n\nconst PAD = 40;\n\n/** Axis-aligned bounds over every object plus the background image, with padding. */\nexport function chartBounds(doc: ChartDoc): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n const acc = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n\n for (const s of expandChart(doc)) acc(s.x, s.y);\n\n for (const obj of allObjects(doc)) {\n if (obj.type === 'gaArea') {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.type === 'section') {\n for (const p of obj.outline) acc(p.x, p.y);\n } else if (obj.type === 'decorImage') {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n } else if (obj.type === 'shape') {\n if (obj.points && obj.points.length) {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n }\n } else if (obj.type === 'table') {\n const off = TABLE_SEAT_OFFSET + SEAT_R;\n const ext =\n obj.shape === 'round'\n ? (obj.radius ?? 40) + off\n : Math.max((obj.width ?? 80) / 2, (obj.height ?? 50) / 2) + off; // rotation-agnostic over-approximation\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'booth') {\n const ext = Math.max(obj.width, obj.height) / 2;\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'text') {\n const w = obj.fontSize * obj.text.length * 0.6; // approximate glyph advance\n acc(obj.position.x, obj.position.y);\n acc(obj.position.x + w, obj.position.y + obj.fontSize);\n }\n }\n\n if (doc.backgroundImage) {\n const { center, width } = doc.backgroundImage;\n const bh = (width * 3) / 4; // assume 4:3 when the true aspect is unknown at bounds-time\n acc(center.x - width / 2, center.y - bh / 2);\n acc(center.x + width / 2, center.y + bh / 2);\n }\n\n // Empty document → a sane default box around the focal point.\n if (!isFinite(minX)) {\n const f = doc.focalPoint ?? { x: 0, y: 0 };\n return { x: f.x - 200, y: f.y - 200, width: 400, height: 400 };\n }\n\n return {\n x: minX - PAD,\n y: minY - PAD,\n width: maxX - minX + PAD * 2,\n height: maxY - minY + PAD * 2,\n };\n}\n","import type { ChartDoc, GAAreaObject } from './types';\nimport { allObjects } from './layout';\n\nconst PREFIX = '__sl_ga__';\nexport const MAX_GA_CAPACITY = 100_000;\nexport const MAX_EVENT_INVENTORY = 100_000;\n\n/** Stable internal inventory label for one unit of a GA area's capacity. */\nexport function gaUnitLabel(areaId: string, index: number): string {\n return `${PREFIX}${encodeURIComponent(areaId)}__${index + 1}`;\n}\n\nexport function gaUnitLabels(area: GAAreaObject): string[] {\n const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));\n return Array.from({ length: capacity }, (_, i) => gaUnitLabel(area.id, i));\n}\n\nexport function gaAreasOf(doc: ChartDoc): GAAreaObject[] {\n return allObjects(doc).filter((o): o is GAAreaObject => o.type === 'gaArea');\n}\n\nexport function isGaUnitLabel(label: string): boolean {\n return label.startsWith(PREFIX);\n}\n","/**\n * Section membership + hide/show resolution (Batch 3.3).\n *\n * A `SectionObject` is a polygon drawn over existing seat objects; an object\n * \"belongs\" to a section when its visual centre (`objectCenter`) falls inside\n * the section outline, first section in doc order winning. This is the same\n * spatial notion `objectCenter`'s doc-comment describes, resolved once here so\n * BOTH the event manager (Sections tab counts) and the buyer picker (omit\n * hidden seats) agree on which seats live in which section.\n *\n * Hiding is per-EVENT (the EventDO holds the hidden id set), not a chart edit —\n * so a republish of the chart never disturbs it. A hidden id may be a section\n * id, a zone id (hides every section in the zone), or `UNGROUPED_ID` (the\n * catch-all bucket of seat objects that sit in no section).\n */\nimport type { ChartDoc, ChartObject, SectionObject } from './types';\nimport { allObjects, expandBooth, expandRow, expandTable, objectCenter, pointInPolygonWithHoles } from './layout';\nimport { gaUnitLabels } from './ga';\n\n/** Synthetic section id for seat objects that fall in no drawn section. */\nexport const UNGROUPED_ID = '__ungrouped__';\n\n/**\n * A per section/zone availability window (Batch 3.4). Wire-compatible with the\n * EventDO's own `AvailabilityRule`. Absence of a rule for an id = on sale.\n * 'hidden' — manual: hidden until the organizer reveals it (3.3).\n * 'timed' — hidden until `revealAt` (epoch ms), then auto-reveals.\n * 'threshold' — auto-reveals once the on-sale inventory is `thresholdPct`% sold.\n * 'closed' — visible to buyers but not purchasable (rendered flat grey);\n * unlike 'hidden', the seats stay on the map, just off sale.\n * `labels` are the seat labels the id governs, so a threshold's denominator can\n * exclude still-hidden seats.\n */\nexport interface AvailabilityRule {\n mode: 'hidden' | 'timed' | 'threshold' | 'closed';\n revealAt?: number;\n thresholdPct?: number;\n labels?: string[];\n}\n\nexport interface SectionNode {\n /** Section id (a `SectionObject.id`, or `UNGROUPED_ID`). */\n id: string;\n label: string;\n /** Zone id this section points at (`SectionObject.zone`), if any. */\n zone?: string;\n /** Total seats across the member objects. */\n seatCount: number;\n /** Ids of the seat-bearing objects that belong to this section. */\n objectIds: string[];\n /** Seat labels across the member objects (for availability-rule denominators). */\n seatLabels: string[];\n}\n\n/** Seat labels produced by one seat-bearing object (rows/tables/booths); [] otherwise. */\nfunction objectSeatLabels(o: ChartObject): string[] {\n if (o.type === 'row') return expandRow(o).map((s) => s.label);\n if (o.type === 'table') return expandTable(o).map((s) => s.label);\n if (o.type === 'booth') return expandBooth(o).map((s) => s.label);\n if (o.type === 'gaArea') return gaUnitLabels(o);\n return [];\n}\n\nfunction isSeatObject(o: ChartObject): o is Extract<ChartObject, { type: 'row' | 'table' | 'booth' | 'gaArea' }> {\n return o.type === 'row' || o.type === 'table' || o.type === 'booth' || o.type === 'gaArea';\n}\n\nfunction samePoints(left: Array<{ x: number; y: number }>, right: Array<{ x: number; y: number }>): boolean {\n return left.length === right.length\n && left.every((point, index) => point.x === right[index].x && point.y === right[index].y);\n}\n\nfunction sameGASurfaceAsSection(object: ChartObject, section: SectionObject): boolean {\n if (object.type !== 'gaArea' || !samePoints(object.points, section.outline)) return false;\n const objectHoles = object.holes ?? [];\n const sectionHoles = section.holes ?? [];\n return objectHoles.length === sectionHoles.length\n && objectHoles.every((hole, index) => samePoints(hole, sectionHoles[index]));\n}\n\n/**\n * Resolve section membership for a chart. Returns one node per drawn section\n * (doc order), a synthetic \"Ungrouped\" node for loose seat objects (null when\n * every seat sits in a section), and the object→section id map.\n */\nexport function computeSections(doc: ChartDoc): {\n sections: SectionNode[];\n ungrouped: SectionNode | null;\n /** seat-object id → owning section id (or `UNGROUPED_ID`). */\n objectToSection: Map<string, string>;\n} {\n // Span all floors (Batch 5) — a multi-floor chart's sections live in floors[];\n // single-floor charts fall through to doc.objects. Section ids are chart-unique.\n const objs = allObjects(doc);\n const sectionObjs = objs.filter((o): o is SectionObject => o.type === 'section');\n const nodes = new Map<string, SectionNode>();\n for (const s of sectionObjs) {\n const logicalId = s.logicalSectionId ?? s.id;\n const existing = nodes.get(logicalId);\n if (existing) {\n // Validation owns disagreement reporting; keep the first component's\n // public identity deterministic if an invalid document reaches here.\n continue;\n }\n nodes.set(logicalId, {\n id: logicalId,\n label: s.displayLabel || s.label || 'Section',\n zone: s.zone,\n seatCount: 0,\n objectIds: [],\n seatLabels: [],\n });\n }\n const ungrouped: SectionNode = { id: UNGROUPED_ID, label: 'Other seats', seatCount: 0, objectIds: [], seatLabels: [] };\n const objectToSection = new Map<string, string>();\n\n for (const obj of objs) {\n if (!isSeatObject(obj)) continue;\n const labels = objectSeatLabels(obj);\n if (labels.length === 0) continue;\n // Deterministically generated reference inventory carries durable ownership.\n // Prefer the named logical section when its geometry confirms that claim: a\n // concave GA surface can have an arithmetic centre outside its own shell,\n // while malformed provenance must not pull a truly standalone area inside.\n const referencedLogicalId = obj.referenceInventorySource?.logicalSectionId;\n const c = objectCenter(obj);\n const referencedOwner = referencedLogicalId\n ? sectionObjs.find((section) => (\n (section.logicalSectionId ?? section.id) === referencedLogicalId\n && (sameGASurfaceAsSection(obj, section) || pointInPolygonWithHoles(c, section.outline, section.holes))\n ))\n : undefined;\n // Ordinary authored inventory still uses the first drawn section (doc order)\n // whose outline contains the visual centre.\n const owner = referencedOwner ?? sectionObjs.find((s) => pointInPolygonWithHoles(c, s.outline, s.holes));\n const node = owner ? nodes.get(owner.logicalSectionId ?? owner.id)! : ungrouped;\n node.seatCount += labels.length;\n node.objectIds.push(obj.id);\n node.seatLabels.push(...labels);\n objectToSection.set(obj.id, node.id);\n }\n\n return {\n sections: [...nodes.values()],\n ungrouped: ungrouped.objectIds.length ? ungrouped : null,\n objectToSection,\n };\n}\n\n/** Is a drawn section hidden under `hidden` — directly, or via its zone? */\nexport function isSectionHidden(s: SectionObject, hidden: ReadonlySet<string>): boolean {\n return hidden.has(s.id)\n || (!!s.logicalSectionId && hidden.has(s.logicalSectionId))\n || (!!s.zone && hidden.has(s.zone));\n}\n\n/**\n * The set of seat-object ids to omit from the buyer view for a given hidden id\n * set. An object is hidden when its owning section is hidden (directly or via\n * zone), or it is ungrouped and the catch-all bucket is hidden.\n */\nexport function hiddenObjectIds(doc: ChartDoc, hidden: ReadonlySet<string>): Set<string> {\n const out = new Set<string>();\n if (!hidden.size) return out;\n const { sections, ungrouped, objectToSection } = computeSections(doc);\n const hiddenSectionIds = new Set<string>();\n const zoneById = new Map(sections.map((s) => [s.id, s.zone] as const));\n for (const s of sections) {\n const zone = zoneById.get(s.id);\n if (hidden.has(s.id) || (zone && hidden.has(zone))) hiddenSectionIds.add(s.id);\n }\n const ungroupedHidden = !!ungrouped && hidden.has(UNGROUPED_ID);\n for (const [objId, secId] of objectToSection) {\n if (hiddenSectionIds.has(secId) || (ungroupedHidden && secId === UNGROUPED_ID)) out.add(objId);\n }\n return out;\n}\n\n/**\n * A copy of the doc with hidden sections' member objects removed, plus the\n * hidden section overlays themselves (so no empty block renders). Returns the\n * SAME reference when nothing is hidden — callers can skip a re-render on `===`.\n */\nexport function applyHidden(doc: ChartDoc, hidden: ReadonlySet<string>): ChartDoc {\n if (!hidden.size) return doc;\n const hide = hiddenObjectIds(doc, hidden);\n const hiddenSet = hidden instanceof Set ? hidden : new Set(hidden);\n const keep = (o: ChartObject): boolean => {\n if (hide.has(o.id)) return false;\n if (o.type === 'section' && isSectionHidden(o, hiddenSet)) return false;\n return true;\n };\n // Multi-floor (Batch 5): filter each floor + the floor-0 mirror.\n if (doc.floors && doc.floors.length) {\n let changed = false;\n const floors = doc.floors.map((f) => {\n const objects = f.objects.filter(keep);\n if (objects.length !== f.objects.length) changed = true;\n return objects.length === f.objects.length ? f : { ...f, objects };\n });\n if (!changed) return doc;\n return { ...doc, floors, objects: floors[0].objects };\n }\n const objects = doc.objects.filter(keep);\n if (objects.length === doc.objects.length) return doc;\n return { ...doc, objects };\n}\n","/**\n * SeatmapRenderer — the shared canvas rendering core (buyer picker shell).\n *\n * Uses Konva directly with per-module imports to keep the bundle lean. The\n * whole point of the spike is staying smooth at ~5,000 seats on mobile, so the\n * hot paths lean on: layer bitmap caching + listening(false) when zoomed out,\n * per-seat fill updates (never full rebuilds) on status change, and viewport-\n * only label rendering rebuilt on interaction-end rather than per frame.\n */\n\n// Core (not Global): Core assembles the real Konva namespace — Global alone\n// lacks DD/Util and Stage._pointermove dereferences Konva.DD unconditionally.\nimport { Konva } from 'konva/lib/Core';\nimport { Stage } from 'konva/lib/Stage';\nimport { Layer } from 'konva/lib/Layer';\nimport { Group } from 'konva/lib/Group';\nimport { Circle } from 'konva/lib/shapes/Circle';\nimport { Rect } from 'konva/lib/shapes/Rect';\nimport { Ellipse } from 'konva/lib/shapes/Ellipse';\nimport { Line } from 'konva/lib/shapes/Line';\nimport { Text } from 'konva/lib/shapes/Text';\nimport { Image as KImage } from 'konva/lib/shapes/Image';\nimport type { KonvaEventObject } from 'konva/lib/Node';\nimport { Shape } from 'konva/lib/Shape';\n\nimport type {\n AccessibilityType,\n ChartDoc,\n ChartTheme,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n Point,\n RenderedBookableLabelEvidence,\n RenderedGAAreaEvidence,\n RenderedFreeTextEvidence,\n RendererQualityEvidence,\n RendererOptions,\n SeatStatus,\n SectionOutlinePath,\n SectionObject,\n} from '../core/types';\nimport { accessibilityRingColor } from '../core/types';\nimport { chartBounds, expandChart, floorsOf, pointInPolygonWithHoles, polygonLabelPoint, stackFloors } from '../core/layout';\nimport {\n BOOTH_LABEL_FONT_SIZE,\n GA_CAPACITY_LABEL_FONT_SIZE,\n GA_FILL_OPACITY,\n GA_LABEL_FONT_SIZE,\n MIN_VISIBLE_BOOKABLE_LABEL_PX,\n SEAT_LABEL_FONT_SIZE,\n bookableMarkerLabel,\n compositeHexOver,\n isBookableLabelLegibleAtScale,\n stateAwareBookableLabelInk,\n} from '../core/chartRenderRules';\nimport { t } from '../i18n';\nimport { formatMoney } from '../lib/money';\n\nconst SEAT_RADIUS = 9;\n/** Absolute scale at which a seat (r=9) renders ~legibly (~8px). */\nconst SEAT_LEGIBLE_SCALE = 0.9;\n/** Below this absolute scale we swap seats for a cached bitmap. */\nconst CACHE_THRESHOLD = 0.55 * SEAT_LEGIBLE_SCALE;\n/** First scale where a 7u seat label reaches the shared rendered-size floor. */\nconst LABEL_SCALE = MIN_VISIBLE_BOOKABLE_LABEL_PX / SEAT_LABEL_FONT_SIZE;\nconst MIN_FITTED_SEAT_LABEL_FONT_SIZE = 4;\n/** Extra screen-px of slack around a seat circle that still counts as a tap on\n * it. Gives small seats a finger-friendly hit target (§4 \"hit ≥ 24px\") so a\n * near-miss on mobile still selects the nearest seat instead of doing nothing. */\nconst SEAT_TAP_SLOP_PX = 14;\n/** At/below this scale, sections read as clean labelled shells (seats hidden). */\nconst SECTION_PROMINENT_SCALE = 0.45 * SEAT_LEGIBLE_SCALE;\n/**\n * Above this scale, seats are fully shown (dots); between here and\n * SECTION_PROMINENT the block melts in. Set high so a big sectioned chart OPENS\n * as named blocks and only reveals seats once you zoom in close.\n */\nconst BLOCK_MELT_TOP = 0.9 * SEAT_LEGIBLE_SCALE;\n/** Camera scale used after a section drill-in. Keeping this above the block\n * melt band guarantees that a section tap lands on live, legible seats even\n * when a narrow phone viewport cannot frame the whole section at that scale. */\nconst SEAT_FOCUS_SCALE = Math.max(SEAT_LEGIBLE_SCALE * 1.1, BLOCK_MELT_TOP);\n/** Ignore normal finger jitter before treating a tap as a map pan. */\nconst PAN_START_SLOP_PX = 8;\n/**\n * Below this scale, ZONE blocks/labels take over from per-section detail (the\n * farthest rung). ~0.55× the section rung so: seats → section blocks → zones.\n */\nconst ZONE_PROMINENT_SCALE = 0.55 * SECTION_PROMINENT_SCALE;\n/** Never label more than this many seats at once (viewport clutter guard). */\nconst MAX_LABELS = 700;\n/**\n * Manage-mode marquee: above this many selected seats we stop drawing per-seat\n * selection-ring nodes (they'd be an invisible speck at that zoom and a huge\n * node count on a 13k arena) and rely on the seat-fill selection paint instead.\n * Selection membership (getSelection / bulk block) is unaffected.\n */\nconst MARQUEE_RING_CAP = 2500;\n\n// ---- Isometric (\"3D\") view mode -------------------------------------------\n/** Full-iso rotation of the chart about its centre (degrees). */\nconst ISO_ANGLE_DEG = -11.5;\n/** Full-iso vertical squash (1 = flat). */\nconst ISO_SQUASH = 0.58;\n/** World units a section (and its members) lift per elevation step at full iso. */\nconst LIFT_PER_STEP = 58;\n/** Flat⇄iso tween duration (ms); reduced-motion snaps. */\nconst ISO_TWEEN_MS = 320;\n/** Buyer camera travel should be easy to follow without feeling sluggish. */\nconst CAMERA_GLIDE_MS = 650;\n\n// ---- Section/zone LOD (\"melt\") tuning -------------------------------------\n/** Section overview is a semantic hierarchy, not a price/availability heatmap. */\nconst BLOCK_FILL_ALPHA = 1;\nconst SECTION_STROKE_PX = 2;\nconst LIGHT_OVERVIEW_SECTION_FILL = '#e5e7eb';\nconst LIGHT_OVERVIEW_SECTION_STROKE = '#c7cbd1';\nconst LIGHT_OVERVIEW_SECTION_INK = '#595f69';\nconst LIGHT_OVERVIEW_FOCAL_FILL = '#d1d5db';\nconst LIGHT_OVERVIEW_FOCAL_STROKE = '#b8bdc4';\nconst DARK_OVERVIEW_SECTION_FILL = '#273142';\nconst DARK_OVERVIEW_SECTION_STROKE = '#526078';\nconst DARK_OVERVIEW_SECTION_INK = '#f1f5f9';\nconst DARK_OVERVIEW_FOCAL_FILL = '#374151';\nconst DARK_OVERVIEW_FOCAL_STROKE = '#64748b';\n/** Screen-space target sizes (px) for scale-compensated section/zone labels. */\nconst SECTION_LABEL_PX = 20;\nconst MIN_SECTION_LABEL_PX = 12;\nconst ZONE_LABEL_PX = 18;\nconst ZONE_SUB_PX = 12;\nconst HIERARCHY_PILL_BACKGROUND = '#111827';\n\nconst HELD_FILL = '#6b7280';\nconst TAKEN_FILL = '#374151';\nconst NFS_STROKE = '#4b5563';\n/** Phase 2 event-level `closed` section: a flat desaturated slate block (label\n * kept), distinct from the per-seat availability-grey. Seats inside read grey\n * at 40% and are not pickable (per chart-design-standards §3). */\nconst CLOSED_SEAT_FILL = '#4b5563';\nconst CLOSED_SEAT_OPACITY = 0.4;\n/** AXS section-focus: non-focused sections dim to this opacity. */\nconst FOCUS_DIM_OPACITY = 0.16;\n/** Light/neutral backdrop panel drawn behind the focused section's seats. */\nconst FOCUS_BACKDROP_FILL = 'rgba(244,246,248,0.06)';\n/** Okabe-Ito colorblind-safe hues (black dropped — unreadable on dark charts).\n * Categories map to these by their doc order when colorblind mode is on. */\nconst CB_PALETTE = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7'];\n\n/** Does a seat satisfy a filter? `[]` means \"any accessible seat\". */\nfunction seatMatchesAccess(seat: ExpandedSeat, filter: AccessibilityType[]): boolean {\n if (filter.length === 0) return !!seat.accessible;\n return !!seat.accessibility?.some((t) => filter.includes(t));\n}\n\n// Theme fallbacks (dark defaults) — used when doc.theme leaves a slot unset.\nconst DEF_SEAT_LABEL = '#0b1220';\nconst DEF_SELECTION = '#ffffff';\n/** Selection/hover ring on LIGHT canvases — a white ring vanishes there. */\nconst DEF_SELECTION_ON_LIGHT = '#0b1220';\nconst DEF_DECOR_FILL = '#232c40';\nconst DEF_TEXT = '#8b93a7';\nconst DEF_CANVAS_BACKGROUND = '#0e1117';\n\n/**\n * Relative luminance (0..1) of a CSS color — supports #rgb, #rrggbb and\n * rgb()/rgba(). Returns NaN for anything unparseable (gradients, ''), which\n * callers must treat as \"unknown → assume dark\" to preserve dark defaults.\n */\nfunction colorLuminance(color: string): number {\n const s = color.trim();\n let r = NaN;\n let g = NaN;\n let b = NaN;\n const hex = /^#([\\da-f]{3}|[\\da-f]{6})$/i.exec(s);\n if (hex) {\n const h = hex[1].length === 3 ? hex[1].split('').map((c) => c + c).join('') : hex[1];\n r = parseInt(h.slice(0, 2), 16);\n g = parseInt(h.slice(2, 4), 16);\n b = parseInt(h.slice(4, 6), 16);\n } else {\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/.exec(s);\n if (rgb) {\n r = +rgb[1];\n g = +rgb[2];\n b = +rgb[3];\n }\n }\n if (Number.isNaN(r)) return NaN;\n return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;\n}\n\n/** Light enough that white UI accents (selection ring) lose contrast. */\nfunction isLightColor(color: string): boolean {\n const lum = colorLuminance(color);\n return !Number.isNaN(lum) && lum > 0.6;\n}\n\n/** Normalize the opaque CSS colours used by supported buyer surfaces. */\nfunction opaqueColorHex(color: string): string | null {\n const value = color.trim();\n const hex = /^#([\\da-f]{3}|[\\da-f]{6})$/i.exec(value);\n if (hex) {\n const expanded = hex[1].length === 3\n ? hex[1].split('').map((channel) => channel + channel).join('')\n : hex[1];\n return `#${expanded.toLowerCase()}`;\n }\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)$/i.exec(value);\n if (!rgb || (rgb[4] != null && Number(rgb[4]) < 0.999)) return null;\n const channels = [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];\n if (channels.some((channel) => !Number.isInteger(channel) || channel < 0 || channel > 255)) return null;\n return `#${channels.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`;\n}\n\ninterface OverviewPalette {\n sectionFill: string;\n sectionStroke: string;\n sectionInk: string;\n focalFill: string;\n focalStroke: string;\n}\n\nfunction overviewPalette(canvasBackground: string): OverviewPalette {\n return isLightColor(canvasBackground)\n ? {\n sectionFill: LIGHT_OVERVIEW_SECTION_FILL,\n sectionStroke: LIGHT_OVERVIEW_SECTION_STROKE,\n sectionInk: LIGHT_OVERVIEW_SECTION_INK,\n focalFill: LIGHT_OVERVIEW_FOCAL_FILL,\n focalStroke: LIGHT_OVERVIEW_FOCAL_STROKE,\n }\n : {\n sectionFill: DARK_OVERVIEW_SECTION_FILL,\n sectionStroke: DARK_OVERVIEW_SECTION_STROKE,\n sectionInk: DARK_OVERVIEW_SECTION_INK,\n focalFill: DARK_OVERVIEW_FOCAL_FILL,\n focalStroke: DARK_OVERVIEW_FOCAL_STROKE,\n };\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.max(lo, Math.min(hi, v));\n\n/** Read a custom attr off an event target (Stage | Shape union isn't callable directly). */\nfunction seatIdOf(target: unknown): string | undefined {\n const n = target as { getAttr?: (k: string) => unknown } | null;\n return (n?.getAttr?.('seatId') as string | undefined) ?? undefined;\n}\n\n/** Mix a #rrggbb colour toward white by `amt` (0..1). */\nfunction lighten(hex: string, amt: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const r = (n >> 16) & 255;\n const g = (n >> 8) & 255;\n const b = n & 255;\n const mix = (c: number) => Math.round(c + (255 - c) * amt);\n return `#${((1 << 24) | (mix(r) << 16) | (mix(g) << 8) | mix(b)).toString(16).slice(1)}`;\n}\n\n/** Mix a #rrggbb colour toward black by `amt` (0..1). */\nfunction darken(hex: string, amt: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const mix = (c: number) => Math.round(c * (1 - amt));\n return `#${((1 << 24) | (mix((n >> 16) & 255) << 16) | (mix((n >> 8) & 255) << 8) | mix(n & 255)).toString(16).slice(1)}`;\n}\n\n/** Axis-aligned bounds of a polygon (no padding). */\nfunction polyBounds(pts: Point[]): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n}\n\nfunction rotatedRectPoints(center: Point, width: number, height: number, rotation: number): Point[] {\n const radians = rotation * Math.PI / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return [\n { x: -width / 2, y: -height / 2 },\n { x: width / 2, y: -height / 2 },\n { x: width / 2, y: height / 2 },\n { x: -width / 2, y: height / 2 },\n ].map((point) => ({\n x: center.x + point.x * cos - point.y * sin,\n y: center.y + point.x * sin + point.y * cos,\n }));\n}\n\nfunction pointsBounds(points: Point[]): { x: number; y: number; width: number; height: number } {\n const bounds = polyBounds(points);\n return { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height };\n}\n\n/**\n * Prove the whole rotated label rectangle remains on the filled shell. Sampling\n * a small grid (rather than corners alone) also catches a concave edge or aisle\n * hole passing through the middle of otherwise-valid corners.\n */\nfunction rotatedRectFitsPolygon(\n center: Point,\n width: number,\n height: number,\n rotation: number,\n outer: Point[],\n holes: Point[][],\n): boolean {\n const radians = rotation * Math.PI / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n for (let yStep = 0; yStep <= 4; yStep++) {\n for (let xStep = 0; xStep <= 6; xStep++) {\n const localX = width * (xStep / 6 - 0.5);\n const localY = height * (yStep / 4 - 0.5);\n const point = {\n x: center.x + localX * cos - localY * sin,\n y: center.y + localX * sin + localY * cos,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) return false;\n }\n }\n return true;\n}\n\n/** Centre-first interior anchors used when a hole/concavity occupies the shell centre. */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\n const centre = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n const points: Point[] = [preferred];\n for (let row = 1; row < 12; row += 1) {\n for (let column = 1; column < 12; column += 1) {\n const point = {\n x: bounds.x + bounds.width * column / 12,\n y: bounds.y + bounds.height * row / 12,\n };\n if (pointInPolygonWithHoles(point, outer, holes)) points.push(point);\n }\n }\n return points\n .sort((left, right) => Math.hypot(left.x - centre.x, left.y - centre.y)\n - Math.hypot(right.x - centre.x, right.y - centre.y))\n .filter((point, index, all) => index === all.findIndex((other) => (\n Math.abs(other.x - point.x) < 1e-6 && Math.abs(other.y - point.y) < 1e-6\n )));\n}\n\nfunction polygonWithHolesShape(\n outer: Point[],\n holes: Point[][] | undefined,\n attrs: { fill?: string; stroke?: string; strokeWidth?: number; opacity?: number; listening?: boolean },\n outerPath?: SectionOutlinePath,\n): Shape {\n const signedArea = (points: Point[]): number => points.reduce((sum, point, index) => {\n const next = points[(index + 1) % points.length];\n return sum + point.x * next.y - next.x * point.y;\n }, 0);\n const outerClockwise = signedArea(outer) > 0;\n return new Shape({\n ...attrs,\n sceneFunc(context, shape) {\n context.beginPath();\n const polygonPath = (points: Point[]) => {\n if (!points.length) return;\n context.moveTo(points[0].x, points[0].y);\n for (let index = 1; index < points.length; index += 1) context.lineTo(points[index].x, points[index].y);\n context.closePath();\n };\n const vectorPath = (path: SectionOutlinePath) => {\n context.moveTo(path.start.x, path.start.y);\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') context.lineTo(segment.end.x, segment.end.y);\n else if (segment.kind === 'arc') context.arc(\n segment.center.x,\n segment.center.y,\n segment.radius,\n Math.atan2(current.y - segment.center.y, current.x - segment.center.x),\n Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x),\n !segment.clockwise,\n );\n else context.bezierCurveTo(\n segment.control1.x, segment.control1.y,\n segment.control2.x, segment.control2.y,\n segment.end.x, segment.end.y,\n );\n current = segment.end;\n }\n context.closePath();\n };\n if (outerPath) vectorPath(outerPath);\n else polygonPath(outer);\n // Canvas' default non-zero rule cuts a hole only when its winding is the\n // opposite of the outer path. Normalize here so imported docs do not\n // depend on the order in which a client happened to serialize vertices.\n for (const hole of holes ?? []) {\n const holeClockwise = signedArea(hole) > 0;\n polygonPath(holeClockwise === outerClockwise ? [...hole].reverse() : hole);\n }\n context.fillStrokeShape(shape);\n },\n perfectDrawEnabled: false,\n });\n}\n\n/** #rrggbb → rgba() string at alpha `a`; passes non-hex through unchanged. */\nfunction rgba(hex: string, a: number): string {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${a})`;\n}\n\n/** Parse #rrggbb → [r,g,b] (0..255); null for non-hex. */\nfunction hexToRgb(hex: string): [number, number, number] | null {\n const m = /^#?([\\da-f]{6})$/i.exec(hex.trim());\n if (!m) return null;\n const n = parseInt(m[1], 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nconst toHex = (r: number, g: number, b: number): string =>\n `#${((1 << 24) | (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b)).toString(16).slice(1)}`;\n\n/**\n * Count-weighted RGB blend of member seat colours — a section reads as its\n * price makeup, not one flat colour. Falls back to `fallback` when empty.\n */\nfunction mixColors(parts: Array<{ hex: string; w: number }>, fallback: string): string {\n let r = 0;\n let g = 0;\n let b = 0;\n let tw = 0;\n for (const p of parts) {\n const rgb = hexToRgb(p.hex);\n if (!rgb || p.w <= 0) continue;\n r += rgb[0] * p.w;\n g += rgb[1] * p.w;\n b += rgb[2] * p.w;\n tw += p.w;\n }\n return tw > 0 ? toHex(r / tw, g / tw, b / tw) : fallback;\n}\n\n/** Linear interpolate between two #rrggbb colours (t 0..1); passes `a` through if unparseable. */\nfunction lerpColor(a: string, b: string, t: number): string {\n const ca = hexToRgb(a);\n const cb = hexToRgb(b);\n if (!ca || !cb) return a;\n return toHex(ca[0] + (cb[0] - ca[0]) * t, ca[1] + (cb[1] - ca[1]) * t, ca[2] + (cb[2] - ca[2]) * t);\n}\n\n/** Per-section render state for the block LOD rung (fills, labels, membership). */\ninterface SectionRender {\n id: string;\n /** Shared public management identity for disconnected visual components. */\n logicalId: string;\n label: string;\n outline: Point[];\n outlinePath?: SectionOutlinePath;\n holes: Point[][];\n centroid: Point;\n /** Deterministic centre-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n zone?: string;\n /** Seats whose centre falls inside the outline (first-match, doc order). */\n memberIds: string[];\n total: number;\n free: number;\n /** Category-mix (or explicit override) fill BEFORE the availability tint. */\n baseFill: string;\n outlineTint: string;\n /** Faint outline drawn under seats — the existing near-zoom look, untouched. */\n outlinePoly: Shape;\n /** Solid block fill that melts in at the block rung. */\n blockPoly: Shape;\n /** Section name (always drawn; brightens at the block rung, hides at zone rung). */\n nameLabel: Text;\n /** Availability retained for focused/detail UI, never painted on the overview shell. */\n subLabel: Text;\n /** Preferred name ink (labelStyle.color or the overview default) fed through\n * auto-contrast each frame so an authored colour survives the block melt. */\n preferredInk: string;\n /** labelStyle.size relative to the default (1 = default), scaling the fitted\n * screen-px band so a larger authored label reads larger in the overview. */\n labelScale: number;\n /** Responsive fit decisions for the current stage scale and local polygon span. */\n nameLabelFits: boolean;\n subLabelFits: boolean;\n /** Tier height (0 = floor). Lifts the section + members in iso (\"3D\") view. */\n elevation: number;\n /**\n * When elevation > 0, the section's bg nodes + member seats live in these\n * groups so a single position offset lifts the whole tier in iso view.\n */\n liftGroupBg: Group | null;\n liftGroupSeat: Group | null;\n /** Extruded side faces (one per outline edge) shown only as isoT rises. */\n sideFaces: Line[];\n}\n\n/** Per-zone render state for the farthest LOD rung. */\ninterface ZoneRender {\n id: string;\n anchor: Point;\n back: Rect;\n background: string;\n label: Text;\n sub: Text | null;\n}\n\nexport class SeatmapRenderer implements ISeatmapRenderer {\n private container: HTMLDivElement;\n private opts: Required<Pick<RendererOptions, 'maxSelection'>> & RendererOptions;\n\n private stage: Stage;\n private bgLayer: Layer;\n private seatLayer: Layer;\n private overlayLayer: Layer;\n private labelGroup: Group;\n\n private seats: ExpandedSeat[] = [];\n private seatById = new Map<string, ExpandedSeat>();\n /** Multi-floor (Batch 5): the last-set chart + which floor we're rendering. */\n private chartDoc: ChartDoc | null = null;\n private activeFloorId = '';\n /** When true on a multi-floor chart, render ALL floors stacked (3D overview). */\n private stacked = false;\n /** Interactive node per seat/booth — a Circle for seats, a Rect for booths. */\n private circleById = new Map<string, Shape>();\n /** Booth block geometry, keyed by booth id (= the unit's rowId). */\n private boothDims = new Map<string, { width: number; height: number; rotation: number }>();\n /** Booth labels live with the booth shape but obey the shared rendered-size LOD. */\n private boothLabelById = new Map<string, Text>();\n /** Viewport seat labels are rebuilt after each settled camera change. */\n private seatLabelById = new Map<string, Text>();\n /** Authored free-text nodes obey the same rendered-size visibility floor. */\n private freeTextById = new Map<string, {\n objectId?: string;\n node: Text;\n background: string;\n kind: RenderedFreeTextEvidence['kind'];\n categoryKey?: string;\n }>();\n /** Stage/rink landmarks retain a readable screen-space caption at overview. */\n private primaryFocalLabels = new Map<Text, number>();\n /** GA paint and text share price/highlight filter state. */\n private gaById = new Map<string, {\n label: string;\n capacity: number;\n categoryKey: string;\n points: Point[];\n polygon: Shape;\n effectiveBackground: string;\n /** GA inventory contained by a section is detail, not overview paint. */\n sectionId?: string;\n }>();\n private statusById = new Map<string, SeatStatus>();\n private catColor = new Map<string, string>();\n private theme: ChartTheme = {};\n /** Opaque paint actually visible behind transparent Konva canvases. */\n private canvasBackground = DEF_CANVAS_BACKGROUND;\n /** Effective selection/hover ring color — resolved per chart in setChart(). */\n private effSelection: string = DEF_SELECTION;\n /** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */\n private colorblind = false;\n /** Category order from the doc — the stable index into the CB palette. */\n private catOrder: string[] = [];\n\n private selection = new Set<string>();\n /** Whole-seat/block selection markers: outline + non-colour check cue. */\n private selectionMarkers = new Map<string, Group>();\n /** Held by this picker instance, not by another buyer. */\n private ownedHold = new Set<string>();\n /** One selected seat being inspected before it is committed to the cart. */\n private selectionFocusId: string | null = null;\n private hoverRing: Circle;\n /** Keyboard-navigation focus ring + the currently focused seat id. */\n private focusRing: Circle;\n private focusedId: string | null = null;\n /**\n * Accessibility filter: `null` = off; `[]` = dim all non-accessible free seats;\n * a type list = dim free seats lacking any of those accommodations.\n */\n private accessFilter: AccessibilityType[] | null = null;\n /** Category highlight (legend hover): dims free seats NOT of this category. */\n private categoryHighlight: string | null = null;\n /** Price-band filter (F4): dim free seats whose category is NOT in this set. */\n private categoryFilter: Set<string> | null = null;\n /** Commercial \"hide limited-view seats\" toggle: dim free seats flagged\n * restrictedView/obstructedView. Parallel to the accessibility filter. */\n private commercialLimitedFilter = false;\n\n // Section/zone overlays (bgLayer) — the 3-rung LOD: seats → section blocks →\n // zone blocks. Kept for the melt restyle and for hit-testing a zoomed-out tap.\n private sections: SectionRender[] = [];\n private zones: ZoneRender[] = [];\n private seatSection = new Map<string, SectionRender>();\n private catPrice = new Map<string, number>();\n /** ISO 4217 currency for on-map \"FROM …\" prices (undefined ⇒ money default). */\n private currency: string | undefined;\n /** Section/zone ids to render dimmed (organizer manager: held-back inventory). */\n private dimmedSections = new Set<string>();\n /** Organizer control-room velocity overlay; absent on buyer surfaces. */\n private sectionHeat = new Map<string, number>();\n /** Phase 2: section/zone ids in the event-level `closed` state — flat grey\n * block, seats greyed + not pickable, but the section stays rendered. */\n private closedSections = new Set<string>();\n /** AXS section-focus: the currently-focused section id (others dim), or null. */\n private focusedSectionId: string | null = null;\n /** Light backdrop panel drawn behind the focused section (removed on clear). */\n private focusBackdrop: Group | null = null;\n /** Object id → floor id (multi-floor only) — resolves a deck tap in the 3D stack. */\n private objectFloor = new Map<string, string>();\n /** Zone id → colour (drives extruded side faces in iso view). */\n private zoneColor = new Map<string, string>();\n private hasSections = false;\n /** seatLayer carries Text (booth labels) — gate the upright-label scan. */\n private hasBoothText = false;\n\n // Isometric (\"3D\") view — an affine skew/rotate + elevation lift, tweened.\n /** 0 = flat (default), 1 = full isometric; animated by setViewMode. */\n private isoT = 0;\n private isoTarget = 0;\n private isoRaf = 0;\n /** Chart centre the iso projection pivots about (bounds centre). */\n private isoCentre = { x: 0, y: 0 };\n /** rAF for an in-flight camera glide (focusRegion / setRung); 0 = none. */\n private glideRaf = 0;\n /** Set in destroy() so an in-flight iso tween bails. */\n private destroyed = false;\n /** Cached scale the section/zone labels were last sized for (scale-compensation). */\n private lodScale = 0;\n /** prefers-reduced-motion → hard-swap rungs instead of cross-fading. */\n private reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n private fitScale = 1;\n /** Effective seat radius (base × theme.seatScale), set per chart in setChart. */\n private seatR = SEAT_RADIUS;\n private bounds = { x: 0, y: 0, width: 1, height: 1 };\n private cached = false;\n private dpr = Math.min(typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, 2);\n\n private rafId = 0;\n private frames = 0;\n private lastFpsAt = 0;\n private recacheTimer: ReturnType<typeof setTimeout> | null = null;\n private resizeObs: ResizeObserver | null = null;\n /** Coalesces bursty view-change sources (pointermove, wheel) into ≤1 callback/frame. */\n private viewChangeRaf = 0;\n\n // Gesture state — pan/pinch are handled with raw pointer events on the\n // container (Konva stage dragging is off; its touch pipeline proved\n // unreliable for multi-touch on real devices).\n private pointers = new Map<number, { x: number; y: number }>();\n private pinch: { startDist: number; startScale: number; worldMid: { x: number; y: number } } | null = null;\n private panLast: { x: number; y: number } | null = null;\n private panStart: { x: number; y: number } | null = null;\n private panStarted = false;\n /** Maximum displacement from gesture start — suppress taps only after a real pan/pinch. */\n private moved = 0;\n /**\n * Manage-mode rubber-band marquee (option-gated). `start`/`cur` are WORLD-space\n * points (overlayLayer rides the stage transform); `rect` is the on-canvas\n * selection band. Null except during an active manage-mode drag.\n */\n private marquee: { start: { x: number; y: number }; rect: Rect } | null = null;\n private marqueeCur: { x: number; y: number } | null = null;\n\n constructor(container: HTMLDivElement, options: RendererOptions = {}) {\n this.container = container;\n this.opts = { maxSelection: 10, selectableStatuses: ['free'], ...options };\n this.currency = options.currency;\n\n Konva.pixelRatio = this.dpr;\n\n this.stage = new Stage({\n container,\n width: container.clientWidth || 1,\n height: container.clientHeight || 1,\n draggable: false, // pan/pinch are ours, via pointer events\n });\n\n container.style.touchAction = 'none';\n container.addEventListener('pointerdown', this.onPointerDown, { passive: false });\n container.addEventListener('pointermove', this.onPointerMove, { passive: false });\n container.addEventListener('pointerup', this.onPointerEnd, { passive: false });\n container.addEventListener('pointercancel', this.onPointerEnd, { passive: false });\n\n // Keyboard accessibility: the canvas is focusable and navigable seat-by-seat.\n if (container.tabIndex < 0) container.tabIndex = 0;\n container.setAttribute('role', 'application');\n if (!container.getAttribute('aria-label')) {\n container.setAttribute('aria-label', t('map.aria'));\n }\n container.addEventListener('keydown', this.onKeyDown);\n\n this.bgLayer = new Layer({ listening: true });\n this.seatLayer = new Layer({ listening: true });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n\n this.hoverRing = new Circle({\n radius: SEAT_RADIUS + 2,\n stroke: '#ffffff',\n strokeWidth: 2,\n opacity: 0.85,\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(this.hoverRing);\n\n this.focusRing = new Circle({\n radius: SEAT_RADIUS + 3,\n stroke: '#38bdf8',\n strokeWidth: 2.5,\n dash: [4, 3],\n opacity: 0.95,\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(this.focusRing);\n\n this.stage.add(this.bgLayer, this.seatLayer, this.overlayLayer);\n\n this.wireInteraction();\n this.startFpsLoop();\n\n if (import.meta.env.DEV) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObs = new ResizeObserver(() => this.handleResize());\n this.resizeObs.observe(container);\n }\n }\n\n // ---- ISeatmapRenderer -----------------------------------------------------\n\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void {\n // Multi-floor: render the active floor (2D) or all floors stacked (3D). `view`\n // scopes the chart accordingly — single-floor charts pass through (=== doc).\n // A fresh chart (new ref) resets to 2D; a re-render (same ref) preserves the mode.\n if (doc !== this.chartDoc) this.stacked = false;\n this.chartDoc = doc;\n this.activeFloorId = opts?.floorId ?? floorsOf(doc)[0].id;\n // Object id → floor id, for resolving which deck a tap hit in the 3D stack\n // (stackFloors keeps object ids, so the map holds across the flatten).\n this.objectFloor.clear();\n if (doc.floors && doc.floors.length > 1) {\n for (const f of doc.floors) for (const o of f.objects) this.objectFloor.set(o.id, f.id);\n }\n const view = this.floorView(doc);\n this.focusedId = null;\n this.focusRing.visible(false);\n this.bgLayer.destroyChildren();\n this.seatLayer.destroyChildren();\n this.labelGroup.destroyChildren();\n this.circleById.clear();\n this.boothDims.clear();\n this.boothLabelById.clear();\n this.seatLabelById.clear();\n this.freeTextById.clear();\n this.primaryFocalLabels.clear();\n this.gaById.clear();\n for (const marker of this.selectionMarkers.values()) marker.destroy();\n this.selectionMarkers.clear();\n this.ownedHold.clear();\n this.selectionFocusId = null;\n this.statusById.clear();\n this.selection.clear();\n this.seatById.clear();\n this.cached = false;\n this.accessFilter = null;\n this.sections = [];\n this.zones = [];\n this.seatSection.clear();\n // Section focus is a transient camera/view state. Carrying a section id\n // across a floor switch can match nothing on the next floor and dim every\n // newly rendered section as though it were a non-focused sibling.\n this.focusedSectionId = null;\n this.focusBackdrop = null;\n this.catPrice.clear();\n this.zoneColor.clear();\n this.lodScale = 0;\n this.hasBoothText = false;\n // Reloading the chart resets the view to flat (identity layer transforms).\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n this.isoT = 0;\n this.isoTarget = 0;\n this.resetLayerTransforms();\n this.hasSections = view.objects.some((o) => o.type === 'section');\n for (const z of doc.zones ?? []) if (z.color) this.zoneColor.set(z.id, z.color);\n // Seats fade against the block fill during the melt; reset to fully opaque.\n this.seatLayer.opacity(1);\n this.hoverRing.visible(false);\n\n this.theme = doc.theme ?? {};\n // Adjustable seat size: a chart-level scale on the base radius. Clamped so\n // enlarged seats don't collide with typical row spacing (~24 units).\n this.seatR = clamp(this.theme.seatScale ?? 1, 0.7, 1.6) * SEAT_RADIUS;\n // Resolve an unthemed embed against its real host surface once, then pin\n // that opaque paint on the renderer container. Rendering decisions and QA\n // evidence must describe the same pixels even when Konva stays transparent.\n this.container.style.background = '';\n this.canvasBackground = this.resolveCanvasBackground();\n this.container.style.background = this.canvasBackground;\n this.effSelection = this.resolveSelectionColor();\n this.hoverRing.stroke(this.effSelection);\n this.hoverRing.radius(this.seatR + 2);\n\n this.catColor.clear();\n this.catPrice.clear();\n this.catOrder = doc.categories.map((c) => c.key);\n for (const c of doc.categories) {\n this.catColor.set(c.key, c.color);\n if (typeof c.price === 'number') this.catPrice.set(c.key, c.price);\n }\n\n for (const obj of view.objects) {\n if (obj.type === 'booth') {\n this.boothDims.set(obj.id, { width: obj.width, height: obj.height, rotation: obj.rotation });\n }\n }\n\n this.seats = expandChart(view);\n for (const s of this.seats) {\n this.seatById.set(s.id, s);\n this.statusById.set(s.id, 'free');\n }\n\n this.renderBackground(view);\n this.renderSeats();\n // re-add overlay furniture wiped by destroyChildren above\n this.overlayLayer.add(this.labelGroup);\n this.overlayLayer.add(this.hoverRing);\n\n this.bounds = chartBounds(view);\n this.isoCentre = { x: this.bounds.x + this.bounds.width / 2, y: this.bounds.y + this.bounds.height / 2 };\n this.zoomToFit();\n }\n\n /** The chart to render: all floors stacked (3D overview), the active floor, or\n * the whole chart for single-floor charts. */\n private floorView(doc: ChartDoc): ChartDoc {\n if (!doc.floors || !doc.floors.length) return doc;\n if (this.stacked && doc.floors.length >= 2) return stackFloors(doc);\n const floor = doc.floors.find((f) => f.id === this.activeFloorId) ?? doc.floors[0];\n return { ...doc, objects: floor.objects, focalPoint: floor.focalPoint, backgroundImage: floor.backgroundImage, floors: undefined };\n }\n\n /** Toggle the 3D all-floors stacked overview (Batch 5). Re-renders; no-op on\n * single-floor charts. The caller re-applies statuses + animates the iso view. */\n setStacked(on: boolean): void {\n if (!this.chartDoc || on === this.stacked) return;\n const multi = !!this.chartDoc.floors && this.chartDoc.floors.length >= 2;\n if (!multi) return;\n this.stacked = on;\n this.setChart(this.chartDoc, { floorId: this.activeFloorId });\n }\n isStacked(): boolean {\n return this.stacked;\n }\n\n /** Switch which floor is shown (2D). Re-renders + re-fits; no-op if unchanged. */\n setActiveFloor(floorId: string): void {\n if (!this.chartDoc || floorId === this.activeFloorId) return;\n this.setChart(this.chartDoc, { floorId });\n }\n\n /** Floors for the host's switcher (single-floor charts return one synthetic floor). */\n getFloors(): { id: string; name: string }[] {\n return this.chartDoc ? floorsOf(this.chartDoc).map((f) => ({ id: f.id, name: f.name })) : [];\n }\n\n getActiveFloorId(): string {\n return this.activeFloorId;\n }\n\n setStatus(seatIds: string[], status: SeatStatus): void {\n let touched = false;\n // Sections whose availability tint / \"N LEFT\" needs a cheap recompute.\n const affected = this.hasSections ? new Set<SectionRender>() : null;\n for (const id of seatIds) {\n if (!this.statusById.has(id)) continue;\n const prev = this.statusById.get(id);\n this.statusById.set(id, status);\n const c = this.circleById.get(id);\n if (c) {\n this.paintSeat(c, id);\n touched = true;\n }\n if (affected) {\n const sec = this.seatSection.get(id);\n if (sec) {\n if ((prev === 'free') !== (status === 'free')) {\n sec.free += status === 'free' ? 1 : -1;\n }\n affected.add(sec);\n }\n }\n }\n if (affected && affected.size) {\n for (const sec of affected) this.refreshSectionFill(sec);\n this.bgLayer.batchDraw();\n }\n if (!touched) return;\n if (this.cached) {\n // bitmap is stale; debounce a re-cache so bulk updates coalesce\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.recacheTimer = setTimeout(() => this.cacheSeatLayer(), 150);\n } else {\n this.seatLayer.batchDraw();\n }\n if (this.effScale() > LABEL_SCALE) this.updateLabels();\n }\n\n setOwnedHold(seatIds: string[] | null): void {\n const next = new Set((seatIds ?? []).filter((id) => this.statusById.has(id)));\n const touched = new Set([...this.ownedHold, ...next]);\n this.ownedHold = next;\n for (const id of touched) {\n const shape = this.circleById.get(id);\n if (shape) this.paintSeat(shape, id);\n this.syncSelectionMarker(id);\n }\n if (!touched.size) return;\n if (this.cached) {\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.recacheTimer = setTimeout(() => this.cacheSeatLayer(), 150);\n } else {\n this.seatLayer.batchDraw();\n }\n if (this.effScale() > LABEL_SCALE) this.updateLabels();\n this.overlayLayer.batchDraw();\n }\n\n setSelectionFocus(seatId: string | null): void {\n const next = seatId && this.selection.has(seatId) ? seatId : null;\n if (next === this.selectionFocusId) return;\n const previous = this.selectionFocusId;\n this.selectionFocusId = next;\n\n for (const seat of this.seats) {\n const shape = this.circleById.get(seat.id);\n if (shape) this.paintSeat(shape, seat.id);\n }\n if (previous) this.syncSelectionMarker(previous);\n if (next) this.syncSelectionMarker(next);\n for (const [id, marker] of this.selectionMarkers) {\n marker.opacity(!next || id === next ? 1 : 0.2);\n }\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.overlayLayer.batchDraw();\n }\n\n getStatus(seatId: string): SeatStatus {\n return this.statusById.get(seatId) ?? 'free';\n }\n\n getSelection(): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n for (const id of this.selection) {\n const s = this.seatById.get(id);\n if (s) out.push(s);\n }\n return out;\n }\n\n clearSelection(): void {\n const ids = [...this.selection];\n for (const id of ids) this.setSelected(id, false, true);\n this.overlayLayer.batchDraw();\n }\n\n setMaxSelection(maxSelection: number): void {\n this.opts.maxSelection = Math.max(0, Math.floor(maxSelection));\n }\n\n select(seatIds: string[]): ExpandedSeat[] {\n const added: ExpandedSeat[] = [];\n for (const id of seatIds) {\n if (this.selection.has(id) || !this.isSelectable(id)) continue;\n if (this.selection.size >= this.opts.maxSelection) {\n this.opts.onSelectionLimit?.(this.opts.maxSelection);\n break;\n }\n this.setSelected(id, true, true);\n const seat = this.seatById.get(id);\n if (seat) added.push(seat);\n }\n if (added.length) this.overlayLayer.batchDraw();\n return added;\n }\n\n /** Switch organizer interaction in place so the host preserves camera, LOD,\n * focus and live status state while moving between Monitor and Block. */\n setManageInteraction(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void {\n if (this.marquee) this.cancelMarquee();\n this.panLast = null;\n this.panStart = null;\n this.panStarted = false;\n this.opts.manageMode = options.manageMode;\n this.opts.marqueeSelect = options.marqueeSelect;\n this.opts.selectableStatuses = [...options.selectableStatuses];\n if (options.maxSelection != null) this.opts.maxSelection = options.maxSelection;\n\n // A selection from a previous interaction mode must not remain actionable\n // after the new mode makes it read-only or changes its eligible statuses.\n const invalid = [...this.selection].filter((id) => !this.isSelectable(id));\n if (invalid.length) this.deselect(invalid);\n if (!options.manageMode && this.selection.size) this.clearSelection();\n this.container.style.cursor = 'default';\n this.overlayLayer.batchDraw();\n }\n\n /** Apply a non-destructive velocity treatment to section outlines. Seat\n * category/status fills remain untouched so heat never changes seat meaning. */\n setSectionHeat(scores: Record<string, number> | null): void {\n this.sectionHeat.clear();\n for (const [sectionId, raw] of Object.entries(scores ?? {})) {\n if (Number.isFinite(raw)) this.sectionHeat.set(sectionId, Math.max(0, Math.min(1, raw)));\n }\n for (const section of this.sections) this.refreshSectionHeat(section);\n this.bgLayer.batchDraw();\n }\n\n deselect(seatIds: string[]): void {\n let changed = false;\n for (const id of seatIds) {\n if (this.selection.has(id)) {\n this.setSelected(id, false, true);\n changed = true;\n }\n }\n if (changed) this.overlayLayer.batchDraw();\n }\n\n // ---- manage-mode bulk selection (SDK SeatManager) -------------------------\n // All option-gated: no-ops (or empty) unless `manageMode` is set, so buyer\n // surfaces that never pass the flag can't reach any of this.\n\n /** Select every selectable seat on the chart (⌘A). Returns the added seats. */\n selectAllSelectable(): ExpandedSeat[] {\n if (!this.opts.manageMode) return [];\n const ids: string[] = [];\n for (const seat of this.seats) if (this.isSelectable(seat.id)) ids.push(seat.id);\n return this.selectMany(ids);\n }\n\n /** Select the selectable seats matching these public labels (category/row/\n * section bulk resolves to labels host-side). Returns the newly added seats. */\n selectByLabels(labels: string[]): ExpandedSeat[] {\n if (!this.opts.manageMode) return [];\n const want = new Set(labels);\n const ids: string[] = [];\n for (const seat of this.seats) {\n if (want.has(seat.label) && this.isSelectable(seat.id)) ids.push(seat.id);\n }\n return this.selectMany(ids);\n }\n\n /** Exact SDK capture helper. MCP never accepts this id; the SDK derives it\n * from the persisted floor and uses the normal selected paint/ring path. */\n setEvidenceSelection(seatId: string): boolean {\n if (!this.seatById.has(seatId) || !this.isSelectable(seatId)) return false;\n if (this.selection.size) this.clearSelection();\n this.setSelected(seatId, true);\n this.overlayLayer.batchDraw();\n return this.selection.has(seatId);\n }\n\n /** Selectable seats in a section OR zone id — pure read (no selection change). */\n getSelectableInSection(sectionId: string): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n const seen = new Set<string>();\n for (const sec of this.sections) {\n if (sec.id !== sectionId && sec.logicalId !== sectionId && sec.zone !== sectionId) continue;\n for (const id of sec.memberIds) {\n if (seen.has(id)) continue;\n seen.add(id);\n if (!this.isSelectable(id)) continue;\n const s = this.seatById.get(id);\n if (s) out.push(s);\n }\n }\n return out;\n }\n\n /**\n * Union `ids` into the selection in one batched pass. Beyond MARQUEE_RING_CAP\n * total selected we skip the per-seat ring nodes (fill paint still marks the\n * seats) so a whole-arena select doesn't spawn thousands of Konva shapes.\n * Returns the full current selection.\n */\n private selectMany(ids: string[]): ExpandedSeat[] {\n const fresh = ids.filter((id) => !this.selection.has(id));\n if (!fresh.length) return this.getSelection();\n const drawRings = this.selection.size + fresh.length <= MARQUEE_RING_CAP;\n for (const id of fresh) {\n if (drawRings) {\n this.setSelected(id, true, true); // ring + fill, silent (batch draw below)\n } else {\n this.selection.add(id);\n const c = this.circleById.get(id);\n if (c) this.paintSeat(c, id);\n }\n }\n if (!this.cached) this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\n return this.getSelection();\n }\n\n // ---- manage-mode marquee gesture ------------------------------------------\n\n private beginMarquee(clientPt: { x: number; y: number }): void {\n const w = this.screenToWorld(clientPt);\n const s = this.stage.scaleX() || 1;\n const rect = new Rect({\n x: w.x,\n y: w.y,\n width: 0,\n height: 0,\n stroke: this.effSelection,\n strokeWidth: 1.5 / s, // world units → ~constant on-screen px under the stage scale\n dash: [5 / s, 4 / s],\n fill: 'rgba(110,123,255,0.10)',\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(rect);\n this.marquee = { start: w, rect };\n this.marqueeCur = w;\n this.overlayLayer.batchDraw();\n }\n\n private updateMarquee(clientPt: { x: number; y: number }): void {\n if (!this.marquee) return;\n const w = this.screenToWorld(clientPt);\n const { start, rect } = this.marquee;\n rect.setAttrs({\n x: Math.min(start.x, w.x),\n y: Math.min(start.y, w.y),\n width: Math.abs(w.x - start.x),\n height: Math.abs(w.y - start.y),\n });\n this.marqueeCur = w;\n this.overlayLayer.batchDraw();\n }\n\n private cancelMarquee(): void {\n if (!this.marquee) return;\n this.marquee.rect.destroy();\n this.marquee = null;\n this.marqueeCur = null;\n this.overlayLayer.batchDraw();\n }\n\n /**\n * Pointer-up: hit-test the marquee world-rect against the in-memory seat\n * centres (NOT the Konva hit-graph — that's a cached bitmap when zoomed and\n * far slower), keep only SELECTABLE seats, union them into the selection and\n * fire `onMarquee`. A near-zero drag reads as a click: clear the selection.\n */\n private finishMarquee(): void {\n const m = this.marquee;\n this.marquee = null;\n if (!m) return;\n m.rect.destroy();\n this.overlayLayer.batchDraw();\n const cur = this.marqueeCur ?? m.start;\n this.marqueeCur = null;\n const x0 = Math.min(m.start.x, cur.x);\n const x1 = Math.max(m.start.x, cur.x);\n const y0 = Math.min(m.start.y, cur.y);\n const y1 = Math.max(m.start.y, cur.y);\n const s = this.stage.scaleX() || 1;\n // Sub-4px drag = a click on empty canvas → deselect-all affordance.\n if ((x1 - x0) * s < 4 && (y1 - y0) * s < 4) {\n if (this.selection.size) {\n this.clearSelection();\n this.opts.onMarquee?.([]);\n }\n return;\n }\n const ids: string[] = [];\n for (const seat of this.seats) {\n if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;\n if (!this.isSelectable(seat.id)) continue;\n ids.push(seat.id);\n }\n this.selectMany(ids);\n this.opts.onMarquee?.(this.getSelection());\n }\n\n flashSeat(seatId: string, color = '#f43f5e'): void {\n const seat = this.seatById.get(seatId);\n if (!seat) return;\n const ring = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR,\n stroke: color,\n strokeWidth: 3,\n opacity: 0.9,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.overlayLayer.add(ring);\n const start = performance.now();\n const dur = 620;\n const step = (now: number): void => {\n // Guard against a destroy() mid-animation (layer torn down).\n if (!ring.getLayer()) return;\n const t = Math.min(1, (now - start) / dur);\n ring.radius(this.seatR * (1 + t * 1.8));\n ring.opacity(0.9 * (1 - t));\n this.overlayLayer.batchDraw();\n if (t < 1) requestAnimationFrame(step);\n else {\n ring.destroy();\n this.overlayLayer.batchDraw();\n }\n };\n requestAnimationFrame(step);\n }\n\n /**\n * Pulse a section outline without moving the camera or mutating the authored\n * geometry. The temporary halo is drawn in the non-listening overlay layer,\n * so the apparent 4% lift never changes hit testing or selection bounds.\n */\n flashSection(sectionId: string, color = '#22a06b'): void {\n const matches = this.sections.filter((section) =>\n section.id === sectionId || section.zone === sectionId);\n if (!matches.length) return;\n\n for (const section of matches) {\n const centre = section.outline.reduce(\n (sum, point) => ({ x: sum.x + point.x, y: sum.y + point.y }),\n { x: 0, y: 0 },\n );\n centre.x /= section.outline.length;\n centre.y /= section.outline.length;\n const lift = section.elevation > 0 ? this.isoLiftLocal(section.elevation) : { x: 0, y: 0 };\n const halo = new Line({\n x: centre.x + lift.x,\n y: centre.y + lift.y,\n points: section.outline.flatMap((point) => [point.x - centre.x, point.y - centre.y]),\n closed: true,\n stroke: color,\n strokeWidth: 3,\n strokeScaleEnabled: false,\n opacity: 0.92,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: true,\n shadowColor: color,\n shadowBlur: 14,\n shadowOpacity: 0.7,\n });\n this.overlayLayer.add(halo);\n this.overlayLayer.batchDraw();\n\n const remove = (): void => {\n if (!halo.getLayer()) return;\n halo.destroy();\n this.overlayLayer.batchDraw();\n };\n if (this.reducedMotion || (typeof document !== 'undefined' && document.hidden)) {\n setTimeout(remove, 520);\n continue;\n }\n\n const start = performance.now();\n const duration = 820;\n const step = (now: number): void => {\n if (this.destroyed || !halo.getLayer()) return;\n const t = Math.min(1, (now - start) / duration);\n const eased = 1 - Math.pow(1 - t, 3);\n const scale = 1 + eased * 0.04;\n halo.scale({ x: scale, y: scale });\n halo.opacity(0.92 * (1 - t));\n this.overlayLayer.batchDraw();\n if (t < 1) requestAnimationFrame(step);\n else remove();\n };\n requestAnimationFrame(step);\n }\n }\n\n // ---- keyboard navigation (accessibility) ----------------------------------\n\n private onKeyDown = (e: KeyboardEvent): void => {\n // Manage-mode bulk shortcuts: ⌘/Ctrl-A selects all selectable, Escape clears.\n // Both fire onMarquee so the SDK toolbar tracks selection through one path.\n if (this.opts.manageMode) {\n if ((e.metaKey || e.ctrlKey) && (e.key === 'a' || e.key === 'A')) {\n e.preventDefault();\n this.opts.onMarquee?.(this.selectAllSelectable());\n return;\n }\n if (e.key === 'Escape' && this.selection.size) {\n e.preventDefault();\n this.clearSelection();\n this.opts.onMarquee?.([]);\n return;\n }\n }\n const dir =\n e.key === 'ArrowLeft' ? { x: -1, y: 0 }\n : e.key === 'ArrowRight' ? { x: 1, y: 0 }\n : e.key === 'ArrowUp' ? { x: 0, y: -1 }\n : e.key === 'ArrowDown' ? { x: 0, y: 1 }\n : null;\n if (dir) {\n e.preventDefault();\n const next = this.focusedId ? this.nearestSeat(this.focusedId, dir) : this.seats[0]?.id ?? null;\n if (next) this.focusSeat(next);\n return;\n }\n if ((e.key === 'Enter' || e.key === ' ') && this.focusedId) {\n e.preventDefault();\n this.toggleSeat(this.focusedId);\n const s = this.seatById.get(this.focusedId);\n if (s) this.opts.onFocusSeat?.(s); // re-announce; status may have changed\n }\n };\n\n /** Nearest seat from `fromId` in a cardinal direction (aligned + close wins). */\n private nearestSeat(fromId: string, dir: { x: number; y: number }): string | null {\n const from = this.seatById.get(fromId);\n if (!from) return null;\n let best: string | null = null;\n let bestScore = Infinity;\n for (const s of this.seats) {\n if (s.id === fromId) continue;\n const dx = s.x - from.x;\n const dy = s.y - from.y;\n const proj = dx * dir.x + dy * dir.y; // along the chosen direction\n if (proj <= 0.5) continue; // must lie in that direction\n const perp = Math.abs(dx * dir.y - dy * dir.x); // lateral offset\n const score = proj + perp * 2.5; // reward alignment + proximity\n if (score < bestScore) {\n bestScore = score;\n best = s.id;\n }\n }\n return best;\n }\n\n private focusSeat(id: string): void {\n const seat = this.seatById.get(id);\n if (!seat) return;\n this.focusedId = id;\n this.focusRing.radius(this.seatR + 3);\n this.focusRing.position({ x: seat.x, y: seat.y });\n this.focusRing.visible(true);\n this.ensureVisible(seat);\n this.overlayLayer.batchDraw();\n this.opts.onFocusSeat?.(seat);\n }\n\n /** Pan/zoom so a seat sits on-screen at a legible scale (for keyboard focus). */\n private ensureVisible(seat: ExpandedSeat): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const target = Math.max(this.stage.scaleX(), SEAT_LEGIBLE_SCALE * 1.2);\n const p = this.worldToScreen(seat);\n const margin = 70;\n const offscreen = p.x < margin || p.x > w - margin || p.y < margin || p.y > h - margin;\n if (this.stage.scaleX() < target || offscreen) {\n // Centre on the PROJECTED seat position so iso view frames it correctly.\n const ip = this.isoT === 0 ? seat : this.isoForward(seat);\n this.stage.scale({ x: target, y: target });\n this.stage.position({ x: w / 2 - ip.x * target, y: h / 2 - ip.y * target });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n }\n\n zoomToFit(): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const b = this.bounds;\n this.fitScale = Math.min(w / b.width, h / b.height) || 1;\n const s = this.fitScale;\n this.stage.scale({ x: s, y: s });\n this.stage.position({\n x: (w - b.width * s) / 2 - b.x * s,\n y: (h - b.height * s) / 2 - b.y * s,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /** Step factor for the on-screen +/− buttons (B1) — same clamp path as pinch/wheel. */\n private static readonly ZOOM_STEP = 1.4;\n\n zoomIn(): void {\n const center = { x: this.stage.width() / 2, y: this.stage.height() / 2 };\n this.zoomAbout(this.stage.scaleX() * SeatmapRenderer.ZOOM_STEP, center);\n }\n\n zoomOut(): void {\n const center = { x: this.stage.width() / 2, y: this.stage.height() / 2 };\n this.zoomAbout(this.stage.scaleX() / SeatmapRenderer.ZOOM_STEP, center);\n }\n\n seatCount(): number {\n return this.seats.length;\n }\n\n bookableCount(): number {\n let total = this.seats.length;\n for (const area of this.gaById.values()) total += area.capacity;\n return total;\n }\n\n worldToScreen(point: Point): { x: number; y: number } {\n const s = this.stage.scaleX();\n // In iso view, host overlays (confirm card, tooltip) must anchor to the\n // PROJECTED seat, so run the point through the iso affine first. At isoT=0\n // isoForward is the identity — byte-for-byte the flat behaviour.\n const p = this.isoT === 0 ? point : this.isoForward(point);\n return { x: p.x * s + this.stage.x(), y: p.y * s + this.stage.y() };\n }\n\n setAccessibleFilter(on: boolean): void {\n this.setAccessibilityFilter(on ? [] : null);\n }\n\n setAccessibilityFilter(types: AccessibilityType[] | null): void {\n const next = types === null ? null : [...types];\n if (this.sameAccessFilter(next)) return;\n this.accessFilter = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n private sameAccessFilter(next: AccessibilityType[] | null): boolean {\n const cur = this.accessFilter;\n if (cur === null || next === null) return cur === next;\n return cur.length === next.length && cur.every((t, i) => t === next[i]);\n }\n\n /**\n * \"Hide limited-view seats\" toggle (commercial): when on, dim free, unselected\n * seats flagged restrictedView or obstructedView — the same visual dimming the\n * accessibility filter uses, just keyed off the seat's commercial attributes.\n */\n setCommercialLimitedFilter(on: boolean): void {\n if (this.commercialLimitedFilter === on) return;\n this.commercialLimitedFilter = on;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n /**\n * Price-band filter (F4): dim free, unselected seats whose category key is NOT\n * in `keys`. `null` clears the filter (all categories fully visible). The\n * widget resolves which categories fall inside the buyer's chosen band.\n */\n setCategoryFilter(keys: string[] | null): void {\n const next = keys === null ? null : new Set(keys);\n const same = (next === null && this.categoryFilter === null) ||\n (next !== null && this.categoryFilter !== null &&\n next.size === this.categoryFilter.size && [...next].every((k) => this.categoryFilter!.has(k)));\n if (same) return;\n this.categoryFilter = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.applyGAFilterState();\n }\n\n private gaCategoryDimmed(categoryKey: string): boolean {\n return Boolean(\n (this.categoryHighlight && categoryKey !== this.categoryHighlight)\n || (this.categoryFilter && !this.categoryFilter.has(categoryKey)),\n );\n }\n\n /** Keep GA paint and its two labels in the same legend/price-filter state. */\n private applyGAFilterState(): void {\n this.paintGAStateForView();\n this.updateFreeTextVisibility();\n this.bgLayer.batchDraw();\n }\n\n private paintGAStateForView(): void {\n for (const ga of this.gaById.values()) {\n const filteredOut = Boolean(this.categoryFilter && !this.categoryFilter.has(ga.categoryKey));\n const overviewHidden = ga.sectionId != null && this.effScale() < CACHE_THRESHOLD;\n ga.polygon.opacity(overviewHidden\n ? 0\n : this.gaCategoryDimmed(ga.categoryKey)\n ? GA_FILL_OPACITY * 0.08\n : GA_FILL_OPACITY);\n // A legend hover is only visual; a price-filter exclusion is not sellable\n // from the map until the filter is cleared.\n ga.polygon.listening(!overviewHidden && !filteredOut);\n }\n }\n\n /** Frame the currently available inventory that survived a buyer price\n * filter. Clearing the filter glides back to the full venue. */\n focusCategories(keys: string[] | null): void {\n if (!keys?.length) {\n this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });\n return;\n }\n const wanted = new Set(keys);\n const matching = this.seats.filter((seat) => {\n if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;\n const status = this.statusById.get(seat.id) ?? 'free';\n return status === 'free' || this.ownedHold.has(seat.id);\n });\n if (!matching.length) return;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const seat of matching) {\n minX = Math.min(minX, seat.x);\n maxX = Math.max(maxX, seat.x);\n minY = Math.min(minY, seat.y);\n maxY = Math.max(maxY, seat.y);\n }\n const pad = Math.max(24, this.seatR * 3);\n minX -= pad;\n maxX += pad;\n minY -= pad;\n maxY += pad;\n this.focusRegion(\n { x: minX, y: minY, width: Math.max(40, maxX - minX), height: Math.max(40, maxY - minY) },\n { durationMs: CAMERA_GLIDE_MS },\n );\n }\n\n // ---- isometric (\"3D\") view mode -------------------------------------------\n\n /**\n * Switch the projection between flat top-down and the isometric \"3D\" view\n * (rotate + y-squash about the chart centre, plus per-elevation lift). Tweens\n * `isoT` 0⇄1 over ~0.32s (ease in-out); reduced-motion snaps. Purely visual —\n * geometry stays flat, so hit-testing (Konva's own, plus the manual section\n * inverse) keeps landing on the projected seats/sections.\n */\n setViewMode(mode: 'flat' | 'isometric'): void {\n const target = mode === 'isometric' ? 1 : 0;\n this.isoTarget = target;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n if (this.reducedMotion) {\n this.isoT = target;\n this.applyIso();\n this.afterViewChange();\n return;\n }\n const from = this.isoT;\n if (from === target) { this.applyIso(); this.afterViewChange(); return; }\n const start = performance.now();\n const step = (now: number): void => {\n if (this.destroyed) return; // guard a destroy() mid-tween\n const raw = Math.min(1, (now - start) / ISO_TWEEN_MS);\n // easeInOutCubic — matches the melt's camera glide.\n const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;\n this.isoT = from + (this.isoTarget - from) * e;\n this.applyIso();\n this.scheduleViewChange();\n if (raw < 1) {\n this.isoRaf = requestAnimationFrame(step);\n } else {\n this.isoT = this.isoTarget;\n this.isoRaf = 0;\n this.applyIso();\n this.afterViewChange(); // re-evaluate cache/labels at the settled effective scale\n }\n };\n this.isoRaf = requestAnimationFrame(step);\n }\n\n /** Current projection — reflects the tween target, not the mid-tween isoT. */\n getViewMode(): 'flat' | 'isometric' {\n return this.isoTarget === 1 ? 'isometric' : 'flat';\n }\n\n /** Iso angle (rad) + y-squash for the current isoT. */\n private isoParams(): { th: number; sg: number } {\n return { th: (ISO_ANGLE_DEG * Math.PI) / 180 * this.isoT, sg: 1 - (1 - ISO_SQUASH) * this.isoT };\n }\n\n /** Effective vertical scale = stage scale × iso squash — legibility math uses this. */\n private effScale(): number {\n return this.stage.scaleX() * (1 - (1 - ISO_SQUASH) * this.isoT);\n }\n\n /** Project a world point through the iso affine about the chart centre (→ iso-world). */\n private isoForward(p: Point): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const c = this.isoCentre;\n const dx = p.x - c.x;\n const dy = p.y - c.y;\n const rx = dx * Math.cos(th) - dy * Math.sin(th);\n const ry = (dx * Math.sin(th) + dy * Math.cos(th)) * sg;\n return { x: c.x + rx, y: c.y + ry };\n }\n\n /** Inverse of isoForward (iso-world → world) for screen-space hit-testing. */\n private isoInverse(p: Point): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const c = this.isoCentre;\n const dx = p.x - c.x;\n const dy = p.y - c.y;\n const uy = dy / sg;\n const wx = dx * Math.cos(th) + uy * Math.sin(th);\n const wy = -dx * Math.sin(th) + uy * Math.cos(th);\n return { x: c.x + wx, y: c.y + wy };\n }\n\n /**\n * Local-space offset that, once the layer applies the iso affine, lifts an\n * object straight UP in iso-world by `elevation × LIFT_PER_STEP × isoT`\n * (= inverse-linear of the pure vertical lift). Zero at isoT=0.\n */\n private isoLiftLocal(elevation: number): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const delta = elevation * LIFT_PER_STEP * this.isoT;\n return { x: -(delta / sg) * Math.sin(th), y: -(delta / sg) * Math.cos(th) };\n }\n\n /** Restore the three layers to identity (flat) — byte-for-byte the original. */\n private resetLayerTransforms(): void {\n for (const layer of [this.bgLayer, this.seatLayer, this.overlayLayer]) {\n layer.position({ x: 0, y: 0 });\n layer.offset({ x: 0, y: 0 });\n layer.scale({ x: 1, y: 1 });\n layer.rotation(0);\n layer.skewX(0);\n layer.skewY(0);\n }\n }\n\n /**\n * Apply the current isoT to the scene: the base rotate+squash as a decomposed\n * layer transform (so seats/décor/rings project together and Konva's own\n * hit-testing follows), upright counter-transforms on text, and the elevation\n * lift + extruded side faces on elevated sections.\n */\n private applyIso(): void {\n const t = this.isoT;\n if (t === 0) {\n this.resetLayerTransforms();\n } else {\n const { th, sg } = this.isoParams();\n // L_iso = Scale(1,sg)·Rot(th) about the centre; decompose to Konva props.\n const a = Math.cos(th);\n const b = sg * Math.sin(th);\n const cc = -Math.sin(th);\n const d = sg * Math.cos(th);\n const r = Math.sqrt(a * a + b * b);\n const delta = a * d - b * cc; // = sg\n const rotationDeg = (Math.atan2(b, a) * 180) / Math.PI;\n const scaleX = r;\n const scaleY = delta / r;\n const skewX = (a * cc + b * d) / delta;\n const c = this.isoCentre;\n for (const layer of [this.bgLayer, this.seatLayer, this.overlayLayer]) {\n layer.position({ x: c.x, y: c.y });\n layer.offset({ x: c.x, y: c.y });\n layer.rotation(rotationDeg);\n layer.scaleX(scaleX);\n layer.scaleY(scaleY);\n layer.skewX(skewX);\n layer.skewY(0);\n }\n }\n\n this.applyUprightLabels();\n this.applyElevation();\n\n this.bgLayer.batchDraw();\n this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\n }\n\n /** Counter-skew every visible label so it renders upright at its projected anchor. */\n private applyUprightLabels(): void {\n const thDeg = ISO_ANGLE_DEG * this.isoT;\n const invScaleY = 1 / (1 - (1 - ISO_SQUASH) * this.isoT);\n // Seat labels live in overlayLayer (labelGroup); section/zone/décor in bgLayer.\n // Skip the seatLayer scan unless it actually holds booth labels (else it is\n // thousands of Circles with no Text).\n const layers = this.hasBoothText\n ? [this.bgLayer, this.seatLayer, this.overlayLayer]\n : [this.bgLayer, this.overlayLayer];\n for (const layer of layers) {\n const texts = layer.find('Text') as unknown as Text[];\n for (const tn of texts) {\n let base = tn.getAttr('uprightBase') as number | undefined;\n if (base == null) {\n base = tn.rotation();\n tn.setAttr('uprightBase', base);\n }\n tn.rotation(base - thDeg);\n tn.scaleX(1);\n tn.scaleY(invScaleY);\n tn.skewX(0);\n }\n }\n }\n\n /** Lift elevated sections (+ their members) and update their extruded side faces. */\n private applyElevation(): void {\n const t = this.isoT;\n for (const sec of this.sections) {\n if (sec.elevation <= 0) continue;\n const off = this.isoLiftLocal(sec.elevation);\n sec.liftGroupBg?.position(off);\n sec.liftGroupSeat?.position(off);\n // Side faces: quad per edge from base outline to the lifted outline, in\n // local (world) space — the layer projects them. Invisible at isoT=0.\n const alpha = 0.9 * t;\n for (let i = 0; i < sec.sideFaces.length; i++) {\n const face = sec.sideFaces[i];\n const p0 = sec.outline[i];\n const p1 = sec.outline[(i + 1) % sec.outline.length];\n face.points([p0.x, p0.y, p1.x, p1.y, p1.x + off.x, p1.y + off.y, p0.x + off.x, p0.y + off.y]);\n face.opacity(alpha);\n }\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.isoRaf) cancelAnimationFrame(this.isoRaf);\n if (this.glideRaf) cancelAnimationFrame(this.glideRaf);\n if (this.viewChangeRaf) cancelAnimationFrame(this.viewChangeRaf);\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.resizeObs?.disconnect();\n this.container.removeEventListener('pointerdown', this.onPointerDown);\n this.container.removeEventListener('pointermove', this.onPointerMove);\n this.container.removeEventListener('pointerup', this.onPointerEnd);\n this.container.removeEventListener('pointercancel', this.onPointerEnd);\n this.container.removeEventListener('keydown', this.onKeyDown);\n this.stage.destroy();\n }\n\n // ---- rendering ------------------------------------------------------------\n\n /** Theme font stack for all rendered text (falls back to Inter). */\n private labelFont(): string {\n return this.theme.fontFamily || 'Inter, sans-serif';\n }\n\n /**\n * Where a seat's nodes live: an elevated section's lift group (so the whole\n * tier shifts with one offset in iso view) or the seat layer directly.\n */\n private seatContainer(id: string): Group | Layer {\n return this.seatSection.get(id)?.liftGroupSeat ?? this.seatLayer;\n }\n\n private renderSeats(): void {\n for (const seat of this.seats) {\n if (seat.kind === 'booth') {\n this.renderBoothUnit(seat);\n continue;\n }\n const target = this.seatContainer(seat.id);\n const c = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n c.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, c);\n this.paintSeat(c, seat.id);\n target.add(c);\n // Accessible seats get a static 2px outer ring, coloured by their primary\n // accommodation (few per chart, so the extra node is cheap).\n if (seat.accessible) {\n target.add(\n new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR + 1,\n stroke: accessibilityRingColor(seat.accessibility),\n strokeWidth: 2,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n }),\n );\n }\n }\n }\n\n /** A booth renders as a click-selectable rounded block (dims from the doc). */\n private renderBoothUnit(seat: ExpandedSeat): void {\n const target = this.seatContainer(seat.id);\n const dims = this.boothDims.get(seat.rowId) ?? { width: 40, height: 30, rotation: 0 };\n const rect = new Rect({\n x: seat.x,\n y: seat.y,\n width: dims.width,\n height: dims.height,\n offsetX: dims.width / 2,\n offsetY: dims.height / 2,\n rotation: dims.rotation,\n cornerRadius: 4,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n rect.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, rect);\n target.add(rect);\n\n const t = new Text({\n x: seat.x,\n y: seat.y,\n text: seat.displayLabel ?? seat.label,\n fontSize: BOOTH_LABEL_FONT_SIZE,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n fill: this.theme.seatLabelColor ?? DEF_SEAT_LABEL,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.visible(false);\n this.boothLabelById.set(seat.id, t);\n this.hasBoothText = true; // gate the upright-label scan of the seat layer\n this.boothLabelById.set(seat.id, t);\n target.add(t);\n this.paintSeat(rect, seat.id);\n }\n\n /** The category's display color — Okabe-Ito hue when colorblind-safe is on. */\n private seatBaseColor(categoryKey: string): string {\n if (!this.colorblind) return this.catColor.get(categoryKey) ?? '#6e7bff';\n const idx = this.catOrder.indexOf(categoryKey);\n return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];\n }\n\n /** Per-seat authored label size relative to the neutral default (1 = default),\n * mirroring the section convention (labelStyle.size ?? 18) / 18. Only real\n * seats carry labelStyle, so booths and unstyled seats resolve to 1. */\n private seatLabelScale(seat: ExpandedSeat): number {\n return (seat.labelStyle?.size ?? 18) / 18;\n }\n\n /** Preferred label ink for a seat: the authored per-seat colour when set,\n * otherwise today's theme default. Fed through auto-contrast by seatLabelInk. */\n private seatPreferredLabelInk(seat: ExpandedSeat): string {\n return seat.labelStyle?.color ?? this.theme.seatLabelColor ?? DEF_SEAT_LABEL;\n }\n\n /** Resolve a seat's label ink against the paint actually visible, honouring an\n * authored per-seat colour through the same auto-contrast rule as sections. */\n private seatLabelInk(seat: ExpandedSeat, shape: Shape): string {\n const fill = shape.fill();\n return stateAwareBookableLabelInk(typeof fill === 'string' ? fill : '', this.seatPreferredLabelInk(seat));\n }\n\n /** Apply fill/stroke/opacity for a seat's current status + selection. */\n private paintSeat(c: Shape, id: string): void {\n const seat = this.seatById.get(id)!;\n const status = this.statusById.get(id) ?? 'free';\n const selected = this.selection.has(id);\n const base = this.seatBaseColor(seat.categoryKey);\n const boothLabel = this.boothLabelById.get(id);\n\n c.dash([]);\n c.strokeWidth(0);\n c.stroke('');\n c.opacity(1);\n\n switch (status) {\n case 'free':\n // Selected: on dark canvases the lightened fill + white ring pops; on\n // light canvases that same wash reads as *disabled*, so keep the full\n // category fill and let the dark contrast ring carry the state.\n c.fill(\n selected && this.effSelection === DEF_SELECTION ? lighten(base, 0.28) : base,\n );\n break;\n case 'held':\n if (this.ownedHold.has(id)) {\n // A buyer returning from checkout must be able to distinguish their\n // own inventory from somebody else's hold. Preserve the category\n // identity and outline the actual seat/booth shape (full rectangle\n // for a booth), rather than painting it generic unavailable grey.\n c.fill(lighten(base, this.effSelection === DEF_SELECTION ? 0.24 : 0.1));\n c.stroke(this.effSelection);\n c.strokeWidth(3);\n } else {\n c.fill(HELD_FILL);\n }\n break;\n case 'booked':\n if (this.colorblind) {\n // Non-color cue: booked reads as a hollow ring, never hue alone.\n c.fill('rgba(0,0,0,0)');\n c.stroke(TAKEN_FILL);\n c.strokeWidth(1.5);\n c.opacity(0.9);\n } else {\n c.fill(TAKEN_FILL);\n c.opacity(0.45);\n }\n break;\n case 'not_for_sale':\n c.fill(TAKEN_FILL);\n c.stroke(NFS_STROKE);\n c.strokeWidth(1);\n c.dash([2, 2]);\n break;\n }\n\n if (boothLabel) {\n boothLabel.text(status === 'booked' ? 'SOLD' : status === 'held' ? 'HELD' : seat.label);\n boothLabel.fontSize(status === 'free' ? 10 : Math.min(10, Math.max(6, this.boothDims.get(seat.rowId)?.width ?? 40) / 6));\n boothLabel.fontStyle(status === 'free' ? '600' : '800');\n boothLabel.fill(status === 'free' ? (this.theme.seatLabelColor ?? DEF_SEAT_LABEL) : '#ffffff');\n boothLabel.offsetX(boothLabel.width() / 2);\n boothLabel.offsetY(boothLabel.height() / 2);\n }\n\n // Accessibility filter dims free, unselected seats that don't match.\n if (this.accessFilter && status === 'free' && !selected && !seatMatchesAccess(seat, this.accessFilter)) {\n c.opacity(0.25);\n }\n // Legend hover-highlight dims free, unselected seats of other categories.\n if (this.categoryHighlight && status === 'free' && !selected && seat.categoryKey !== this.categoryHighlight) {\n c.opacity(0.25);\n }\n // Price-band filter (F4): dim free, unselected seats outside the chosen band.\n if (this.categoryFilter && status === 'free' && !selected && !this.categoryFilter.has(seat.categoryKey)) {\n c.opacity(0.22);\n }\n // \"Hide limited-view seats\": dim free, unselected seats with a restricted or\n // obstructed sightline so the clear-view seats stand out.\n if (this.commercialLimitedFilter && status === 'free' && !selected &&\n (seat.commercial?.restrictedView || seat.commercial?.obstructedView)) {\n c.opacity(0.22);\n }\n // Held-back inventory (organizer manager): seats in a dimmed section/zone\n // read as inactive so the map matches the Sections list at a glance.\n if (this.dimmedSections.size) {\n const sec = this.seatSection.get(id);\n if (sec && (\n this.dimmedSections.has(sec.id)\n || this.dimmedSections.has(sec.logicalId)\n || (sec.zone != null && this.dimmedSections.has(sec.zone))\n )) {\n c.opacity(0.18);\n }\n }\n // Phase 2 `closed` section: flat grey, 40% opacity, never a category hue —\n // overrides the status paint above. Seats stay visible but read off-sale.\n if (this.closedSections.size && this.seatInClosedSection(id)) {\n c.fill(CLOSED_SEAT_FILL);\n c.stroke('');\n c.strokeWidth(0);\n c.dash([]);\n c.opacity(CLOSED_SEAT_OPACITY);\n }\n // AXS section-focus: seats outside the focused section desaturate + dim so\n // the focused block reads against a calm ground (§4 focus spec).\n if (this.focusedSectionId) {\n const sec = this.seatSection.get(id);\n const inFocus = !!sec && (\n sec.id === this.focusedSectionId\n || sec.logicalId === this.focusedSectionId\n || sec.zone === this.focusedSectionId\n );\n if (!inFocus) c.opacity(FOCUS_DIM_OPACITY);\n }\n // Buyer confirmation focus: retain the candidate at full strength while\n // every unrelated seat recedes. Labels use the resulting opacity below so\n // the detail layer follows the same focus hierarchy as the seat geometry.\n if (this.selectionFocusId && id !== this.selectionFocusId) c.opacity(Math.min(c.opacity(), 0.16));\n const bookableLabel = this.boothLabelById.get(id) ?? this.seatLabelById.get(id);\n if (bookableLabel) {\n // Booths carry no labelStyle, so seatLabelInk resolves to today's theme\n // ink for them; real seats get their authored colour auto-contrasted.\n bookableLabel.fill(this.seatLabelInk(seat, c));\n bookableLabel.visible(\n isBookableLabelLegibleAtScale(bookableLabel.fontSize(), this.effScale())\n && c.opacity() >= 0.5,\n );\n }\n }\n\n /** True when a seat sits in a section/zone currently marked `closed`. */\n private seatInClosedSection(id: string): boolean {\n if (!this.closedSections.size) return false;\n const sec = this.seatSection.get(id);\n return !!sec && (\n this.closedSections.has(sec.id)\n || this.closedSections.has(sec.logicalId)\n || (sec.zone != null && this.closedSections.has(sec.zone))\n );\n }\n\n /**\n * Colorblind-safe mode: swap category hues for the Okabe-Ito palette and\n * render booked seats hollow. Off restores the exact default rendering.\n */\n setColorblindSafe(on: boolean): void {\n if (on === this.colorblind) return;\n this.colorblind = on;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n /**\n * Dim the seats of these section/zone ids (organizer manager use) so held-back\n * inventory is visually distinct on the canvas without hiding it. `null`/empty\n * clears. Unlike the buyer's applyHidden, the sections stay rendered.\n */\n setDimmedSections(ids: string[] | null): void {\n const next = new Set(ids ?? []);\n if (next.size === this.dimmedSections.size && [...next].every((i) => this.dimmedSections.has(i))) return;\n this.dimmedSections = next;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n }\n\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, but the section stays rendered\n * (unlike the buyer's applyHidden which strips it). `null`/empty clears.\n */\n setClosedSections(ids: string[] | null): void {\n const next = new Set(ids ?? []);\n if (next.size === this.closedSections.size && [...next].every((i) => this.closedSections.has(i))) return;\n this.closedSections = next;\n this.repaintSectionsAndSeats();\n }\n\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * panel behind this section's seats, and glide the camera in to frame it (the\n * seat-pick gate below only lets buyers pick once seats are ≥ LABEL_SCALE big).\n */\n focusSection(id: string): void {\n if (!this.sections.some((section) => section.id === id || section.logicalId === id)) return;\n this.focusedSectionId = id;\n this.drawFocusBackdrop(id);\n this.repaintSectionsAndSeats();\n this.updateLOD();\n this.focusRegion(id, { minScale: SEAT_FOCUS_SCALE });\n }\n\n /** Clear an AXS section focus — restore full-bowl brightness + drop the backdrop. */\n clearSectionFocus(): void {\n if (!this.focusedSectionId) return;\n this.focusedSectionId = null;\n if (this.focusBackdrop) {\n this.focusBackdrop.destroy();\n this.focusBackdrop = null;\n }\n this.repaintSectionsAndSeats();\n this.updateLOD();\n }\n\n /** The currently AXS-focused section id, or null. */\n getFocusedSection(): string | null {\n return this.focusedSectionId;\n }\n\n /** Draw (or replace) the light backdrop panel behind the focused section. */\n private drawFocusBackdrop(id: string): void {\n if (this.focusBackdrop) {\n this.focusBackdrop.destroy();\n this.focusBackdrop = null;\n }\n const sections = this.sections.filter((section) => section.id === id || section.logicalId === id);\n if (!sections.length) return;\n const backdrop = new Group({ listening: false });\n for (const section of sections) {\n backdrop.add(polygonWithHolesShape(section.outline, section.holes, {\n fill: FOCUS_BACKDROP_FILL,\n stroke: rgba('#ffffff', 0.1),\n strokeWidth: 1,\n listening: false,\n }, section.outlinePath));\n }\n this.bgLayer.add(backdrop);\n backdrop.moveToTop(); // above the dimmed sibling blocks, still under the seat layer\n this.focusBackdrop = backdrop;\n }\n\n /** Repaint every seat + section block to reflect closed/focus state, then redraw. */\n private repaintSectionsAndSeats(): void {\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n for (const sec of this.sections) sec.blockPoly.fill(this.sectionBlockFill(sec));\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.bgLayer.batchDraw();\n }\n\n /** The world-space rectangle currently visible in the viewport (minimap F3). */\n getVisibleWorldRect(): { x: number; y: number; width: number; height: number } {\n const tl = this.screenToWorld({ x: 0, y: 0 });\n const br = this.screenToWorld({ x: this.stage.width(), y: this.stage.height() });\n return {\n x: Math.min(tl.x, br.x),\n y: Math.min(tl.y, br.y),\n width: Math.abs(br.x - tl.x),\n height: Math.abs(br.y - tl.y),\n };\n }\n\n /** Axis-aligned world bounds of seats, section outlines, and GA polygons (minimap F3 frame). */\n getWorldBounds(): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n const grow = (x: number, y: number): void => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n for (const s of this.seats) grow(s.x, s.y);\n for (const sec of this.sections) for (const p of sec.outline) grow(p.x, p.y);\n for (const area of this.gaById.values()) for (const p of area.points) grow(p.x, p.y);\n if (!Number.isFinite(minX)) return { x: 0, y: 0, width: 1, height: 1 };\n return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n }\n\n /** Legend hover: highlight one category (dim the rest), or null to clear. */\n setCategoryHighlight(key: string | null): void {\n if (this.categoryHighlight === key) return;\n this.categoryHighlight = key;\n for (const seat of this.seats) {\n const c = this.circleById.get(seat.id);\n if (c) this.paintSeat(c, seat.id);\n }\n this.updateLabels();\n if (this.cached) {\n this.seatLayer.clearCache();\n this.cacheSeatLayer();\n } else {\n this.seatLayer.batchDraw();\n }\n this.applyGAFilterState();\n }\n\n private renderBackground(doc: ChartDoc): void {\n if (doc.backgroundImage) this.renderBackgroundImage(doc.backgroundImage);\n // Decor graphics (ice rink, court art) draw first so they sit UNDER the\n // section outlines and — being on bgLayer, below seatLayer entirely — under\n // every seat. listening(false) keeps them out of the hit graph.\n for (const obj of doc.objects) if (obj.type === 'decorImage') this.renderDecorImage(obj);\n // Sections sit under all other décor so their outlines never occlude seats.\n // NOTE(phase-2): event-level section open/closed/hidden state will gate this\n // draw + the seat membership below — hide/dim a section by id/zone here.\n for (const obj of doc.objects) if (obj.type === 'section') this.renderSection(obj);\n // Zone labels sit above section blocks (drawn after) — the farthest rung.\n this.renderZones(doc);\n for (const obj of doc.objects) {\n if (obj.type === 'shape') {\n this.renderShape(obj);\n } else if (obj.type === 'gaArea') {\n this.renderGA(obj);\n } else if (obj.type === 'table') {\n this.renderTable(obj);\n } else if (obj.type === 'text') {\n this.renderText(obj);\n }\n }\n // `focalPoint` is authoring geometry, not buyer-facing décor. The designer\n // exposes its guide only while the focal tool is active.\n }\n\n /** Organizer floor-plan photo, dimmed, at the very bottom of the bg layer. */\n private renderBackgroundImage(bg: NonNullable<ChartDoc['backgroundImage']>): void {\n if (!bg.url || bg.visible === false) return;\n const img = new window.Image();\n img.onload = () => {\n const natW = img.naturalWidth || 4;\n const natH = img.naturalHeight || 3;\n const rawCrop = bg.crop ?? { x: 0, y: 0, width: 1, height: 1 };\n const cropX = Math.max(0, Math.min(0.99, rawCrop.x));\n const cropY = Math.max(0, Math.min(0.99, rawCrop.y));\n const crop = {\n x: cropX,\n y: cropY,\n width: Math.max(0.01, Math.min(1 - cropX, rawCrop.width)),\n height: Math.max(0.01, Math.min(1 - cropY, rawCrop.height)),\n };\n const w = bg.width;\n const h = w * ((natH * crop.height) / (natW * crop.width));\n const node = new KImage({\n image: img,\n x: bg.center.x,\n y: bg.center.y,\n offsetX: w / 2,\n offsetY: h / 2,\n width: w,\n height: h,\n rotation: bg.rotation ?? 0,\n crop: {\n x: crop.x * natW,\n y: crop.y * natH,\n width: crop.width * natW,\n height: crop.height * natH,\n },\n opacity: bg.opacity,\n listening: false,\n });\n this.bgLayer.add(node);\n node.moveToBottom();\n this.bgLayer.batchDraw();\n };\n img.src = bg.url;\n }\n\n /**\n * A decor graphic (rink / court / stage art). The KImage node is added to the\n * bgLayer synchronously so it keeps its z-slot beneath the sections drawn right\n * after; the bitmap is decoded async and pasted in on load. A single node = a\n * single drawImage per frame, and it rides the same layer cache — effectively\n * zero per-frame cost. Never listens, so it can't intercept a seat click.\n */\n private renderDecorImage(obj: Extract<ChartDoc['objects'][number], { type: 'decorImage' }>): void {\n // Pass the (not-yet-loaded) Image element as the node's image: Konva draws\n // nothing until it decodes, then onload triggers a repaint. Keeps the node's\n // z-slot fixed beneath the sections drawn immediately after.\n const img = new window.Image();\n const node = new KImage({\n image: img,\n x: obj.x + obj.width / 2,\n y: obj.y + obj.height / 2,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation ?? 0,\n opacity: clamp(obj.opacity ?? 1, 0, 1),\n listening: false,\n perfectDrawEnabled: false,\n });\n this.bgLayer.add(node);\n img.onload = () => {\n if (!node.getLayer()) return; // chart swapped out before the image loaded\n this.bgLayer.batchDraw();\n };\n img.src = obj.href;\n }\n\n private renderTable(obj: Extract<ChartDoc['objects'][number], { type: 'table' }>): void {\n if (obj.shape === 'round') {\n this.bgLayer.add(\n new Circle({\n x: obj.center.x,\n y: obj.center.y,\n radius: obj.radius ?? 40,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n listening: false,\n }),\n );\n } else {\n const w = obj.width ?? 80;\n const h = obj.height ?? 50;\n this.bgLayer.add(\n new Rect({\n x: obj.center.x,\n y: obj.center.y,\n width: w,\n height: h,\n offsetX: w / 2,\n offsetY: h / 2,\n rotation: obj.rotation,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n cornerRadius: 4,\n listening: false,\n }),\n );\n }\n const label = this.addCentredLabel(this.bgLayer, obj.label, obj.center.x, obj.center.y, '#cbd5e1', 12, true);\n this.freeTextById.set(obj.id, { node: label, background: '#232c40', kind: 'table' });\n }\n\n private renderText(obj: Extract<ChartDoc['objects'][number], { type: 'text' }>): void {\n const background = this.canvasBackground;\n const preferredInk = obj.color ?? this.theme.textColor ?? DEF_TEXT;\n const node = new Text({\n x: obj.position.x,\n y: obj.position.y,\n text: obj.text,\n fontSize: obj.fontSize,\n rotation: obj.rotation,\n // Authored ink remains preferred, but an embed/theme surface can change\n // the actual canvas. Fail over to readable black/white instead of\n // painting an otherwise valid caption invisibly on that active surface.\n fill: stateAwareBookableLabelInk(background, preferredInk),\n fontFamily: this.labelFont(),\n listening: false,\n perfectDrawEnabled: false,\n });\n this.freeTextById.set(obj.id, {\n node,\n background,\n kind: 'free-text',\n });\n this.bgLayer.add(node);\n }\n\n private renderShape(obj: Extract<ChartDoc['objects'][number], { type: 'shape' }>): void {\n const authoredFill = obj.fill ?? this.theme.decorFill ?? DEF_DECOR_FILL;\n const isStage = obj.role === 'stage';\n const referenceFocal = obj.role === 'reference-focal';\n const isDecor = !!obj.role && !isStage;\n const palette = overviewPalette(this.canvasBackground);\n // A sampled source colour remains persisted on the object as evidence, but\n // the buyer overview renders the focal landmark as the same neutral visual\n // hierarchy as the supplied seating-chart target. Source black must not\n // become an unlabelled black hole in the generated chart.\n const fill = referenceFocal ? palette.focalFill : authoredFill;\n // Stage: darker at the back (min-y), brighter toward the audience edge (max-y).\n const stroke = isStage ? lighten(fill, 0.28) : referenceFocal ? palette.focalStroke : undefined;\n const strokeWidth = isStage ? 1 : referenceFocal ? 2 : 0;\n let cx = 0;\n let cy = 0;\n if (obj.kind === 'rect' && obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n const grad = isStage\n ? {\n fillLinearGradientStartPoint: { x: 0, y: 0 },\n fillLinearGradientEndPoint: { x: 0, y: obj.height },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n cx = obj.x + obj.width / 2;\n cy = obj.y + obj.height / 2;\n // Rotate about center: pivot at (cx,cy) via offset; local coords (and the\n // gradient) are unchanged, so the fill spans the box regardless of angle.\n this.bgLayer.add(\n new Rect({\n x: cx,\n y: cy,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n rotation: obj.rotation ?? 0,\n width: obj.width,\n height: obj.height,\n ...grad,\n stroke,\n strokeWidth,\n cornerRadius: 4,\n listening: false,\n }),\n );\n } else if (obj.kind === 'ellipse' && obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n cx = obj.x + obj.width / 2;\n cy = obj.y + obj.height / 2;\n const grad = isStage\n ? {\n fillLinearGradientStartPoint: { x: 0, y: -obj.height / 2 },\n fillLinearGradientEndPoint: { x: 0, y: obj.height / 2 },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n this.bgLayer.add(\n new Ellipse({ x: cx, y: cy, rotation: obj.rotation ?? 0, radiusX: obj.width / 2, radiusY: obj.height / 2, ...grad, stroke, strokeWidth, listening: false }),\n );\n } else if (obj.kind === 'polygon' && obj.points && obj.points.length) {\n const pts = obj.points.flatMap((p) => [p.x, p.y]);\n const b = polyBounds(obj.points);\n cx = obj.points.reduce((a, p) => a + p.x, 0) / obj.points.length;\n cy = obj.points.reduce((a, p) => a + p.y, 0) / obj.points.length;\n const grad = isStage\n ? {\n // Line points are absolute chart coords; the gradient endpoints share\n // that space and rotate with the node (pivot at the centroid below).\n fillLinearGradientStartPoint: { x: 0, y: b.y },\n fillLinearGradientEndPoint: { x: 0, y: b.y + b.height },\n fillLinearGradientColorStops: [0, darken(fill, 0.3), 1, lighten(fill, 0.12)],\n }\n : { fill };\n // Rotate about the centroid: position=offset=centroid leaves the polygon\n // in place at rotation 0 and pivots there for any angle.\n this.bgLayer.add(\n new Line({ points: pts, closed: true, x: cx, y: cy, offsetX: cx, offsetY: cy, rotation: obj.rotation ?? 0, ...grad, stroke, strokeWidth, listening: false }),\n );\n }\n if (obj.label) {\n if (isStage) {\n const node = this.addStageLabel(cx, cy, obj.label, fill);\n this.primaryFocalLabels.set(node, 22);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'stage' });\n }\n else if (isDecor) {\n // A compiled reference focal is a primary orientation landmark, not\n // quiet furniture. Keep its desktop overview label above the shared\n // 12px rendered floor and choose ink against the actual source fill.\n // Ordinary décor retains the subdued treatment.\n const node = this.addCentredLabel(\n this.bgLayer,\n obj.label,\n cx,\n cy,\n referenceFocal ? stateAwareBookableLabelInk(fill, '#e6e9f0') : '#9aa3b5',\n referenceFocal ? 18 : 12,\n false,\n );\n if (referenceFocal) this.primaryFocalLabels.set(node, 18);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'decor' });\n } else {\n const node = this.addCentredLabel(this.bgLayer, obj.label, cx, cy, '#cbd5e1', 16, true);\n this.freeTextById.set(obj.id, { node, background: fill, kind: 'decor' });\n }\n }\n }\n\n /** Prominent stage caption: uppercase, letter-spaced, larger, softly dimmed. */\n private addStageLabel(x: number, y: number, text: string, background: string): Text {\n const ink = stateAwareBookableLabelInk(background, '#e6e9f0');\n const t = new Text({\n x,\n y,\n text: text.toUpperCase(),\n fontSize: 22,\n fontStyle: '700',\n letterSpacing: 4,\n fontFamily: this.labelFont(),\n fill: ink,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n this.bgLayer.add(t);\n return t;\n }\n\n private renderGA(obj: Extract<ChartDoc['objects'][number], { type: 'gaArea' }>): void {\n const color = this.catColor.get(obj.categoryKey) ?? '#6e7bff';\n const canvas = this.canvasBackground;\n const effectiveBackground = compositeHexOver(color, canvas, GA_FILL_OPACITY);\n const preferredInk = this.theme.textColor ?? '#e6e9f0';\n const ink = stateAwareBookableLabelInk(effectiveBackground, preferredInk);\n const poly = polygonWithHolesShape(obj.points, obj.holes, {\n fill: color,\n opacity: GA_FILL_OPACITY,\n stroke: color,\n strokeWidth: 1.5,\n });\n poly.setAttr('gaId', obj.id);\n poly.on('click tap', () => this.opts.onGAClick?.(obj.id));\n poly.on('mouseenter', () => {\n this.container.style.cursor = 'pointer';\n });\n poly.on('mouseleave', () => {\n this.container.style.cursor = 'default';\n });\n this.bgLayer.add(poly);\n\n const labelPoint = polygonLabelPoint(obj.points, obj.holes);\n const containingSection = this.sections.find((section) => (\n pointInPolygonWithHoles(labelPoint, section.outline, section.holes)\n ));\n const label = this.addCentredLabel(this.bgLayer, obj.label, labelPoint.x, labelPoint.y - 8, ink, GA_LABEL_FONT_SIZE, false);\n const capacity = this.addCentredLabel(this.bgLayer, `cap ${obj.capacity}`, labelPoint.x, labelPoint.y + 10, ink, GA_CAPACITY_LABEL_FONT_SIZE, false);\n this.freeTextById.set(`${obj.id}:label`, {\n objectId: obj.id,\n node: label,\n background: effectiveBackground,\n kind: 'ga-label',\n categoryKey: obj.categoryKey,\n });\n this.freeTextById.set(`${obj.id}:capacity`, {\n objectId: obj.id,\n node: capacity,\n background: effectiveBackground,\n kind: 'ga-capacity',\n categoryKey: obj.categoryKey,\n });\n this.gaById.set(obj.id, {\n label: obj.label,\n capacity: obj.capacity,\n categoryKey: obj.categoryKey,\n points: obj.points,\n polygon: poly,\n effectiveBackground,\n ...(containingSection ? { sectionId: containingSection.logicalId } : {}),\n });\n }\n\n /**\n * A section renders in three coordinated layers driven by the LOD melt:\n * • a faint outline (the existing near-zoom look, untouched),\n * • a neutral solid shell that fades in at the overview rung, and\n * • one readable, contained section name.\n * Category, row, seat, and availability detail belongs to section focus/zoom.\n * Membership and category mix are still precomputed for the detailed state.\n */\n private renderSection(obj: SectionObject): void {\n const centroid = polygonLabelPoint(obj.outline, obj.holes);\n const palette = overviewPalette(this.canvasBackground);\n\n // Membership: seats inside the outline, first section (doc order) wins.\n const memberIds: string[] = [];\n const catCounts = new Map<string, number>();\n let free = 0;\n for (const seat of this.seats) {\n if (this.seatSection.has(seat.id)) continue;\n if (!pointInPolygonWithHoles(seat, obj.outline, obj.holes)) continue;\n memberIds.push(seat.id);\n catCounts.set(seat.categoryKey, (catCounts.get(seat.categoryKey) ?? 0) + 1);\n if ((this.statusById.get(seat.id) ?? 'free') === 'free') free++;\n }\n\n // Category-mix fill: explicit override wins, else blend member colours by count.\n const baseFill =\n obj.color ??\n mixColors(\n [...catCounts].map(([key, w]) => ({ hex: this.catColor.get(key) ?? '#6e7bff', w })),\n '#3a4358',\n );\n\n // Elevation: elevated sections lift as one tier in the iso view, so their bg\n // nodes + member seats go into lift groups (positioned in applyElevation).\n // Side faces (a zone-coloured quad per outline edge) extrude only as isoT rises.\n const elevation = Math.max(0, Math.round(obj.elevation ?? 0));\n let liftGroupBg: Group | null = null;\n let liftGroupSeat: Group | null = null;\n const sideFaces: Line[] = [];\n if (elevation > 0) {\n const faceFill = darken(this.zoneColor.get(obj.zone ?? '') ?? baseFill, 0.42);\n for (let i = 0; i < obj.outline.length; i++) {\n const face = new Line({\n points: [],\n closed: true,\n fill: faceFill,\n stroke: rgba('#000000', 0.25),\n strokeWidth: 1,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n sideFaces.push(face);\n this.bgLayer.add(face); // behind the group added next → behind the fill\n }\n liftGroupBg = new Group({ listening: false });\n this.bgLayer.add(liftGroupBg);\n liftGroupSeat = new Group({ listening: false });\n this.seatLayer.add(liftGroupSeat);\n }\n const bgTarget: Group | Layer = liftGroupBg ?? this.bgLayer;\n\n // Zone-coloured outline under the seats — matches the crisp section blocks\n // the designer draws, so the near-zoom map reads as defined zones too.\n const outlineTint = obj.color ?? this.zoneColor.get(obj.zone ?? '') ?? '#3a4358';\n const outlinePoly = polygonWithHolesShape(obj.outline, obj.holes, {\n stroke: rgba(outlineTint, 0.5),\n strokeWidth: 1.75,\n fill: rgba(outlineTint, 0.08),\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(outlinePoly);\n\n // Neutral overview shell — category paint is intentionally deferred until\n // focus/seat detail so the venue hierarchy remains legible at first glance.\n const blockPoly = polygonWithHolesShape(obj.outline, obj.holes, {\n fill: palette.sectionFill,\n stroke: palette.sectionStroke,\n strokeWidth: SECTION_STROKE_PX,\n opacity: 0,\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(blockPoly);\n\n // Per-section label overrides (size/color) layered on the overview defaults.\n // color becomes the preferred ink the block-melt loop auto-contrasts each\n // frame; size scales the fitted screen-px band (default section size = 18).\n const labelStyle = obj.labelPresentation?.labelStyle;\n const preferredInk = labelStyle?.color ?? palette.sectionInk;\n const labelScale = (labelStyle?.size ?? 18) / 18;\n const nameLabel = new Text({\n x: obj.labelPresentation?.position?.x ?? centroid.x,\n y: obj.labelPresentation?.position?.y ?? centroid.y,\n text: obj.displayLabel ?? obj.label,\n rotation: obj.labelPresentation?.rotation ?? 0,\n visible: obj.labelPresentation?.visible !== false,\n fontSize: 22 * labelScale,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: stateAwareBookableLabelInk(palette.sectionFill, preferredInk),\n listening: false,\n perfectDrawEnabled: false,\n });\n nameLabel.offsetX(nameLabel.width() / 2);\n nameLabel.offsetY(nameLabel.height() / 2);\n bgTarget.add(nameLabel);\n\n const subLabel = new Text({\n x: centroid.x,\n y: centroid.y,\n text: t('map.seatsLeft', { count: free }),\n fontSize: 12,\n fontStyle: '700',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: palette.sectionInk,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n subLabel.offsetX(subLabel.width() / 2);\n bgTarget.add(subLabel);\n\n const sec: SectionRender = {\n id: obj.id,\n logicalId: obj.logicalSectionId ?? obj.id,\n label: obj.displayLabel ?? obj.label,\n outline: obj.outline,\n ...(obj.outlinePath ? { outlinePath: obj.outlinePath } : {}),\n holes: obj.holes ?? [],\n centroid,\n labelAnchors: polygonLabelCandidates(obj.outline, obj.holes ?? [], centroid),\n zone: obj.zone,\n memberIds,\n total: memberIds.length,\n free,\n baseFill,\n outlineTint,\n outlinePoly,\n blockPoly,\n nameLabel,\n subLabel,\n preferredInk,\n labelScale,\n nameLabelFits: true,\n subLabelFits: true,\n elevation,\n liftGroupBg,\n liftGroupSeat,\n sideFaces,\n };\n for (const id of memberIds) this.seatSection.set(id, sec);\n this.refreshSectionFill(sec);\n this.refreshSectionHeat(sec);\n this.sections.push(sec);\n }\n\n private refreshSectionHeat(sec: SectionRender): void {\n const raw = this.sectionHeat.get(sec.id)\n ?? this.sectionHeat.get(sec.logicalId)\n ?? (sec.zone ? this.sectionHeat.get(sec.zone) : undefined);\n if (raw == null || raw <= 0) {\n sec.outlinePoly.stroke(rgba(sec.outlineTint, 0.5));\n sec.outlinePoly.fill(rgba(sec.outlineTint, 0.08));\n sec.outlinePoly.strokeWidth(1.75);\n sec.outlinePoly.shadowOpacity(0);\n return;\n }\n const color = lerpColor('#f4b740', '#ef4444', raw);\n sec.outlinePoly.stroke(rgba(color, 0.72 + raw * 0.25));\n sec.outlinePoly.fill(rgba(color, 0.08 + raw * 0.13));\n sec.outlinePoly.strokeWidth(2 + raw * 3.5);\n sec.outlinePoly.shadowColor(color);\n sec.outlinePoly.shadowBlur(4 + raw * 12);\n sec.outlinePoly.shadowOpacity(0.25 + raw * 0.45);\n }\n\n /** Recompute a section's neutral overview state and retained detail count. */\n private refreshSectionFill(sec: SectionRender): void {\n sec.blockPoly.fill(this.sectionBlockFill(sec));\n sec.subLabel.text(t('map.seatsLeft', { count: sec.free }));\n sec.subLabel.offsetX(sec.subLabel.width() / 2);\n }\n\n /** True when a section/zone is currently in the `closed` event-state. */\n private isSectionClosed(sec: SectionRender): boolean {\n return this.closedSections.has(sec.id)\n || this.closedSections.has(sec.logicalId)\n || (sec.zone != null && this.closedSections.has(sec.zone));\n }\n\n /** Clean overview shells never leak category, price, or live availability paint. */\n private sectionBlockFill(sec: SectionRender): string {\n const fill = overviewPalette(this.canvasBackground).sectionFill;\n return this.isSectionClosed(sec) ? darken(fill, 0.12) : fill;\n }\n\n /**\n * Zone rung: one giant screen-constant label per zone (+ optional \"FROM $n\"),\n * shown at the farthest zoom in place of per-section detail. Skipped entirely\n * when the doc declares no zones — sections then stay the far rung (graceful).\n */\n private renderZones(doc: ChartDoc): void {\n if (!doc.zones?.length || !this.sections.length) return;\n const byZone = new Map<string, SectionRender[]>();\n for (const sec of this.sections) {\n if (!sec.zone) continue;\n (byZone.get(sec.zone) ?? byZone.set(sec.zone, []).get(sec.zone)!).push(sec);\n }\n for (const z of doc.zones) {\n const members = byZone.get(z.id);\n if (!members || !members.length) continue;\n // Anchor at the TOPMOST member (min y), not the mean centroid: for a\n // symmetric bowl (a zone = a full ring around the stage) the mean lands on\n // the origin and every zone label stacks on the stage. The topmost member\n // gives a distinct point per ring (labels stack up the vertical axis).\n let anchor = members[0];\n for (const s of members) if (s.centroid.y < anchor.centroid.y) anchor = s;\n const cx = anchor.centroid.x;\n const cy = anchor.centroid.y;\n\n // \"FROM $n\" = cheapest category price found among this zone's member seats.\n let minPrice = Infinity;\n for (const sec of members) {\n for (const id of sec.memberIds) {\n const seat = this.seatById.get(id);\n const p = seat && this.catPrice.get(seat.categoryKey);\n if (typeof p === 'number' && p < minPrice) minPrice = p;\n }\n }\n\n // A zone name often extends beyond its irregular section polygon. Give\n // the entire caption an opaque, measured backing instead of choosing ink\n // against only the anchor section and then painting part of that text over\n // the surrounding canvas.\n const back = new Rect({\n x: cx,\n y: cy,\n width: 1,\n height: 1,\n offsetX: 0.5,\n offsetY: 0.5,\n cornerRadius: 1,\n fill: HIERARCHY_PILL_BACKGROUND,\n stroke: z.color ?? anchor.outlineTint,\n strokeWidth: 1,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n this.bgLayer.add(back);\n\n const label = new Text({\n x: cx,\n y: cy,\n text: z.label.toUpperCase(),\n fontSize: ZONE_LABEL_PX,\n fontStyle: '800',\n letterSpacing: 0.5,\n fontFamily: this.labelFont(),\n fill: '#f4f6fb',\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n label.offsetX(label.width() / 2);\n label.offsetY(label.height() / 2);\n this.bgLayer.add(label);\n\n let sub: Text | null = null;\n if (isFinite(minPrice)) {\n sub = new Text({\n x: cx,\n y: cy,\n text: t('map.fromPrice', { price: formatMoney(minPrice, this.currency) }),\n fontSize: 14,\n fontStyle: '600',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: '#cbd5e1',\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n sub.offsetX(sub.width() / 2);\n this.bgLayer.add(sub);\n }\n this.zones.push({\n id: z.id,\n anchor: { x: cx, y: cy },\n back,\n background: HIERARCHY_PILL_BACKGROUND,\n label,\n sub,\n });\n }\n }\n\n /**\n * THE MELT — a continuous, scale-driven cross-fade across the three rungs:\n * seats ⇄ section blocks ⇄ zone blocks.\n * `blockT` ramps 0→1 as scale falls through [SECTION_PROMINENT, CACHE_THRESHOLD]\n * so the solid fill is fully present exactly as seats become the cached bitmap\n * and fade out; `zoneT` ramps 0→1 across [ZONE_PROMINENT, SECTION_PROMINENT] so\n * per-section detail hands off to giant zone labels. Reduced-motion hard-swaps.\n * Section/zone labels are scale-compensated to hold a roughly constant screen size.\n */\n private applySectionLod(scale: number): void {\n let blockT: number;\n let zoneT: number;\n if (this.reducedMotion) {\n blockT = scale <= SECTION_PROMINENT_SCALE ? 1 : 0;\n zoneT = scale <= ZONE_PROMINENT_SCALE ? 1 : 0;\n } else {\n blockT = clamp((BLOCK_MELT_TOP - scale) / (BLOCK_MELT_TOP - SECTION_PROMINENT_SCALE), 0, 1);\n zoneT = clamp((SECTION_PROMINENT_SCALE - scale) / (SECTION_PROMINENT_SCALE - ZONE_PROMINENT_SCALE), 0, 1);\n }\n // The overview rung is a crisp semantic composition. Finish the melt before\n // entering it so no residual seats or category outlines leak through simply\n // because zoom-to-fit landed a few hundredths below the detail threshold.\n const sectionOverview = scale < CACHE_THRESHOLD;\n if (sectionOverview) blockT = 1;\n // No zones ⇒ skip the zone rung: sections stay the far rung (graceful).\n if (!this.zones.length) zoneT = 0;\n\n // Seats melt out as the block fill melts in (coordinated with the bitmap swap).\n this.seatLayer.opacity(sectionOverview ? 0 : 1 - blockT);\n\n // Labels are drawn UPRIGHT (the iso squash is cancelled per-text), so their\n // on-screen size follows the raw stage scale, not the squashed effective one.\n const sx = this.stage.scaleX();\n // Scale-compensate label sizes only when the scale meaningfully changed.\n const rescale = this.lodScale === 0 || Math.abs(scale - this.lodScale) / (this.lodScale || 1) > 0.02;\n if (rescale) this.lodScale = scale;\n\n const focus = this.focusedSectionId;\n const palette = overviewPalette(this.canvasBackground);\n // Avoid a ghosted label during the first 20% of the block melt, when\n // individual bookable shapes are still the dominant visual layer.\n const sectionLabelT = clamp((blockT - 0.2) / 0.8, 0, 1);\n for (const sec of this.sections) {\n // AXS focus: non-focused sections dim to ~16%; the focused block stays full.\n const dim = focus && sec.id !== focus && sec.logicalId !== focus && sec.zone !== focus ? FOCUS_DIM_OPACITY : 1;\n // Category-tinted detail outlines disappear as the clean shell takes over.\n sec.outlinePoly.opacity(sectionOverview ? 0 : (1 - blockT) * dim);\n sec.blockPoly.opacity(BLOCK_FILL_ALPHA * blockT * dim);\n sec.blockPoly.stroke(palette.sectionStroke);\n sec.blockPoly.strokeWidth(SECTION_STROKE_PX / Math.max(sx, 0.0001));\n // Section names belong to the block rung. Hide them completely once\n // individual seats/booths are the active layer so they cannot sit under\n // bookable labels or shapes.\n const sectionFill = sec.blockPoly.fill();\n const sectionInk = stateAwareBookableLabelInk(\n typeof sectionFill === 'string' ? sectionFill : sec.baseFill,\n sec.preferredInk,\n );\n sec.nameLabel.fill(sectionInk);\n sec.subLabel.fill(sectionInk);\n if (rescale) this.fitSectionRungLabels(sec, sx);\n const labelOpacity = sectionLabelT * (1 - zoneT) * dim;\n sec.nameLabel.opacity(sec.nameLabelFits ? labelOpacity : 0);\n // Availability stays in the focused/detail UI. It is deliberately not a\n // second map label at the clean section-overview rung.\n sec.subLabel.opacity(0);\n }\n\n // Fade the big zone labels out as the view tilts into 3D — the raised tiers\n // read clearly on their own, and the overlaid zone text just clutters them.\n const zoneOpacity = zoneT * (1 - this.isoT);\n for (const zone of this.zones) {\n zone.back.opacity(zoneOpacity);\n zone.label.opacity(zoneOpacity);\n if (zone.sub) zone.sub.opacity(zoneOpacity);\n if (rescale) this.sizeZonePill(zone, sx);\n }\n // Greedy de-collision of the visible label tiers (small canvases stack\n // \"UPPER BOWL\"/\"LOWER BOWL\"/FROM-$ on top of each other otherwise).\n this.decollideRungLabels(sx);\n this.dedupeLogicalSectionLabels();\n for (const zone of this.zones) {\n const opacity = zone.label.opacity();\n zone.back.opacity(opacity);\n if (zone.sub) zone.sub.opacity(opacity);\n }\n this.bgLayer.batchDraw();\n }\n\n /** One semantic section gets one overview label, even across split contours. */\n private dedupeLogicalSectionLabels(): void {\n const byLogical = new Map<string, SectionRender[]>();\n for (const section of this.sections) {\n (byLogical.get(section.logicalId) ?? byLogical.set(section.logicalId, []).get(section.logicalId)!).push(section);\n }\n for (const components of byLogical.values()) {\n if (components.length < 2) continue;\n const visible = components\n .filter((component) => component.nameLabel.opacity() > 0.05)\n .sort((left, right) => {\n const leftBounds = polyBounds(left.outline);\n const rightBounds = polyBounds(right.outline);\n return rightBounds.width * rightBounds.height - leftBounds.width * leftBounds.height;\n });\n for (const component of visible.slice(1)) component.nameLabel.opacity(0);\n }\n }\n\n /**\n * Keep transitional zone pills from covering section names. Section names\n * are already proven inside disjoint shells, so they must not cull each other.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; box: { x: number; y: number; w: number; h: number } }\n const cands: Cand[] = [];\n const boxOf = (t: Text): { x: number; y: number; w: number; h: number } => {\n const p = this.worldToScreen({ x: t.x(), y: t.y() });\n const rotated = pointsBounds(rotatedRectPoints(\n { x: 0, y: 0 },\n t.width() * sx,\n t.height() * sx,\n t.rotation(),\n ));\n const w = rotated.width;\n const h = rotated.height;\n return { x: p.x - w / 2, y: p.y - h / 2, w, h };\n };\n for (const zone of this.zones) {\n if (zone.label.opacity() > 0.05) {\n const p = this.worldToScreen(zone.anchor);\n const w = zone.back.width() * sx;\n const h = zone.back.height() * sx;\n cands.push({ node: zone.label, tier: 0, section: false, box: { x: p.x - w / 2, y: p.y - h / 2, w, h } });\n }\n }\n for (const sec of this.sections) {\n if (sec.nameLabel.opacity() > 0.05) cands.push({ node: sec.nameLabel, tier: 1, section: true, box: boxOf(sec.nameLabel) });\n }\n if (cands.length < 2) return;\n cands.sort((a, b) => a.tier - b.tier || a.box.y - b.box.y || a.box.x - b.box.x);\n const kept: Cand['box'][] = [];\n const collides = (b: Cand['box']): boolean =>\n kept.some((k) =>\n b.x < k.x + k.w + GAP && k.x < b.x + b.w + GAP &&\n b.y < k.y + k.h + GAP && k.y < b.y + b.h + GAP,\n );\n for (const c of cands) {\n if (collides(c.box)) {\n c.node.opacity(0);\n } else if (!c.section) {\n // Section shells do not collide by construction; only zone pills form\n // blockers for later transitional labels.\n kept.push(c.box);\n }\n }\n }\n\n /** Set a centred label's world fontSize (for a target screen px) and re-anchor it. */\n private sizeLabel(t: Text, fontSize: number, y: number): void {\n t.fontSize(Math.max(1, fontSize));\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.y(y);\n }\n\n /** Fit one centred section name, rotating narrow shells like the target chart. */\n private fitSectionRungLabels(sec: SectionRender, sx: number): void {\n const paddingPx = 8;\n sec.subLabelFits = false;\n // Scale the fitted screen-px band by the section's authored label size so a\n // larger override reads larger; the step still shrinks to fit the polygon.\n const maxPx = SECTION_LABEL_PX * sec.labelScale;\n const minPx = MIN_SECTION_LABEL_PX * sec.labelScale;\n for (let fontPx = maxPx; fontPx >= minPx; fontPx -= 1) {\n for (const rotation of [0, -90]) {\n sec.nameLabel.rotation(rotation);\n this.sizeLabel(sec.nameLabel, fontPx / sx, sec.nameLabel.y());\n for (const anchor of sec.labelAnchors) {\n sec.nameLabel.position(anchor);\n const paddingWorld = paddingPx / sx;\n if (rotatedRectFitsPolygon(\n anchor,\n sec.nameLabel.width() + paddingWorld,\n sec.nameLabel.height() + paddingWorld,\n rotation,\n sec.outline,\n sec.holes,\n )) {\n sec.nameLabelFits = true;\n return;\n }\n }\n }\n }\n sec.nameLabel.position(sec.centroid);\n sec.nameLabel.rotation(0);\n sec.nameLabelFits = false;\n }\n\n /** Size one screen-constant zone name/price pill around its shared anchor. */\n private sizeZonePill(zone: ZoneRender, sx: number): void {\n const padX = 10 / sx;\n const padY = 6 / sx;\n const gap = zone.sub ? 3 / sx : 0;\n this.sizeLabel(zone.label, ZONE_LABEL_PX / sx, zone.anchor.y);\n if (zone.sub) this.sizeLabel(zone.sub, ZONE_SUB_PX / sx, zone.anchor.y);\n const width = Math.max(zone.label.width(), zone.sub?.width() ?? 0) + padX * 2;\n const height = zone.label.height() + (zone.sub ? gap + zone.sub.height() : 0) + padY * 2;\n zone.label.y(zone.anchor.y - (zone.sub ? (gap + zone.sub.height()) / 2 : 0));\n if (zone.sub) zone.sub.y(zone.anchor.y + (zone.label.height() + gap) / 2);\n zone.back.position(zone.anchor);\n zone.back.size({ width, height });\n zone.back.offset({ x: width / 2, y: height / 2 });\n zone.back.cornerRadius(7 / sx);\n zone.back.strokeWidth(1 / sx);\n }\n\n /**\n * Map a container-relative screen point back to world coords. Inverts the\n * stage (scale/pos) and, in iso view, the iso affine — so screen-space taps\n * test against the flat world outlines/geometry. Identity-equivalent at isoT=0.\n */\n private screenToWorld(clientPoint: { x: number; y: number }): { x: number; y: number } {\n const s = this.stage.scaleX();\n const iso = { x: (clientPoint.x - this.stage.x()) / s, y: (clientPoint.y - this.stage.y()) / s };\n return this.isoT === 0 ? iso : this.isoInverse(iso);\n }\n\n /** Section id under a container-relative screen point, or null (Slice 5 tap-to-zoom). */\n sectionAt(clientPoint: { x: number; y: number }): string | null {\n if (!this.sections.length) return null;\n const world = this.screenToWorld(clientPoint);\n const hit = this.sections.find((sec) => pointInPolygonWithHoles(world, sec.outline, sec.holes));\n return hit ? hit.logicalId : null;\n }\n\n /** Seat ids belonging to a section (Slice 5 section-summary card). */\n sectionMembers(id: string): string[] {\n return [...new Set(this.sections\n .filter((section) => section.id === id || section.logicalId === id || section.zone === id)\n .flatMap((section) => section.memberIds))];\n }\n\n private addCentredLabel(\n layer: Layer,\n text: string,\n x: number,\n y: number,\n fill: string,\n fontSize: number,\n bold: boolean,\n ): Text {\n const t = new Text({\n x,\n y,\n text,\n fontSize,\n fontStyle: bold ? '700' : '500',\n fontFamily: this.labelFont(),\n fill,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n layer.add(t);\n return t;\n }\n\n // ---- selection ------------------------------------------------------------\n\n private isSelectable(id: string): boolean {\n // A closed section's seats are never pickable, whatever their raw status.\n if (this.seatInClosedSection(id)) return false;\n const statuses = this.opts.selectableStatuses ?? ['free'];\n return statuses.includes(this.statusById.get(id) ?? 'free');\n }\n\n private toggleSeat(id: string): void {\n if (this.selection.has(id)) {\n this.setSelected(id, false);\n const seat = this.seatById.get(id);\n if (seat) this.opts.onDeselect?.(seat);\n } else {\n if (!this.isSelectable(id)) return;\n if (this.selection.size >= this.opts.maxSelection) {\n this.opts.onSelectionLimit?.(this.opts.maxSelection);\n return;\n }\n this.setSelected(id, true);\n const seat = this.seatById.get(id);\n if (seat) this.opts.onSelect?.(seat);\n }\n this.overlayLayer.batchDraw();\n }\n\n /**\n * Selection/hover ring color. An explicit theme.selectionColor always wins;\n * otherwise auto-contrast against the effective canvas background — the\n * designer renders on dark (white ring reads), but light-themed hosts (e.g.\n * the DesiPass buyer picker on cream) made the white ring invisible and\n * selected seats looked *disabled*. theme.background is checked first, then\n * the container's computed CSS background (walking up past transparent\n * ancestors). Unknown/unparseable backgrounds keep the dark default.\n */\n private resolveCanvasBackground(): string {\n const themed = this.theme.background ? opaqueColorHex(this.theme.background) : null;\n if (themed) return themed;\n if (typeof getComputedStyle === 'function') {\n let element: HTMLElement | null = this.container;\n while (element) {\n const resolved = opaqueColorHex(getComputedStyle(element).backgroundColor);\n if (resolved) return resolved;\n element = element.parentElement;\n }\n }\n return DEF_CANVAS_BACKGROUND;\n }\n\n private resolveSelectionColor(): string {\n if (this.theme.selectionColor) return this.theme.selectionColor;\n return isLightColor(this.canvasBackground) ? DEF_SELECTION_ON_LIGHT : DEF_SELECTION;\n }\n\n private setSelected(id: string, on: boolean, silent = false): void {\n const c = this.circleById.get(id);\n if (on) {\n this.selection.add(id);\n } else {\n if (this.selectionFocusId === id) this.setSelectionFocus(null);\n this.selection.delete(id);\n }\n this.syncSelectionMarker(id);\n if (c) {\n this.paintSeat(c, id);\n if (!silent && !this.cached) this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild one marker after selected/held/candidate state changes. */\n private syncSelectionMarker(id: string): void {\n this.selectionMarkers.get(id)?.destroy();\n this.selectionMarkers.delete(id);\n if (!this.selection.has(id) && !this.ownedHold.has(id)) return;\n\n const seat = this.seatById.get(id);\n if (!seat) return;\n const candidate = this.selectionFocusId === id;\n const dims = this.boothDims.get(seat.rowId);\n const marker = new Group({\n name: 'selection-ring',\n x: seat.x,\n y: seat.y,\n rotation: dims?.rotation ?? 0,\n listening: false,\n perfectDrawEnabled: false,\n opacity: this.selectionFocusId && !candidate ? 0.2 : 1,\n });\n marker.setAttr('seatId', id);\n const common = {\n stroke: this.effSelection,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n };\n\n if (dims) {\n marker.add(new Rect({\n ...common,\n width: dims.width,\n height: dims.height,\n offsetX: dims.width / 2,\n offsetY: dims.height / 2,\n cornerRadius: 4,\n strokeWidth: candidate ? 4 : 3,\n }));\n if (candidate) {\n marker.add(new Rect({\n ...common,\n width: dims.width + 10,\n height: dims.height + 10,\n offsetX: (dims.width + 10) / 2,\n offsetY: (dims.height + 10) / 2,\n cornerRadius: 7,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n const badgeX = Math.max(0, dims.width / 2 - 14);\n const badgeY = -Math.max(0, dims.height / 2 - 14);\n marker.add(new Circle({ x: badgeX, y: badgeY, radius: 10, fill: this.effSelection, listening: false }));\n marker.add(new Line({\n x: badgeX,\n y: badgeY,\n points: [-4.5, 0, -1, 3.5, 5.5, -4.5],\n stroke: isLightColor(this.effSelection) ? '#0b1220' : '#ffffff',\n strokeWidth: 2.4,\n lineCap: 'round',\n lineJoin: 'round',\n listening: false,\n }));\n }\n } else {\n marker.add(new Circle({ ...common, radius: this.seatR + (candidate ? 4.5 : 2.5), strokeWidth: candidate ? 3.5 : 2.5 }));\n if (candidate) {\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 8,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n marker.add(new Line({\n points: [-this.seatR * 0.52, 0, -this.seatR * 0.12, this.seatR * 0.4, this.seatR * 0.6, -this.seatR * 0.46],\n stroke: '#ffffff',\n strokeWidth: Math.max(2.6, this.seatR * 0.34),\n lineCap: 'round',\n lineJoin: 'round',\n shadowColor: '#0b1220',\n shadowBlur: 1.5,\n shadowOpacity: 0.55,\n listening: false,\n }));\n }\n }\n\n this.selectionMarkers.set(id, marker);\n this.overlayLayer.add(marker);\n }\n\n // ---- interaction ----------------------------------------------------------\n\n /**\n * The stage scale `focusRegion(id)` would settle at — i.e. the zoom that\n * frames this section in the current viewport. Used to decide whether\n * redirecting a seat tap to section-focus would actually zoom in FURTHER, or\n * whether the section already fills the viewport (small container) so the tap\n * must fall through and pick.\n */\n private sectionBounds(id: string): { x: number; y: number; width: number; height: number } | null {\n const bounds = this.sections\n .filter((section) => section.id === id || section.logicalId === id)\n .map((section) => polyBounds(section.outline));\n if (!bounds.length) return null;\n const left = Math.min(...bounds.map((box) => box.x));\n const top = Math.min(...bounds.map((box) => box.y));\n const right = Math.max(...bounds.map((box) => box.x + box.width));\n const bottom = Math.max(...bounds.map((box) => box.y + box.height));\n return { x: left, y: top, width: right - left, height: bottom - top };\n }\n\n private sectionFrameScale(id: string): number {\n const b = this.sectionBounds(id);\n if (!b) return this.stage.scaleX();\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n if (b.width <= 0 || b.height <= 0) return this.stage.scaleX();\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n return clamp(Math.max(frameScale, SEAT_FOCUS_SCALE), min, max);\n }\n\n /**\n * Resolve a seat tap: honour the 3D deck-drill and the AXS seat-pick gate,\n * then toggle. The gate (§4) redirects small on-screen seats to section-focus\n * to avoid blind mis-picks at overview scales — but ONLY when focusing would\n * zoom the seat up to a safe size. If we're already focused on the section, or\n * the section already fills the viewport (a narrow — OR even a wide — container\n * frames a big section BELOW LABEL_SCALE), redirecting is a no-op that would\n * leave the seat permanently unpickable (§5 `picking-gate-unreachable`), so we\n * fall through and PICK. This is the invariant: seats are never unpickable.\n */\n private handleSeatTap(id: string): void {\n // In the 3D all-floors overview, tapping a seat enters its deck in 2D\n // rather than selecting (seat picking happens on the flat floor map).\n if (this.stacked && this.opts.onDeckTap) {\n const floorId = this.objectFloor.get(this.seatById.get(id)?.rowId ?? '');\n if (floorId) { this.opts.onDeckTap(floorId); return; }\n }\n if (this.effScale() < LABEL_SCALE && this.sections.length) {\n const sec = this.seatSection.get(id);\n if (sec) {\n const alreadyFocused = this.focusedSectionId === sec.logicalId;\n // Would section-focus zoom us in meaningfully (>2%)? If not, the gate has\n // nowhere left to go — pick instead of deadlocking.\n const canZoomInFurther = this.sectionFrameScale(sec.logicalId) > this.stage.scaleX() * 1.02;\n if (!alreadyFocused && canZoomInFurther) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(sec.logicalId);\n else this.focusSection(sec.logicalId);\n return;\n }\n }\n }\n this.toggleSeat(id);\n }\n\n /**\n * Nearest SELECTABLE seat whose centre is within `slopPx` (screen space) of a\n * seat circle edge, or null. Enlarges the effective tap target for small seats\n * so a near-miss on mobile still lands on the intended seat, without ever\n * hijacking a clean tap on empty space beyond the slop.\n */\n private nearestSeatToScreen(screen: { x: number; y: number }, slopPx: number): string | null {\n const s = this.stage.scaleX() || 1;\n const reachWorld = this.seatR + slopPx / s; // circle radius + finger slack\n const world = this.screenToWorld(screen);\n let best: string | null = null;\n let bestD = reachWorld;\n for (const seat of this.seats) {\n if (!this.selection.has(seat.id) && !this.isSelectable(seat.id)) continue;\n const d = Math.hypot(seat.x - world.x, seat.y - world.y);\n if (d < bestD) {\n bestD = d;\n best = seat.id;\n }\n }\n return best;\n }\n\n private wireInteraction(): void {\n this.seatLayer.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.moved > PAN_START_SLOP_PX) return; // it was a pan/pinch, not a tap\n const id = seatIdOf(e.target);\n if (!id) return;\n this.handleSeatTap(id);\n });\n\n // Hover (mouse only) via delegated enter/leave on seat circles.\n this.seatLayer.on('mouseover', (e: KonvaEventObject<MouseEvent>) => {\n const id = seatIdOf(e.target);\n if (!id) return;\n const seat = this.seatById.get(id);\n if (!seat) return;\n this.hoverRing.position({ x: seat.x, y: seat.y });\n this.hoverRing.visible(true);\n this.overlayLayer.batchDraw();\n this.container.style.cursor = 'pointer';\n this.opts.onHover?.(seat);\n });\n this.seatLayer.on('mouseout', () => {\n this.hoverRing.visible(false);\n this.overlayLayer.batchDraw();\n this.container.style.cursor = 'default';\n this.opts.onHover?.(null);\n });\n\n this.stage.on('wheel', (e: KonvaEventObject<WheelEvent>) => {\n e.evt.preventDefault();\n // Position from the event itself — Konva's tracked pointer position is\n // unreliable when the last pointer event went elsewhere.\n const r = this.container.getBoundingClientRect();\n const pointer = { x: e.evt.clientX - r.left, y: e.evt.clientY - r.top };\n // Scale with the actual wheel delta so trackpad flings and fast wheels\n // zoom proportionally (a fixed step per event ignores delta magnitude).\n const factor = Math.exp(-e.evt.deltaY * 0.002);\n this.zoomAbout(this.stage.scaleX() * clamp(factor, 0.5, 2), pointer);\n });\n\n // Zoomed out, the seat layer is a non-listening cached bitmap and seats\n // are finger-width anyway — a tap zooms into that area instead of\n // attempting a 4px-precision selection (same behaviour as seats.io).\n this.stage.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.moved > PAN_START_SLOP_PX) return;\n const pointer = this.stage.getPointerPosition();\n if (!pointer) return;\n // Seats are LIVE (not a cached bitmap): the seatLayer handler above owns\n // direct seat hits. Here we only rescue near-misses — a finger landing just\n // off a small seat picks the nearest one (mobile hit target, §4 hit ≥ 24px).\n // A clean tap on empty space beyond the slop still does nothing.\n if (!this.cached) {\n if (seatIdOf(e.target)) return; // direct hit already handled\n const near = this.nearestSeatToScreen(pointer, SEAT_TAP_SLOP_PX);\n if (near) this.handleSeatTap(near);\n return;\n }\n // 3D all-floors overview: tapping a deck enters that floor in 2D. The iso\n // projection is a layer transform, so the flat screenToWorld hit-test below\n // won't work here — resolve the deck via the iso-aware nearest seat instead.\n if (this.stacked && this.opts.onDeckTap) {\n const floorId = this.deckFloorAt();\n if (floorId) { this.opts.onDeckTap(floorId); return; }\n }\n // A tap inside a section (seats aren't the active rung here — the layer is\n // cached) hands off to the host: fire onSectionTap so the picker can glide\n // in + show the section-summary card (Slice 5). With no handler wired we\n // keep the standalone behaviour of gliding to fit that section.\n if (this.sections.length) {\n const world = this.screenToWorld(pointer);\n const hit = this.sections.find((sn) => pointInPolygonWithHoles(world, sn.outline, sn.holes));\n if (hit) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(hit.logicalId);\n else this.focusRegion(hit.logicalId);\n return;\n }\n }\n const target = Math.max(SEAT_LEGIBLE_SCALE * 1.2, this.stage.scaleX() * 2.5);\n this.zoomAbout(target, pointer);\n });\n }\n\n /**\n * Which deck (floor) a screen tap landed on in the 3D stacked overview. The\n * seat layer is melt-cached at that zoom so individual seat nodes aren't\n * hit-testable; instead we invert the iso+stage transform via the layer's\n * relative pointer and take the nearest seat's floor. Only the floor matters,\n * so within-floor elevation offsets don't affect the result. Null if none.\n */\n private deckFloorAt(): string | null {\n if (!this.objectFloor.size) return null;\n const p = this.seatLayer.getRelativePointerPosition();\n if (!p) return null;\n let best: string | null = null;\n let bestD = Infinity;\n for (const s of this.seats) {\n const dx = s.x - p.x;\n const dy = s.y - p.y;\n const d = dx * dx + dy * dy;\n if (d < bestD) { bestD = d; best = s.rowId; }\n }\n return best ? this.objectFloor.get(best) ?? null : null;\n }\n\n // ---- Pan & pinch (raw pointer events — mouse, touch and pen alike) --------\n\n private toLocal(e: PointerEvent): { x: number; y: number } {\n const r = this.container.getBoundingClientRect();\n return { x: e.clientX - r.left, y: e.clientY - r.top };\n }\n\n // NOTE: no setPointerCapture here — capturing on the container retargets\n // pointer events away from Konva's canvas, killing its click/tap/hover\n // pipeline. We rely on bubbling instead.\n private onPointerDown = (e: PointerEvent): void => {\n this.cancelGlide(); // grabbing the map cancels an in-flight glide\n const local = this.toLocal(e);\n this.pointers.set(e.pointerId, local);\n if (this.pointers.size === 1) {\n this.moved = 0;\n this.pinch = null;\n this.panStart = local;\n this.panStarted = false;\n // Manage-mode rubber-band marquee (option-gated — buyer pan is byte-\n // identical when manageMode is off). A mouse/pen primary-button drag at\n // the seats rung selects instead of panning; touch keeps single-finger\n // pan (pinch zooms) and a middle-button drag (button !== 0) still pans.\n // Disabled below the seats rung so the organizer zooms in first.\n if (\n this.opts.manageMode && this.opts.marqueeSelect &&\n e.pointerType !== 'touch' && e.button === 0 &&\n this.getRung() === 'seats'\n ) {\n this.beginMarquee(local);\n this.panLast = null;\n } else {\n this.panLast = local;\n }\n } else if (this.pointers.size === 2) {\n // A second finger converts an in-progress marquee into a pinch-zoom.\n if (this.marquee) this.cancelMarquee();\n // Anchor the whole pinch to its starting geometry: scale follows the\n // finger-distance ratio and the world point under the midpoint stays\n // glued to the midpoint. No per-event compounding → no drift.\n const [a, b] = [...this.pointers.values()];\n const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n const s = this.stage.scaleX();\n this.pinch = {\n startDist: Math.hypot(b.x - a.x, b.y - a.y),\n startScale: s,\n worldMid: { x: (mid.x - this.stage.x()) / s, y: (mid.y - this.stage.y()) / s },\n };\n this.panLast = null;\n this.panStart = null;\n this.panStarted = true;\n this.moved = PAN_START_SLOP_PX + 1;\n }\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.pointers.has(e.pointerId)) return;\n e.preventDefault();\n const p = this.toLocal(e);\n this.pointers.set(e.pointerId, p);\n if (this.pointers.size === 1 && this.panStart) {\n this.moved = Math.max(this.moved, Math.hypot(p.x - this.panStart.x, p.y - this.panStart.y));\n } else if (this.pointers.size >= 2) {\n this.moved = PAN_START_SLOP_PX + 1;\n }\n\n if (this.marquee) {\n this.updateMarquee(p);\n return;\n }\n if (this.pinch && this.pointers.size >= 2) {\n const [a, b] = [...this.pointers.values()];\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n if (this.pinch.startDist < 1) return;\n const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n const { min, max } = this.zoomBounds();\n const scale = clamp(this.pinch.startScale * (dist / this.pinch.startDist), min, max);\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: mid.x - this.pinch.worldMid.x * scale,\n y: mid.y - this.pinch.worldMid.y * scale,\n });\n this.stage.batchDraw();\n this.scheduleViewChange();\n } else if (this.panLast && this.pointers.size === 1) {\n // Keep the camera still through normal finger jitter. Aside from making\n // taps feel steadier, this lets Konva deliver the section tap instead of\n // losing it to a one- or two-pixel accidental drag.\n if (!this.panStarted) {\n if (this.moved <= PAN_START_SLOP_PX) return;\n this.panStarted = true;\n }\n this.stage.position({\n x: this.stage.x() + (p.x - this.panLast.x),\n y: this.stage.y() + (p.y - this.panLast.y),\n });\n this.panLast = p;\n this.stage.batchDraw();\n this.scheduleViewChange();\n }\n };\n\n private onPointerEnd = (e: PointerEvent): void => {\n // Finishing a manage-mode marquee: compute the selection on pointer-UP.\n if (this.marquee) {\n this.finishMarquee();\n this.pointers.delete(e.pointerId);\n if (this.pointers.size === 0) this.panLast = null;\n return;\n }\n this.pointers.delete(e.pointerId);\n if (this.pointers.size < 2) this.pinch = null;\n if (this.pointers.size === 1) {\n // pinch → single finger: continue as a pan without jumping\n this.panLast = [...this.pointers.values()][0];\n this.panStart = this.panLast;\n this.panStarted = true;\n }\n if (this.pointers.size === 0) {\n this.panLast = null;\n this.panStart = null;\n this.panStarted = false;\n this.afterViewChange();\n }\n };\n\n /**\n * Min is chart-relative (never lose the room); max is absolute so seats\n * reach a readable size on any chart, however large the venue.\n */\n private zoomBounds(): { min: number; max: number } {\n let min = 0.5 * this.fitScale;\n // When the chart has zones, the zone rung lives at an ABSOLUTE scale\n // (ZONE_PROMINENT_SCALE). On a large venue `0.5·fitScale` can sit above it,\n // making the zone overview unreachable by zooming out — allow a touch more\n // room so the rung is actually reachable (zone-charts only).\n if (this.zones.length) min = Math.min(min, ZONE_PROMINENT_SCALE * 0.9);\n return { min, max: Math.max(10 * this.fitScale, 4) };\n }\n\n /** Zoom so `clientPoint` (stage-relative px) stays fixed under the cursor. */\n private zoomAbout(nextScale: number, clientPoint: { x: number; y: number }): void {\n const { min, max } = this.zoomBounds();\n const scale = clamp(nextScale, min, max);\n const old = this.stage.scaleX();\n if (scale === old) return;\n const worldX = (clientPoint.x - this.stage.x()) / old;\n const worldY = (clientPoint.y - this.stage.y()) / old;\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: clientPoint.x - worldX * scale,\n y: clientPoint.y - worldY * scale,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /** Zoom + pan so world-rect `b` fills the viewport (with a small margin). */\n private zoomToBounds(\n b: { x: number; y: number; width: number; height: number },\n minScale?: number,\n ): void {\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n const scale = clamp(Math.max(frameScale, minScale ?? min), min, max);\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: w / 2 - (b.x + b.width / 2) * scale,\n y: h / 2 - (b.y + b.height / 2) * scale,\n });\n this.afterViewChange();\n this.stage.batchDraw();\n }\n\n /**\n * Smoothly glide the camera to frame a section (by id) or a world-space bounds\n * rect — the Slice 5 \"glide in\". Pan+zoom tween over a calm easeInOutCubic; the\n * melt/LOD rides the camera every frame. `prefers-reduced-motion` (or\n * `opts.animate === false`) snaps via zoomToBounds. A grab (pointer-down) or a\n * newer glide cancels an in-flight one.\n */\n focusRegion(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void {\n const b =\n typeof target === 'string'\n ? this.sectionBounds(target)\n : target;\n if (!b) return;\n this.cancelGlide();\n if (opts?.animate === false || this.reducedMotion) {\n this.zoomToBounds(b, opts?.minScale);\n return;\n }\n const w = this.stage.width();\n const h = this.stage.height();\n const { min, max } = this.zoomBounds();\n const margin = 1.12;\n const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));\n const toScale = clamp(Math.max(frameScale, opts?.minScale ?? min), min, max);\n const toX = w / 2 - (b.x + b.width / 2) * toScale;\n const toY = h / 2 - (b.y + b.height / 2) * toScale;\n const fromScale = this.stage.scaleX();\n const fromX = this.stage.x();\n const fromY = this.stage.y();\n if (Math.abs(toScale - fromScale) < 1e-4 && Math.abs(toX - fromX) < 0.5 && Math.abs(toY - fromY) < 0.5) {\n this.afterViewChange();\n return;\n }\n const start = performance.now();\n const duration = Math.max(180, Math.min(1200, opts?.durationMs ?? CAMERA_GLIDE_MS));\n const step = (now: number): void => {\n if (this.destroyed) { this.glideRaf = 0; return; }\n const raw = Math.min(1, (now - start) / duration);\n const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;\n const sc = fromScale + (toScale - fromScale) * e;\n this.stage.scale({ x: sc, y: sc });\n this.stage.position({ x: fromX + (toX - fromX) * e, y: fromY + (toY - fromY) * e });\n this.updateLOD(); // the melt cross-fades as the camera rides in\n this.scheduleViewChange();\n this.stage.batchDraw();\n if (raw < 1) {\n this.glideRaf = requestAnimationFrame(step);\n } else {\n this.glideRaf = 0;\n this.afterViewChange();\n }\n };\n this.glideRaf = requestAnimationFrame(step);\n }\n\n /** Cancel an in-flight camera glide (a grab or a newer glide interrupts it). */\n private cancelGlide(): void {\n if (this.glideRaf) {\n cancelAnimationFrame(this.glideRaf);\n this.glideRaf = 0;\n }\n }\n\n /** Current LOD rung derived from effective zoom — drives the ZONES/SECTIONS/SEATS pill. */\n getRung(): LodRung {\n const scale = this.effScale();\n if (scale >= CACHE_THRESHOLD) return 'seats';\n if (this.zones.length && scale < ZONE_PROMINENT_SCALE) return 'zones';\n return 'sections';\n }\n\n getRenderedQualityEvidence(): RendererQualityEvidence {\n const effectiveScale = this.effScale();\n const stageScale = this.stage.scaleX();\n const viewport = { width: this.stage.width(), height: this.stage.height() };\n const rounded = (value: number) => Math.round(value * 100) / 100;\n const labels: RenderedBookableLabelEvidence[] = this.seats.map((seat) => {\n const shape = this.circleById.get(seat.id);\n const label = this.boothLabelById.get(seat.id) ?? this.seatLabelById.get(seat.id);\n const authoredFontSize = seat.kind === 'booth'\n ? BOOTH_LABEL_FONT_SIZE\n : SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const renderedFontPx = rounded((label?.fontSize() ?? authoredFontSize) * effectiveScale);\n const screen = this.worldToScreen(seat);\n const outside = screen.x < 0 || screen.x > viewport.width || screen.y < 0 || screen.y > viewport.height;\n const opacity = shape?.opacity() ?? 0;\n const section = this.seatSection.get(seat.id);\n const visible = Boolean(label?.isVisible()) && opacity >= 0.5 && !outside;\n let hiddenReason: RenderedBookableLabelEvidence['hiddenReason'];\n if (!visible) {\n if (opacity < 0.5) hiddenReason = 'dimmed-or-unavailable';\n else if (renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX) hiddenReason = 'below-minimum-size';\n else if (outside) hiddenReason = 'outside-viewport';\n else if (!label) hiddenReason = 'clutter-or-fit';\n else hiddenReason = 'renderer-hidden';\n }\n const labelWidth = label ? label.width() * stageScale : 0;\n const labelHeight = label ? label.height() * effectiveScale : 0;\n const directWidthPx = shape instanceof Rect\n ? shape.width() * stageScale\n : this.seatR * 2 * effectiveScale;\n const directHeightPx = shape instanceof Rect\n ? shape.height() * stageScale\n : this.seatR * 2 * effectiveScale;\n // The stage-level near-miss resolver extends every live seat target by\n // SEAT_TAP_SLOP_PX around the same seat radius used by interaction.\n const assistedDiameterPx = 2 * (this.seatR * effectiveScale + SEAT_TAP_SLOP_PX);\n const fill = shape?.fill();\n const ink = label?.fill();\n return {\n seatId: seat.id,\n label: seat.label,\n kind: seat.kind === 'booth' ? 'booth' : 'seat',\n categoryKey: seat.categoryKey,\n ...(section ? { sectionId: section.id } : {}),\n ...(section?.zone ? { zoneId: section.zone } : {}),\n status: this.statusById.get(seat.id) ?? 'free',\n selected: this.selection.has(seat.id),\n visible,\n renderedFontPx,\n fill: typeof fill === 'string' ? fill : '',\n ink: typeof ink === 'string' ? ink : (this.theme.seatLabelColor ?? DEF_SEAT_LABEL),\n opacity: rounded(opacity),\n pointerTarget: {\n active: !this.cached && this.isSelectable(seat.id),\n directWidthPx: rounded(directWidthPx),\n directHeightPx: rounded(directHeightPx),\n effectiveMinimumPx: rounded(Math.max(\n Math.min(directWidthPx, directHeightPx),\n assistedDiameterPx,\n )),\n },\n screenCenter: { x: rounded(screen.x), y: rounded(screen.y) },\n ...(visible ? {\n screenBox: {\n x: rounded(screen.x - labelWidth / 2),\n y: rounded(screen.y - labelHeight / 2),\n width: rounded(labelWidth),\n height: rounded(labelHeight),\n },\n } : {}),\n ...(hiddenReason ? { hiddenReason } : {}),\n };\n });\n const visibleLabels = labels.filter((label) => label.visible).length;\n const hierarchyEvidence = (\n id: string,\n kind: 'section' | 'zone',\n role: 'name' | 'availability' | 'price',\n node: Text,\n backgroundFill: string,\n section?: SectionRender,\n ) => {\n const worldCorners = rotatedRectPoints(\n { x: node.x(), y: node.y() },\n node.width(),\n node.height(),\n node.rotation(),\n );\n const screenBounds = pointsBounds(worldCorners.map((corner) => this.worldToScreen(corner)));\n const opacity = rounded(node.opacity());\n const ink = node.fill();\n const outside = screenBounds.x + screenBounds.width < 0 || screenBounds.x > viewport.width\n || screenBounds.y + screenBounds.height < 0 || screenBounds.y > viewport.height;\n const visible = node.isVisible() && opacity > 0.05 && !outside;\n const fitsContainer = section\n ? rotatedRectFitsPolygon(\n { x: node.x(), y: node.y() },\n node.width(),\n node.height(),\n node.rotation(),\n section.outline,\n section.holes,\n )\n : undefined;\n return {\n id,\n kind,\n role,\n label: node.text(),\n visible,\n renderedFontPx: rounded(node.fontSize() * stageScale),\n opacity,\n fill: backgroundFill,\n ink: typeof ink === 'string' ? ink : '',\n ...(fitsContainer == null ? {} : { fitsContainer }),\n ...(visible ? {\n screenBox: {\n x: rounded(screenBounds.x),\n y: rounded(screenBounds.y),\n width: rounded(screenBounds.width),\n height: rounded(screenBounds.height),\n },\n } : {}),\n };\n };\n const hierarchyLabels = [\n ...this.sections.map((section) => {\n const fill = section.blockPoly.fill();\n return hierarchyEvidence(\n section.id,\n 'section',\n 'name',\n section.nameLabel,\n typeof fill === 'string' ? fill : section.baseFill,\n section,\n );\n }),\n ...this.sections.map((section) => {\n const fill = section.blockPoly.fill();\n return hierarchyEvidence(\n `${section.id}:availability`,\n 'section',\n 'availability',\n section.subLabel,\n typeof fill === 'string' ? fill : section.baseFill,\n section,\n );\n }),\n ...this.zones.flatMap((zone) => [\n hierarchyEvidence(zone.id, 'zone', 'name', zone.label, zone.background),\n ...(zone.sub ? [hierarchyEvidence(`${zone.id}:price`, 'zone', 'price', zone.sub, zone.background)] : []),\n ]),\n ];\n const gaAreas: RenderedGAAreaEvidence[] = [...this.gaById].map(([areaId, ga]) => {\n const screenPoints = ga.points.map((point) => this.worldToScreen(point));\n const left = Math.min(...screenPoints.map((point) => point.x));\n const top = Math.min(...screenPoints.map((point) => point.y));\n const right = Math.max(...screenPoints.map((point) => point.x));\n const bottom = Math.max(...screenPoints.map((point) => point.y));\n const outside = right < 0 || left > viewport.width || bottom < 0 || top > viewport.height;\n const opacity = rounded(ga.polygon.opacity());\n const visible = opacity >= 0.1 && !outside;\n const fill = ga.polygon.fill();\n return {\n areaId,\n label: ga.label,\n capacity: ga.capacity,\n categoryKey: ga.categoryKey,\n ...(ga.sectionId ? { sectionId: ga.sectionId } : {}),\n visible,\n interactive: ga.polygon.listening(),\n opacity,\n fill: typeof fill === 'string' ? fill : '',\n effectiveBackground: ga.effectiveBackground,\n ...(visible ? {\n screenBox: {\n x: rounded(left),\n y: rounded(top),\n width: rounded(right - left),\n height: rounded(bottom - top),\n },\n } : {}),\n };\n });\n const freeTextLabels = [...this.freeTextById].map(([recordKey, record]) => {\n const { node, background, kind } = record;\n const point = this.worldToScreen({ x: node.x(), y: node.y() });\n const width = node.width() * stageScale;\n const height = node.height() * effectiveScale;\n const left = point.x - node.offsetX() * stageScale;\n const top = point.y - node.offsetY() * effectiveScale;\n const renderedFontPx = rounded(node.fontSize() * effectiveScale);\n const outside = left + width < 0 || left > viewport.width\n || top + height < 0 || top > viewport.height;\n const visible = node.isVisible() && !outside;\n const ink = node.fill();\n const opacity = rounded(node.getAbsoluteOpacity());\n let hiddenReason: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden' | undefined;\n if (!visible) {\n if (renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX) hiddenReason = 'below-minimum-size';\n else if (outside) hiddenReason = 'outside-viewport';\n else hiddenReason = 'renderer-hidden';\n }\n return {\n objectId: record.objectId ?? recordKey,\n kind,\n text: node.text(),\n visible,\n renderedFontPx,\n ink: typeof ink === 'string' ? ink : '',\n background,\n opacity,\n ...(visible ? {\n screenBox: {\n x: rounded(left),\n y: rounded(top),\n width: rounded(width),\n height: rounded(height),\n },\n } : {}),\n ...(hiddenReason ? { hiddenReason } : {}),\n };\n });\n const palette = overviewPalette(this.canvasBackground);\n const neutralSectionFills = new Set([\n palette.sectionFill.toLowerCase(),\n darken(palette.sectionFill, 0.12).toLowerCase(),\n ]);\n const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);\n return {\n viewport,\n canvasBackground: this.canvasBackground,\n effectiveScale: rounded(effectiveScale),\n rung: this.getRung(),\n minimumVisibleLabelPx: MIN_VISIBLE_BOOKABLE_LABEL_PX,\n totalLabelledBookableUnits: labels.length,\n visibleLabels,\n hiddenLabels: labels.length - visibleLabels,\n totalBookableUnits: labels.length + gaAreas.reduce((sum, area) => sum + area.capacity, 0),\n selectionRingSeatIds: this.overlayLayer.find('.selection-ring')\n .map((node) => String(node.getAttr('seatId') ?? ''))\n .filter(Boolean),\n selectionRingColor: this.effSelection,\n focusedSectionId: this.focusedSectionId,\n focusBackdropVisible: Boolean(this.focusBackdrop?.isVisible()),\n categoryFilterKeys: this.categoryFilter ? [...this.categoryFilter].sort() : null,\n overviewStyle: {\n visibleSectionShells: visibleSectionShells.length,\n categoryPaintedSectionShells: visibleSectionShells.filter((section) => {\n const fill = section.blockPoly.fill();\n return typeof fill !== 'string' || !neutralSectionFills.has(fill.toLowerCase());\n }).length,\n visibleCategoryDetailOutlines: this.sections.filter((section) => section.outlinePoly.opacity() > 0.05).length,\n // Row-hint nodes no longer exist in the production overview scene.\n visibleSectionRowHints: 0,\n visibleSectionAvailabilityLabels: this.sections.filter((section) => section.subLabel.opacity() > 0.05).length,\n visibleSectionGADetails: [...this.gaById.values()].filter((area) => (\n area.sectionId != null && area.polygon.opacity() > 0.05\n )).length,\n },\n labels,\n gaAreas,\n hierarchyLabels,\n freeTextLabels,\n };\n }\n\n /** Jump the camera to a rung's zoom band (glided). */\n setRung(rung: LodRung): void {\n if (rung === 'zones') {\n this.cancelGlide();\n this.zoomToFit();\n return;\n }\n const target =\n rung === 'sections'\n ? (SECTION_PROMINENT_SCALE + CACHE_THRESHOLD) / 2\n : Math.max(\n this.seatLabelTargetScale() * 1.05,\n SEAT_FOCUS_SCALE,\n CACHE_THRESHOLD * 1.3,\n );\n const w = this.stage.width();\n const h = this.stage.height();\n const visible = this.getVisibleWorldRect();\n const viewCentre = {\n x: visible.x + visible.width / 2,\n y: visible.y + visible.height / 2,\n };\n let cx = viewCentre.x;\n let cy = viewCentre.y;\n if (rung === 'sections' && this.sections.length > 0) {\n const sectionCentres = this.sections.map((section) => {\n const bounds = polyBounds(section.outline);\n return {\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n };\n });\n const halfWidth = w / (target * 2);\n const halfHeight = h / (target * 2);\n const hierarchyWillBeVisible = sectionCentres.some((point) =>\n Math.abs(point.x - viewCentre.x) <= halfWidth\n && Math.abs(point.y - viewCentre.y) <= halfHeight);\n if (!hierarchyWillBeVisible) {\n // A narrow viewport through the empty centre of an upper stadium deck\n // can miss every section. Fall back to the nearest hierarchy block.\n const nearest = sectionCentres.reduce((best, point) => {\n const distance = (point.x - viewCentre.x) ** 2 + (point.y - viewCentre.y) ** 2;\n return distance < best.distance ? { point, distance } : best;\n }, { point: sectionCentres[0], distance: Infinity });\n cx = nearest.point.x;\n cy = nearest.point.y;\n }\n }\n const seatAnchors = rung === 'seats' ? this.seats.filter((seat) => seat.kind !== 'booth') : [];\n if (seatAnchors.length > 0) {\n // Bowl/arena charts commonly have an empty focal area at their geometric\n // centre. Centring a deep seat zoom there exposes only the pitch or stage.\n // Anchor the rung on the nearest actual seat to the current view centre so\n // explicit LOD navigation stays local after a pan and always reveals\n // bookable inventory after zoom-to-fit.\n let nearest = seatAnchors[0];\n let nearestDistance = Infinity;\n for (const seat of seatAnchors) {\n const dx = seat.x - viewCentre.x;\n const dy = seat.y - viewCentre.y;\n const distance = dx * dx + dy * dy;\n if (distance < nearestDistance) {\n nearest = seat;\n nearestDistance = distance;\n }\n }\n cx = nearest.x;\n cy = nearest.y;\n }\n const bw = w / (target * 1.12);\n const bh = h / (target * 1.12);\n this.focusRegion({ x: cx - bw / 2, y: cy - bh / 2, width: bw, height: bh });\n }\n\n /**\n * The seat rung must account for labels that auto-fit inside a seat circle.\n * A short `A-1` remains at the normal 7u target; a table label such as\n * `T13-10` may fit at 4u and therefore needs a deeper camera target to reach\n * the same 12 CSS-pixel floor. Measurement happens only on explicit rung\n * navigation, never during pan/zoom frames.\n */\n private seatLabelTargetScale(): number {\n let minimumFont = BOOTH_LABEL_FONT_SIZE;\n const measure = new Text({\n fontSize: SEAT_LABEL_FONT_SIZE,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n listening: false,\n });\n const maxWidth = this.seatR * 2 - 3;\n for (const seat of this.seats) {\n if (seat.kind === 'booth') {\n minimumFont = Math.min(minimumFont, BOOTH_LABEL_FONT_SIZE);\n continue;\n }\n const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n measure.fontSize(authoredFontSize);\n measure.text(bookableMarkerLabel(seat.displayLabel ?? seat.label));\n const fitted = measure.width() > maxWidth\n ? Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, (authoredFontSize * maxWidth) / measure.width())\n : authoredFontSize;\n minimumFont = Math.min(minimumFont, fitted);\n }\n measure.destroy();\n return MIN_VISIBLE_BOOKABLE_LABEL_PX / Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, minimumFont);\n }\n\n /** Recompute LOD (cache/labels) after any pan/zoom settles. */\n private afterViewChange(): void {\n this.updateLOD();\n this.updateFreeTextVisibility();\n this.updateLabels();\n this.scheduleViewChange();\n }\n\n /** rAF-coalesced `onViewChange` — at most one host callback per animation frame. */\n private scheduleViewChange(): void {\n if (this.viewChangeRaf) return;\n this.viewChangeRaf = requestAnimationFrame(() => {\n this.viewChangeRaf = 0;\n this.opts.onViewChange?.();\n });\n }\n\n private updateLOD(): void {\n // Effective scale folds in the iso y-squash (smaller ⇒ seats read smaller),\n // so LOD/melt thresholds trip correctly in 3D view. Equals the raw stage\n // scale at isoT=0 → flat behaviour is unchanged.\n const scale = this.effScale();\n const focalScale = Math.max(scale, 0.0001);\n for (const [label, targetPx] of this.primaryFocalLabels) {\n this.sizeLabel(label, targetPx / focalScale, label.y());\n }\n if (this.hasSections) this.applySectionLod(scale);\n else if (this.primaryFocalLabels.size) this.bgLayer.batchDraw();\n this.paintGAStateForView();\n const shouldCache = scale < CACHE_THRESHOLD;\n if (shouldCache && !this.cached) {\n this.cacheSeatLayer();\n } else if (!shouldCache && this.cached) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the\n * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */\n private rebuildSeatCache(): void {\n // Cache at ~screen resolution: bitmap px ≈ on-screen px, so a huge chart in\n // chart-units doesn't blow up into a gigapixel canvas when zoomed out.\n const pr = clamp(this.stage.scaleX() * this.dpr, 0.15, 2);\n this.seatLayer.clearCache();\n this.seatLayer.cache({ pixelRatio: pr });\n this.seatLayer.listening(false);\n this.cached = true;\n }\n\n private cacheSeatLayer(): void {\n this.rebuildSeatCache();\n this.seatLayer.batchDraw();\n }\n\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the\n * ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore\n * Konva's batchDraw) on hidden/backgrounded/occluded tabs, so seat-status\n * deltas applied via setStatus() mutate the scene graph but never reach the\n * canvas until the tab is foregrounded. This flushes the cache-debounce and\n * paints every layer setStatus() can touch, immediately.\n *\n * Additive: the foreground path never calls this, so foreground behaviour is\n * byte-identical.\n */\n forceDraw(): void {\n // Flush any pending cache-debounce (setStatus coalesces bursts behind a\n // 150ms setTimeout) so a returning tab isn't left showing a stale bitmap.\n if (this.recacheTimer) {\n clearTimeout(this.recacheTimer);\n this.recacheTimer = null;\n // Fold coalesced deltas into a bitmap only if the CURRENT camera is still\n // on the cached overview rung. A status update can queue this timer and a\n // subsequent detail zoom can uncache the layer before forceDraw(); blindly\n // rebuilding here would disable pointer listening on live detail seats.\n if (this.effScale() < CACHE_THRESHOLD) {\n this.rebuildSeatCache();\n } else if (this.cached) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n }\n }\n // Synchronous paint of every layer setStatus() may repaint. Layer.draw()\n // renders on the calling thread, unlike batchDraw()'s rAF schedule.\n this.bgLayer.draw();\n this.seatLayer.draw();\n this.overlayLayer.draw();\n }\n\n private updateFreeTextVisibility(): void {\n const effectiveScale = this.effScale();\n for (const { objectId, node, categoryKey, kind } of this.freeTextById.values()) {\n const gaDimmed = categoryKey != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaCategoryDimmed(categoryKey);\n const gaOverviewHidden = objectId != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaById.get(objectId)?.sectionId != null\n && effectiveScale < CACHE_THRESHOLD;\n node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));\n }\n }\n\n private updateLabels(): void {\n const effectiveScale = this.effScale();\n const show = effectiveScale >= LABEL_SCALE;\n for (const [id, label] of this.boothLabelById) {\n const shape = this.circleById.get(id);\n label.visible(\n isBookableLabelLegibleAtScale(label.fontSize(), effectiveScale)\n && (shape?.opacity() ?? 1) >= 0.5,\n );\n }\n this.labelGroup.destroyChildren();\n this.seatLabelById.clear();\n if (!show) {\n this.overlayLayer.batchDraw();\n return;\n }\n // Visible chart rect (with a small margin) in chart coordinates.\n const s = this.stage.scaleX();\n const x0 = (-this.stage.x()) / s;\n const y0 = (-this.stage.y()) / s;\n const x1 = (this.stage.width() - this.stage.x()) / s;\n const y1 = (this.stage.height() - this.stage.y()) / s;\n\n let count = 0;\n for (const seat of this.seats) {\n // Booth labels already live beside their rectangular shape in seatLayer\n // (renderBoothUnit). Adding them again to the zoom-only overlay produces\n // the offset/doubled numbers visible at close zoom levels.\n if (seat.kind === 'booth') continue;\n if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;\n const shape = this.circleById.get(seat.id);\n if ((shape?.opacity() ?? 1) < 0.5) continue;\n const status = this.statusById.get(seat.id) ?? 'free';\n // Buyers see another buyer's hold as an unavailable lock, without its\n // inventory label. Organizers in manage mode retain the held unit's\n // identity so they can inspect or release it from the control room.\n const unavailable = status === 'booked'\n || (status === 'held' && !this.ownedHold.has(seat.id) && !this.opts.manageMode);\n if (unavailable) {\n // Status is geometry, not a letter: a centred lock for a temporary hold\n // and one quiet diagonal mark for sold. This stays aligned at every\n // zoom level and does not ask buyers to decode \"H\" or a large × glyph.\n const cue = new Group({ x: seat.x, y: seat.y, listening: false });\n if (status === 'held') {\n cue.add(new Rect({\n x: -4.2, y: -0.7, width: 8.4, height: 6.5, cornerRadius: 1.3,\n stroke: '#ffffff', strokeWidth: 1.25, listening: false,\n }));\n cue.add(new Line({\n points: [-2.4, -0.8, -2.4, -2.7, -1.2, -4, 0, -4.35, 1.2, -4, 2.4, -2.7, 2.4, -0.8],\n stroke: '#ffffff', strokeWidth: 1.2, lineCap: 'round', lineJoin: 'round', listening: false,\n }));\n } else {\n cue.add(new Line({\n points: [-4.2, 4.2, 4.2, -4.2], stroke: '#ffffff', strokeWidth: 1.8,\n lineCap: 'round', listening: false,\n }));\n }\n this.labelGroup.add(cue);\n if (++count >= MAX_LABELS) break;\n continue;\n }\n // Authored per-seat size scales the neutral default BEFORE auto-fit, so\n // the fit/shrink/legibility logic below still runs on top of it.\n const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const t = new Text({\n x: seat.x,\n y: seat.y,\n text: bookableMarkerLabel(seat.displayLabel ?? seat.label),\n fontSize: authoredFontSize,\n fontStyle: '600',\n fontFamily: this.labelFont(),\n fill: shape ? this.seatLabelInk(seat, shape) : this.seatPreferredLabelInk(seat),\n listening: false,\n perfectDrawEnabled: false,\n });\n // Auto-fit: shrink long labels (e.g. \"T10-10\") so they never spill out of\n // the seat circle. Down to a legibility floor; below that the label is\n // dropped rather than rendered as an unreadable speck.\n const maxW = this.seatR * 2 - 3;\n if (t.width() > maxW) t.fontSize(Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, (authoredFontSize * maxW) / t.width()));\n // The minimum fitted font can still be wider than the physical marker\n // for verbose row labels. Never let text spill across adjacent seats;\n // keep the seat interactive and let the picker/tooltip expose its label.\n if (t.width() > maxW + 0.01) { t.destroy(); continue; }\n if (!isBookableLabelLegibleAtScale(t.fontSize(), effectiveScale)) { t.destroy(); continue; }\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n this.labelGroup.add(t);\n this.seatLabelById.set(seat.id, t);\n if (++count >= MAX_LABELS) break;\n }\n // Keep freshly-built seat labels upright under the iso layer skew.\n if (this.isoT > 0) this.applyUprightLabels();\n this.overlayLayer.batchDraw();\n }\n\n private handleResize(): void {\n const w = this.container.clientWidth || 1;\n const h = this.container.clientHeight || 1;\n if (w === this.stage.width() && h === this.stage.height()) return;\n this.stage.size({ width: w, height: h });\n // Keep the chart framed; refit is the least surprising behaviour on resize.\n this.zoomToFit();\n }\n\n private startFpsLoop(): void {\n const tick = (now: number) => {\n if (!this.lastFpsAt) this.lastFpsAt = now;\n this.frames++;\n const elapsed = now - this.lastFpsAt;\n if (elapsed >= 1000) {\n this.opts.onFps?.(Math.round((this.frames * 1000) / elapsed));\n this.frames = 0;\n this.lastFpsAt = now;\n }\n this.rafId = requestAnimationFrame(tick);\n };\n this.rafId = requestAnimationFrame(tick);\n }\n}\n\nexport function createRenderer(container: HTMLDivElement, opts?: RendererOptions): ISeatmapRenderer {\n return new SeatmapRenderer(container, opts);\n}\n","/**\n * Rendering constants that quality inspection must agree with.\n *\n * Keep these in core rather than inside the Konva renderer so headless catalog,\n * API, and MCP checks can evaluate the text that the buyer/designer will see.\n */\n\n/** Seat and table-seat labels are authored at this many chart units. */\nexport const SEAT_LABEL_FONT_SIZE = 7;\n\n/** Booth labels are authored at this many chart units. */\nexport const BOOTH_LABEL_FONT_SIZE = 10;\n\n/** GA area captions and their capacity sublabels. */\nexport const GA_LABEL_FONT_SIZE = 15;\nexport const GA_CAPACITY_LABEL_FONT_SIZE = 11;\n\n/**\n * GA category paint remains slightly translucent, but must still separate from\n * both supported canvas surfaces by the shared 3:1 graphical-object floor.\n */\nexport const GA_FILL_OPACITY = 0.85;\n\n/**\n * Small labels below this rendered CSS-pixel size are hidden by LOD instead of\n * being painted as unreadable specks.\n */\nexport const MIN_VISIBLE_BOOKABLE_LABEL_PX = 12;\n\n/** WCAG contrast for normal/small text. */\nexport const SMALL_TEXT_CONTRAST = 4.5;\n\n/** WCAG contrast for genuinely large text. */\nexport const LARGE_TEXT_CONTRAST = 3;\n\n/** Dark/light label candidates used only when a transient rendered state\n * changes the authored category fill (selected, held, unavailable, and so on). */\nexport const DARK_BOOKABLE_LABEL_INK = '#000000';\nexport const LIGHT_BOOKABLE_LABEL_INK = '#ffffff';\n\n/** 18pt normal text and 14pt bold text expressed as CSS pixels. */\nconst LARGE_NORMAL_TEXT_PX = 24;\nconst LARGE_BOLD_TEXT_PX = 18.67;\n\nexport function minimumTextContrast(renderedFontPx: number, fontWeight = 400): number {\n const isLarge = renderedFontPx >= LARGE_NORMAL_TEXT_PX\n || (fontWeight >= 700 && renderedFontPx >= LARGE_BOLD_TEXT_PX);\n return isLarge ? LARGE_TEXT_CONTRAST : SMALL_TEXT_CONTRAST;\n}\n\nexport function isBookableLabelLegibleAtScale(fontSize: number, effectiveScale: number): boolean {\n return fontSize * effectiveScale >= MIN_VISIBLE_BOOKABLE_LABEL_PX;\n}\n\n/**\n * Keep the public seat label as the inventory identity while rendering only\n * its terminal seat number inside the physical marker. Generated row seats use\n * `<row label>-<number>`; a custom label without that suffix remains unchanged.\n */\nexport function bookableMarkerLabel(publicLabel: string): string {\n return /-(\\d{1,5})$/.exec(publicLabel)?.[1] ?? publicLabel;\n}\n\nfunction luminance(value: string): number | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const channel = (offset: number) => {\n const encoded = Number.parseInt(match[1].slice(offset, offset + 2), 16) / 255;\n return encoded <= 0.04045 ? encoded / 12.92 : ((encoded + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4);\n}\n\n/** WCAG contrast for the actual opaque hex paints used by bookable labels. */\nexport function renderedTextContrast(ink: string, fill: string): number | null {\n const inkLuminance = luminance(ink);\n const fillLuminance = luminance(fill);\n if (inkLuminance == null || fillLuminance == null) return null;\n return (Math.max(inkLuminance, fillLuminance) + 0.05)\n / (Math.min(inkLuminance, fillLuminance) + 0.05);\n}\n\nfunction rgb(value: string): [number, number, number] | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const packed = Number.parseInt(match[1], 16);\n return [(packed >> 16) & 255, (packed >> 8) & 255, packed & 255];\n}\n\n/**\n * Resolve the opaque pixel under text painted over a translucent category\n * shape. Quality evidence must compare against this composite—not the raw\n * category colour or the canvas alone.\n */\nexport function compositeHexOver(\n foreground: string,\n background: string,\n opacity: number,\n): string {\n const front = rgb(foreground);\n const back = rgb(background);\n if (!front || !back) return background;\n const alpha = Math.max(0, Math.min(1, opacity));\n const channels = front.map((value, index) => Math.round(value * alpha + back[index] * (1 - alpha)));\n return `#${channels.map((value) => value.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Bookable fills can vary per category and per transient state, while a chart\n * exposes only one preferred label token. Preserve that preference whenever it\n * passes, then deterministically choose the strongest normal-text candidate.\n */\nexport function stateAwareBookableLabelInk(fill: string, preferred: string): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= SMALL_TEXT_CONTRAST) return preferred;\n const darkContrast = renderedTextContrast(DARK_BOOKABLE_LABEL_INK, fill) ?? 0;\n const lightContrast = renderedTextContrast(LIGHT_BOOKABLE_LABEL_INK, fill) ?? 0;\n if (darkContrast === 0 && lightContrast === 0) return preferred;\n return darkContrast >= lightContrast ? DARK_BOOKABLE_LABEL_INK : LIGHT_BOOKABLE_LABEL_INK;\n}\n\nconst OPAQUE_HEX = /^#[0-9a-f]{6}$/i;\n\n/** Is a solid hex fill light enough to read as a light surface? Feedback helpers\n * use this to pick the neutral section shell a label sits on. */\nexport function isLightFill(fill: string): boolean {\n const value = luminance(fill);\n return value != null && value > 0.5;\n}\n\n/**\n * Neutral section shell fills the renderer paints when a section has no custom\n * colour, mirrored here so contrast feedback can evaluate uncoloured sections.\n */\nexport const LIGHT_NEUTRAL_SECTION_FILL = '#e5e7eb';\nexport const DARK_NEUTRAL_SECTION_FILL = '#273142';\nexport function neutralSectionFill(canvasBackground: string): string {\n return isLightFill(canvasBackground) ? LIGHT_NEUTRAL_SECTION_FILL : DARK_NEUTRAL_SECTION_FILL;\n}\n\nexport interface LabelInkContrastSummary {\n /** Backgrounds that could be evaluated (valid preferred + valid fill hex). */\n total: number;\n /** Backgrounds where the preferred ink is auto-swapped for legibility. */\n overridden: number;\n /** `applies` = preferred survives everywhere; `overridden` = swapped\n * everywhere; `mixed` = some of each; `none` = nothing evaluable. */\n status: 'applies' | 'overridden' | 'mixed' | 'none';\n /** Fallback ink chosen where the preferred was overridden (black/white), or\n * null when nothing was overridden — names the swap in user-facing copy. */\n overrideInk: string | null;\n}\n\n/**\n * Feedback-only companion to {@link stateAwareBookableLabelInk}: does a preferred\n * label ink survive across a set of backgrounds, or does the shared auto-contrast\n * rule silently swap it for black/white on some of them? Reuses the exact same\n * per-fill decision so a report can never disagree with what the renderer paints.\n */\nexport function summarizeLabelInkContrast(\n preferred: string,\n backgrounds: Iterable<string>,\n): LabelInkContrastSummary {\n const preferredValid = OPAQUE_HEX.test(preferred.trim());\n const preferredHex = preferred.trim().toLowerCase();\n let total = 0;\n let overridden = 0;\n let overrideInk: string | null = null;\n for (const fill of backgrounds) {\n if (!preferredValid || !OPAQUE_HEX.test(fill.trim())) continue;\n total += 1;\n const ink = stateAwareBookableLabelInk(fill, preferred);\n if (ink.toLowerCase() !== preferredHex) {\n overridden += 1;\n overrideInk = ink;\n }\n }\n const status = total === 0 ? 'none'\n : overridden === 0 ? 'applies'\n : overridden === total ? 'overridden'\n : 'mixed';\n return { total, overridden, status, overrideInk };\n}\n","/**\n * Money formatting — the ONE place currency rendering happens.\n *\n * Ticket money is multi-currency: the org sets a default and each event can\n * override it (ISO 4217 code delivered with the event/chart payload). Until\n * those backend fields land, callers fall back to DEFAULT_CURRENCY, which is\n * kept at EUR so live buyer pages render exactly what they rendered when the\n * symbol was hardcoded. Flipping an org to USD/INR/… later is data, not code.\n *\n * Amounts are in MAJOR units (45 === €45) matching Category.price in\n * src/core/types.ts. If/when backend money fields arrive in minor units,\n * convert at the API boundary, not here.\n */\n\n// App-wide fallback when no org currency is available (unauthed/demo surfaces).\n// Owner decision 2026-07-08: USD default (orgs.currency also defaults to USD).\nexport const DEFAULT_CURRENCY = 'USD';\n\n/** BCP 47 locale used for number/date rendering; kept in sync by src/i18n. */\nlet displayLocale: string | undefined;\n\nexport function setMoneyLocale(locale: string | undefined): void {\n displayLocale = locale;\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction formatter(currency: string, digits: number | undefined): Intl.NumberFormat {\n const key = `${displayLocale ?? ''}|${currency}|${digits ?? 'auto'}`;\n let fmt = formatterCache.get(key);\n if (!fmt) {\n fmt = new Intl.NumberFormat(displayLocale, {\n style: 'currency',\n currency,\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n formatterCache.set(key, fmt);\n }\n return fmt;\n}\n\n/**\n * \"€45\" / \"$1,500\" / \"45 €\" (locale-dependent placement).\n * Whole amounts render without \".00\" (design shows \"$45\", \"$120\"); pass\n * `fractionDigits` for fixed precision (e.g. 3 for \"$0.045 / credit\").\n */\nexport function formatMoney(\n amount: number,\n currency: string = DEFAULT_CURRENCY,\n fractionDigits?: number,\n): string {\n const digits = fractionDigits ?? (Number.isInteger(amount) ? 0 : undefined);\n return formatter(currency, digits).format(amount);\n}\n\n/** Bare symbol for input adornments (\"€\", \"$\", \"₹\"). */\nexport function currencySymbol(currency: string = DEFAULT_CURRENCY): string {\n const part = formatter(currency, 0)\n .formatToParts(0)\n .find((p) => p.type === 'currency');\n return part?.value ?? currency;\n}\n","/**\n * English bundle — the reference dictionary every other locale is checked\n * against. Keys are added as pages route their strings through t();\n * buyer-surface keys land first.\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const en: Dict = {\n // shared\n 'common.cancel': 'Cancel',\n 'common.close': 'Close',\n 'common.done': 'Done',\n 'common.copied': '✓ Copied',\n\n // buyer picker\n 'picker.holdSeats': 'Hold seats & checkout',\n 'picker.completeBooking': 'Complete booking',\n 'picker.seatsHeld': 'Seats held — {time}',\n 'picker.holdExpired': 'Your hold expired — the seats were released. Pick again.',\n 'picker.seatTaken': 'Seat {label} was just taken by another buyer.',\n 'picker.poweredBy': 'Powered by SeatLayer',\n 'picker.testMode': 'TEST MODE',\n 'picker.colorblind': 'Colorblind-friendly colors',\n 'picker.orphanHint': 'This leaves a single seat stranded — consider shifting one seat over.',\n 'picker.seats.one': '{count} seat',\n 'picker.seats.other': '{count} seats',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Seating map. Use arrow keys to move between seats, Enter to select.',\n 'map.seatsLeft': '{count} LEFT',\n 'map.fromPrice': 'FROM {price}',\n 'map.statusHeld': 'On hold',\n 'map.statusTaken': 'Taken',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Language',\n 'picker.zoomToFit': 'Zoom to fit',\n 'picker.seatCountLabel': 'seats',\n 'picker.capacity': 'capacity',\n 'picker.viewMode': 'View mode',\n 'picker.floor': 'Floor',\n 'picker.zoomLevel': 'Zoom level',\n 'picker.rungTip.zones': 'Venue overview — groups of sections such as North Stand or VIP',\n 'picker.rungTip.sections': 'Section blocks — category-mix fill + availability tint',\n 'picker.rungTip.seats': 'Individual seats — blocks melt into dots',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SEATS',\n 'picker.sectionSummaryAria': '{label} section summary',\n 'picker.closeSectionSummary': 'Close section summary',\n 'picker.seatsLeftInSection.one': '{count} seat left',\n 'picker.seatsLeftInSection.other': '{count} seats left',\n 'picker.overview': 'Overview',\n 'picker.tapSeatHint': 'Tap any seat to check its view',\n 'picker.chartSize': 'Chart size',\n 'picker.custom': 'Custom',\n 'picker.categories': 'Categories',\n 'picker.accessibility': 'Accessibility',\n 'picker.showAnyAccessible': 'Show any accessible seat',\n 'picker.any': 'Any',\n 'picker.yourSeats': 'Your seats',\n 'picker.emptySeats': 'Tap seats on the map',\n 'picker.emptySeatsWithGa': 'Tap seats on the map · tap a standing area for GA tickets',\n 'picker.oneFewer': 'One fewer',\n 'picker.oneMore': 'One more',\n 'picker.remove': 'Remove {label}',\n 'picker.ticketTierFor': 'Ticket tier for {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'View from seat {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'PREVIEW',\n 'picker.open360': 'Open 360° view',\n 'picker.sightline': '≈ {m} m to stage · clear sightline',\n 'picker.bookedDemo': 'Booked! (demo)',\n 'picker.bookButton.one': 'Book {count} ticket — {amount}',\n 'picker.bookButton.other': 'Book {count} tickets — {amount}',\n 'picker.simulateCrowd': 'Simulate crowd: {state}',\n 'picker.on': 'ON',\n 'picker.off': 'OFF',\n 'picker.panorama360': '360° venue photo',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m from stage',\n 'picker.restrictedView': 'Restricted view',\n 'picker.obstructedView': 'Obstructed view',\n 'picker.premiumSeat': 'Premium seat',\n 'picker.hideLimitedView': 'Hide limited-view seats',\n};\n","/**\n * i18n core — deliberately tiny and framework-free so the embed SDK can share\n * it without dragging in a runtime library (the 150KB-gzipped complete CDN budget is a\n * product contract).\n *\n * Scope: the buyer surface (picker, public event\n * page, SDK) ships fully translated in en/es/de/fr; dashboard pages route\n * their strings through t() as they are rebuilt but ship English this round.\n *\n * Keys are flat dot-namespaced strings (\"picker.holdSeats\"). Interpolation\n * uses {name} placeholders. Missing keys fall back to English, then to the\n * key itself — a page never crashes over a translation.\n */\n\nimport { setMoneyLocale } from '../lib/money';\nimport { en } from './locales/en';\n\nexport type Locale = 'en' | 'es' | 'de' | 'fr';\nexport const SUPPORTED_LOCALES: Locale[] = ['en', 'es', 'de', 'fr'];\n\nexport type Dict = Record<string, string>;\n\nconst bundles: Partial<Record<Locale, Dict>> = { en };\n\n/** Extra strings layered over the active bundle (SDK white-label overrides). */\nlet overrides: Dict = {};\n\nlet active: Locale = 'en';\n\n/** explicit setting → stored preference → browser language → en */\nexport function resolveLocale(explicit?: string | null, stored?: string | null): Locale {\n for (const candidate of [explicit, stored, typeof navigator !== 'undefined' ? navigator.language : null]) {\n if (!candidate) continue;\n const base = candidate.toLowerCase().split('-')[0] as Locale;\n if (SUPPORTED_LOCALES.includes(base)) return base;\n }\n return 'en';\n}\n\nexport function getLocale(): Locale {\n return active;\n}\n\n/**\n * Set the active locale. Locale bundles other than English are registered by\n * the surface that needs them (the picker imports its own es/de/fr bundles;\n * the dashboard stays English until its translations ship).\n */\nexport function setLocale(locale: Locale, bundle?: Dict): void {\n if (bundle) bundles[locale] = { ...bundles[locale], ...bundle };\n active = bundles[locale] ? locale : 'en';\n setMoneyLocale(active);\n if (typeof document !== 'undefined') document.documentElement.lang = active;\n}\n\nexport function setStringOverrides(next: Dict): void {\n overrides = next;\n}\n\nconst PLACEHOLDER = /\\{(\\w+)\\}/g;\n\nexport function t(key: string, vars?: Record<string, string | number>): string {\n const raw = overrides[key] ?? bundles[active]?.[key] ?? en[key] ?? key;\n if (!vars) return raw;\n return raw.replace(PLACEHOLDER, (_, name: string) => String(vars[name] ?? `{${name}}`));\n}\n\n/** \"1 seat\" / \"3 seats\" without hand-rolled concatenation. */\nexport function tCount(key: string, count: number, vars?: Record<string, string | number>): string {\n const rule = new Intl.PluralRules(active).select(count);\n const exact = overrides[`${key}.${rule}`] ?? bundles[active]?.[`${key}.${rule}`] ?? en[`${key}.${rule}`];\n const raw = exact ?? overrides[`${key}.other`] ?? bundles[active]?.[`${key}.other`] ?? en[`${key}.other`] ?? key;\n return raw.replace(PLACEHOLDER, (_, name: string) => String({ count, ...vars }[name] ?? `{${name}}`));\n}\n\nexport function formatDate(value: number | Date, opts?: Intl.DateTimeFormatOptions): string {\n return new Intl.DateTimeFormat(active, opts ?? { dateStyle: 'medium', timeStyle: 'short' }).format(value);\n}\n","/**\n * Orphan-seat detection for MANUAL selection — the client-side sibling of the\n * server's best-available orphan avoidance (workers/api/src/bestAvailable):\n * a \"stranded single\" is a free seat whose both same-row neighbors are\n * unavailable (non-free or currently selected). The picker uses this to show\n * a non-blocking hint; nothing is ever prevented.\n */\nimport type { ExpandedSeat, SeatStatus } from './types';\n\n/** Numeric seat index from the stable id (`${rowId}:${index}`). */\nfunction seatIndex(id: string): number {\n const n = Number(id.slice(id.lastIndexOf(':') + 1));\n return Number.isFinite(n) ? n : -1;\n}\n\n/**\n * Free seats stranded by the current selection: both same-row neighbors exist\n * and are unavailable, and at least one neighbor is part of `selectedIds` —\n * so pre-existing single gaps (caused by earlier buyers) never nag.\n * Booth units are ignored (no row adjacency).\n */\nexport function strandedSingles(\n seats: Iterable<ExpandedSeat>,\n statusOf: (seatId: string) => SeatStatus,\n selectedIds: ReadonlySet<string>,\n): ExpandedSeat[] {\n // Group by row, ordered by index, skipping booths.\n const rows = new Map<string, ExpandedSeat[]>();\n for (const s of seats) {\n if (s.kind === 'booth') continue;\n const list = rows.get(s.rowId);\n if (list) list.push(s);\n else rows.set(s.rowId, [s]);\n }\n\n const unavailable = (s: ExpandedSeat): boolean =>\n selectedIds.has(s.id) || statusOf(s.id) !== 'free';\n\n const out: ExpandedSeat[] = [];\n for (const list of rows.values()) {\n if (list.length < 3) continue;\n list.sort((a, b) => seatIndex(a.id) - seatIndex(b.id));\n for (let i = 1; i < list.length - 1; i++) {\n const seat = list[i];\n if (unavailable(seat)) continue; // not free (or selected) → not stranded\n const left = list[i - 1];\n const right = list[i + 1];\n // Neighbors must be physically adjacent (index gap of 1) — a labelled\n // aisle gap in the numbering doesn't strand anyone.\n if (seatIndex(seat.id) - seatIndex(left.id) !== 1 || seatIndex(right.id) - seatIndex(seat.id) !== 1) continue;\n if (!unavailable(left) || !unavailable(right)) continue;\n if (!selectedIds.has(left.id) && !selectedIds.has(right.id)) continue;\n out.push(seat);\n }\n }\n return out;\n}\n","/**\n * PickerController — the single, framework-agnostic buyer-picker core.\n *\n * Consolidates the transport + booking logic that was copy-pasted across\n * sdk/src/SeatingChart.ts, src/pages/PublicEventPage.tsx and PickerPage.tsx:\n * fetch the published chart, mount the Konva renderer, seed statuses from a REST\n * snapshot, keep them live over a WebSocket (reconnect w/ backoff, re-snapshot on\n * every open), and run the hold → book state machine (best-available, hold reuse,\n * per-label partial release, 409 semantics, server-authoritative hold expiry).\n *\n * The SDK, the live buyer page, and the demo picker all drive this one class;\n * presentation (confirm card, legend, cart, etc.) lives in the consumers.\n *\n * Transport is injected (PickerTransport) so the SDK can use its CORS-trivial\n * PubApi while the dashboard uses an adapter over src/lib/api.ts.\n */\nimport { createRenderer } from '../engine/SeatmapRenderer';\nimport { allObjects, expandChart } from '../core/layout';\nimport { applyHidden, computeSections } from '../core/sections';\nimport { strandedSingles } from '../core/orphans';\nimport { t } from '../i18n';\nimport type {\n CategoryTier,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n RendererCallbacks,\n SeatCommercialAttributes,\n SeatStatus,\n SectionObject,\n} from '../core/types';\nimport { gaAreasOf, gaUnitLabels } from '../core/ga';\n\nconst DEFAULT_MAX_SELECTION = 10;\nconst MAX_BACKOFF_MS = 15_000;\n\nexport interface PickerSeat {\n id: string;\n label: string;\n categoryKey: string;\n /** Price for the chosen tier when the category has tiers, else the base price. */\n price: number;\n /** Ticket tiers the seat's category offers (Adult/Child/…); absent when none. */\n tiers?: CategoryTier[];\n /** The chosen tier's id — defaults to the first tier; absent when no tiers. */\n tierId?: string;\n /** Commercial selling/view attributes (restricted/obstructed view, premium,\n * note) resolved for this seat; absent when the seat carries none. Lets the\n * buyer cart + confirm surface flag limited-view/premium seats. */\n commercial?: SeatCommercialAttributes;\n}\n\n/**\n * Rich hover payload for seat tooltips — the PickerSeat plus everything a\n * buyer-facing popover needs: category label + swatch color, live status and\n * the chart currency. Emitted by `onSeatHover` (null on hover-out).\n */\nexport interface SeatHoverDetails extends PickerSeat {\n categoryLabel: string;\n categoryColor: string;\n status: SeatStatus;\n currency: string;\n /** Human-readable spatial context for hover and confirmation UI. */\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: string;\n}\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\n/** An open hold — its id, the labels it covers, and the server's expiry time (ms epoch). */\nexport interface HoldInfo {\n holdId: string;\n labels: string[];\n expiresAt: number;\n /** The held seats with their chosen ticket tier — what the host books against. */\n seats: PickerSeat[];\n /** Server-authoritative commercial line items, including GA units and resolved prices. */\n items?: HoldServerItem[];\n}\n\n/** One category's slice of a section (dot + price + count) for the summary card. */\nexport interface SectionCategory {\n key: string;\n label: string;\n color: string;\n price: number;\n count: number;\n}\n\n/**\n * Big-venue section-summary — everything the tapped-section card renders: name,\n * its zone, live seats-left, price range, and the per-category breakdown.\n * Computed from the renderer's spatial section membership (Slice 5).\n */\nexport interface SectionSummary {\n id: string;\n label: string;\n /** Zone label (from ChartDoc.zones); '' when the section has no zone. */\n zoneLabel: string;\n /** Mix/section colour for the card's dot (section.color → zone colour → dominant category). */\n color: string;\n /** Free member seats right now. */\n seatsLeft: number;\n priceMin: number;\n priceMax: number;\n /** Per-category breakdown, cheapest first. */\n categories: SectionCategory[];\n}\n\ninterface HoldResponse {\n holdId: string;\n expiresAt: number;\n items?: HoldServerItem[];\n}\ninterface ResumeHoldResponse extends HoldResponse {\n items: HoldServerItem[];\n}\nexport interface HoldServerItem {\n label: string;\n objectId: string;\n objectType: 'seat' | 'booth' | 'ga';\n categoryKey: string;\n tierId: string | null;\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\nexport interface HoldSelectionRequest { label: string; tierId?: string | null }\ninterface BestAvailableResponse extends HoldResponse {\n labels: string[];\n}\n\n/** Swappable public-surface transport (SDK PubApi or a dashboard `api.pub.*` adapter). */\nexport interface PickerTransport {\n chart(key: string): Promise<{\n doc: ChartDoc;\n event: { key: string; name: string; salesClosed?: boolean; venue?: string | null; startsAt?: number | null; currency?: string; mode?: string };\n }>;\n objects(key: string): Promise<{ seats: Record<string, string>; hidden?: string[]; closed?: string[] }>;\n hold(key: string, selections: HoldSelectionRequest[], ttlMs?: number, replaceHoldId?: string): Promise<HoldResponse>;\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResponse>;\n release(key: string, labels: string[], holdId: string): Promise<unknown>;\n /** Optional capability-style lookup used to restore an active browser hold. */\n resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;\n /** Optional — the SDK omits booking (it hands the holdId to the host page). */\n book?(key: string, labels: string[], holdId: string, bookingRef: string): Promise<unknown>;\n /** Optional (P4) — push an active hold's expiry out (\"need more time?\"). */\n extend?(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends?: number }>;\n socketUrl(key: string): string;\n}\n\nexport interface PickerCallbacks extends RendererCallbacks {\n /** Selection changed (manual clicks or a server best-available pick). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /** A hold opened (manual hold or best-available). */\n onHold?: (hold: HoldInfo) => void;\n /** A prior active hold was restored from its opaque hold id. */\n onHoldRestored?: (hold: HoldInfo) => void;\n /** The open hold expired server-side (the controller has already released it). */\n onHoldExpired?: () => void;\n /** A booking completed with this ref. */\n onBook?: (bookingRef: string) => void;\n /** Any live seat-status change arrived (delta or snapshot) — e.g. to recount \"N left\". */\n onStatusChange?: () => void;\n /**\n * Mouse hover moved onto a seat (null on hover-out) — the seat enriched with\n * category label/color, resolved price and live status, ready for a tooltip.\n * Fires alongside the raw renderer-level `onHover`.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n /** The server declared the event closed (a 409 event_closed). */\n onSalesClosed?: () => void;\n /**\n * A section block was tapped at the far/zone rung — the controller has glided\n * the camera in and passes the computed summary (or null when cleared, e.g.\n * overview() / zoom-to-zones) so the host can show/hide the summary card.\n */\n onSectionFocus?: (summary: SectionSummary | null) => void;\n /** A deck was tapped in the 3D all-floors overview — host enters that floor in 2D. */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking selection advice (localized): currently the orphan-seat hint —\n * the selection would strand a single free seat between unavailable\n * neighbors. `null` clears a previously shown hint. Never prevents anything.\n */\n onHint?: (message: string | null) => void;\n onError?: (err: unknown) => void;\n}\n\nexport interface PickerOptions extends PickerCallbacks {\n transport: PickerTransport;\n eventKey: string;\n maxSelection?: number;\n /** Renderer confirm-card mode (host shows a confirm popover instead of instant cart add). */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (default from money.DEFAULT_CURRENCY). */\n currency?: string;\n /** Flash a pulse when a seat we didn't touch goes free→taken (live-activity cue). */\n flashOnLiveChange?: boolean;\n /** Start in colorblind-safe rendering (Okabe-Ito hues + hollow booked seats). */\n colorblindSafe?: boolean;\n /**\n * Keep painting seat-status deltas even while the tab is hidden/backgrounded.\n *\n * Default FALSE — the buyer widget stays efficient: it lets rAF stay paused\n * while hidden and does a single synchronous catch-up repaint on regain (the\n * visibilitychange handler resnapshots + forceDraw()s). Set TRUE only for an\n * always-live surface — the future organizer control-room board — where a\n * backgrounded monitor must keep repainting; then each delta calls\n * renderer.forceDraw() when the tab is hidden. Purely a paint hint; enforcement\n * and the WS protocol are identical either way.\n */\n keepLiveWhileHidden?: boolean;\n}\n\n/** Read `status`/`conflicts`/`reason` off any thrown error without importing a specific ApiError. */\nfunction errInfo(err: unknown): { status?: number; conflicts?: HoldConflict[]; reason?: string } {\n const e = (err ?? {}) as { status?: number; conflicts?: HoldConflict[]; reason?: string };\n return { status: e.status, conflicts: e.conflicts, reason: e.reason };\n}\n\n/** DO seat status → renderer status ('blocked' has no renderer analogue → 'not_for_sale'). */\nfunction mapStatus(s: string): SeatStatus {\n if (s === 'blocked') return 'not_for_sale';\n if (s === 'held' || s === 'booked' || s === 'free' || s === 'not_for_sale') return s;\n return 'free';\n}\n\nexport class PickerController {\n private readonly opts: PickerOptions;\n private readonly api: PickerTransport;\n private readonly key: string;\n private maxSelection: number;\n\n private renderer: ISeatmapRenderer | null = null;\n private _doc: ChartDoc | null = null;\n /** Section/zone ids hidden from buyers this event (3.3) — seats vanish, not grey. */\n private hidden = new Set<string>();\n /** Section/zone ids in the `closed` event-state (Phase 2) — seats stay, greyed\n * + not pickable. Kept separate from `hidden` (which strips them). */\n private closedSections = new Set<string>();\n\n /** label ⇄ id maps — backend speaks labels, the engine speaks ids. */\n private labelToId = new Map<string, string>();\n private labelToSeat = new Map<string, ExpandedSeat>();\n /** seatId → chosen ticket-tier id (absent ⇒ the category's first/default tier). */\n private seatTiers = new Map<string, string>();\n /** id → seat, for the section-summary breakdown (renderer members are ids). */\n private seatById = new Map<string, ExpandedSeat>();\n /** id → buyer-facing spatial metadata used by every tooltip/confirm surface. */\n private seatContext = new Map<string, { sectionLabel?: string; rowLabel?: string; seatNumber?: string }>();\n private allIds: string[] = [];\n\n // realtime socket\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private attempt = 0;\n private closed = false;\n /** Bound visibilitychange listener (buyer catch-up on tab regain). Kept on the\n * instance so destroy() can detach it; null when not attached (guards double\n * mounts / non-DOM environments). */\n private onVisibilityChange: (() => void) | null = null;\n\n // hold state\n private hold_: HoldInfo | null = null;\n private liveStatuses = new Map<string, string>();\n private currency = 'USD';\n private expiryTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: PickerOptions) {\n this.opts = options;\n this.api = options.transport;\n this.key = options.eventKey;\n this.maxSelection = options.maxSelection ?? DEFAULT_MAX_SELECTION;\n }\n\n get doc(): ChartDoc | null {\n return this._doc;\n }\n\n /** The chart with hidden sections' seats removed — what buyers actually see. */\n private visibleDoc(): ChartDoc {\n return this._doc ? applyHidden(this._doc, this.hidden) : ({ objects: [] } as unknown as ChartDoc);\n }\n\n /** Adopt a new hidden set; rebuild the visible chart only if it differs. */\n private syncHidden(ids: string[]): boolean {\n const next = ids.filter((x): x is string => typeof x === 'string');\n if (next.length === this.hidden.size && next.every((id) => this.hidden.has(id))) return false;\n this.hidden = new Set(next);\n this.renderer?.setChart(this.visibleDoc());\n return true;\n }\n\n /** Adopt a new closed-section set; restyle (grey + non-pickable) if it differs.\n * Cheap restyle — no chart rebuild — so mid-sale open/close repaints live. */\n private syncClosed(ids: string[] | undefined): boolean {\n const next = (ids ?? []).filter((x): x is string => typeof x === 'string');\n if (next.length === this.closedSections.size && next.every((id) => this.closedSections.has(id))) return false;\n this.closedSections = new Set(next);\n this.renderer?.setClosedSections?.(next);\n return true;\n }\n\n /** Whether a section is currently in the `closed` state (card must not open). */\n isSectionClosed(id: string): boolean {\n return this.closedSections.has(id);\n }\n currentHold(): HoldInfo | null {\n return this.hold_;\n }\n getRenderer(): ISeatmapRenderer | null {\n return this.renderer;\n }\n seatByLabel(label: string): ExpandedSeat | undefined {\n return this.labelToSeat.get(label);\n }\n idForLabel(label: string): string | undefined {\n return this.labelToId.get(label);\n }\n\n /** Fetch chart, build label maps, mount the renderer, seed statuses, go live. */\n async render(host: HTMLDivElement): Promise<{\n doc: ChartDoc;\n salesClosed: boolean;\n eventName: string;\n venue?: string | null;\n startsAt?: number | null;\n currency?: string;\n /** 'test' ⇒ sandbox event (hosts show a TEST MODE ribbon). */\n mode?: string;\n } | null> {\n if (this.renderer) return null; // already rendered — never mount twice on one controller\n this.closed = false;\n let res;\n try {\n res = await this.api.chart(this.key);\n } catch (err) {\n this.emitError(err);\n return null;\n }\n // destroy() may have run while the chart fetch was in flight (StrictMode\n // double-mount, or a fast key change) — bail before mounting anything.\n if (this.closed) return null;\n this._doc = res.doc;\n\n this.labelToId = new Map();\n this.labelToSeat = new Map();\n this.seatById = new Map();\n this.seatContext = new Map();\n this.allIds = [];\n const chartObjects = new Map(allObjects(res.doc).map((object) => [object.id, object] as const));\n const membership = computeSections(res.doc);\n const sectionLabels = new Map(\n [...membership.sections, ...(membership.ungrouped ? [membership.ungrouped] : [])].map((section) => [section.id, section.label] as const),\n );\n for (const s of expandChart(res.doc)) {\n this.labelToId.set(s.label, s.id);\n this.labelToSeat.set(s.label, s);\n this.seatById.set(s.id, s);\n this.allIds.push(s.id);\n const source = chartObjects.get(s.rowId);\n const sourceLabel = source && 'label' in source && typeof source.label === 'string' ? source.label : undefined;\n const rowLabel = s.kind === 'booth' ? undefined : sourceLabel;\n const labelParts = s.label.split('-');\n const seatNumber = rowLabel && s.label.startsWith(`${rowLabel}-`)\n ? s.label.slice(rowLabel.length + 1)\n : s.kind === 'booth'\n ? s.label\n : labelParts[labelParts.length - 1] ?? s.label;\n this.seatContext.set(s.id, {\n sectionLabel: sectionLabels.get(membership.objectToSection.get(s.rowId) ?? ''),\n rowLabel,\n seatNumber,\n });\n }\n\n // The organizer's currency travels with the chart payload; it wins over any\n // option passed at construction (the SDK host may not know it up front).\n const currency = res.event.currency ?? this.opts.currency;\n this.currency = currency ?? 'USD';\n const renderer = createRenderer(host, {\n maxSelection: this.maxSelection,\n confirmSelection: this.opts.confirmSelection,\n currency,\n onSelect: (seat) => {\n this.opts.onSelect?.(seat);\n this.emitSelectionChange();\n },\n onDeselect: (seat) => {\n this.opts.onDeselect?.(seat);\n this.emitSelectionChange();\n },\n onSelectionLimit: this.opts.onSelectionLimit,\n onHover: (seat) => {\n this.opts.onHover?.(seat);\n if (this.opts.onSeatHover) this.opts.onSeatHover(seat ? this.describeSeat(seat) : null);\n },\n onFocusSeat: this.opts.onFocusSeat,\n onViewChange: this.opts.onViewChange,\n onGAClick: this.opts.onGAClick,\n // Section tap at the far/zone rung → glide in + surface the summary card.\n onSectionTap: (id) => this.handleSectionTap(id),\n onDeckTap: (floorId) => this.handleDeckTap(floorId),\n onFps: this.opts.onFps,\n });\n if (this.closed) {\n renderer.destroy(); // destroyed during createRenderer — don't leak the stage\n return null;\n }\n this.renderer = renderer;\n\n // Pull live state (seat statuses + hidden section/zone ids) BEFORE the first\n // paint so hidden sections never flash in. Falls back to the raw chart if the\n // snapshot is briefly unavailable — the WS re-snapshot then reconciles.\n let seats: Record<string, string> | null = null;\n let closedIds: string[] = [];\n try {\n const objs = await this.api.objects(this.key);\n this.hidden = new Set(objs.hidden ?? []);\n closedIds = (objs.closed ?? []).filter((x): x is string => typeof x === 'string');\n seats = objs.seats;\n } catch {\n /* transient — connect()'s onopen re-snapshots */\n }\n if (this.closed) {\n renderer.destroy();\n this.renderer = null;\n return null;\n }\n renderer.setChart(this.visibleDoc());\n if (this.opts.colorblindSafe) renderer.setColorblindSafe?.(true);\n // Closed sections are applied AFTER setChart (which resets state) so their\n // grey + non-pickable treatment lands on the first paint, no flash.\n this.closedSections = new Set(closedIds);\n if (closedIds.length) renderer.setClosedSections?.(closedIds);\n if (seats) this.applySeatsMap(seats);\n this.attachVisibilityListener();\n this.connect();\n return {\n doc: res.doc,\n salesClosed: !!res.event.salesClosed,\n eventName: res.event.name,\n venue: res.event.venue,\n startsAt: res.event.startsAt,\n currency,\n // 'test' ⇒ sandbox event: hosts render a TEST MODE ribbon (Phase 11).\n mode: res.event.mode ?? 'live',\n };\n }\n\n // ---- selection ------------------------------------------------------------\n\n getSelection(): PickerSeat[] {\n if (!this.renderer) return [];\n return this.renderer.getSelection().map((s) => this.toSeat(s));\n }\n /** Enriched metadata for a seat confirmation card or tooltip. */\n seatDetails(seatId: string): SeatHoverDetails | null {\n const seat = this.seatById.get(seatId);\n return seat ? this.describeSeat(seat) : null;\n }\n clearSelection(): void {\n this.renderer?.clearSelection();\n this.emitSelectionChange();\n }\n deselect(ids: string[]): void {\n this.renderer?.deselect(ids);\n this.emitSelectionChange();\n }\n setMaxSelection(maxSelection: number): void {\n this.maxSelection = Math.max(0, Math.floor(maxSelection));\n this.renderer?.setMaxSelection?.(this.maxSelection);\n }\n select(ids: string[]): PickerSeat[] {\n const added = this.renderer?.select?.(ids) ?? [];\n if (added.length) this.emitSelectionChange();\n return added.map((seat) => this.toSeat(seat));\n }\n\n // ---- booking machine ------------------------------------------------------\n\n /**\n * Hold the current selection (or a given label set). The controller does the\n * renderer/hold side (409 → deselect + repaint the taken seats held) and then\n * re-throws so the caller can choose the banner copy. Returns null only when\n * there's nothing to hold.\n */\n async hold(labelsArg?: string[], ttlMs?: number): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n const labels = labelsArg ?? r.getSelection().map((s) => s.label);\n const existingGA = (this.hold_?.items ?? []).filter((item) => item.objectType === 'ga');\n const combinedLabels = [...new Set([...existingGA.map((item) => item.label), ...labels])];\n if (!combinedLabels.length) return null;\n\n // Reuse an existing hold that exactly covers this selection (re-holding 409s).\n if (this.hold_ && this.holdCovers(combinedLabels)) return this.hold_;\n try {\n const selections = combinedLabels.map((label) => {\n const ga = existingGA.find((item) => item.label === label);\n if (ga) return { label, tierId: ga.tierId };\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return { label, ...(resolved?.tierId ? { tierId: resolved.tierId } : {}) };\n });\n const result = await this.api.hold(this.key, selections, ttlMs, this.hold_?.holdId);\n this.setHold({ holdId: result.holdId, labels: combinedLabels, expiresAt: result.expiresAt, items: result.items });\n return this.hold_;\n } catch (err) {\n this.handle409Conflicts(err);\n throw err;\n }\n }\n\n /** Restore an active server hold without creating or extending inventory. */\n async resumeHold(holdId: string): Promise<HoldInfo | null> {\n if (this.closed || !holdId || !this.api.resume) return null;\n const result = await this.api.resume(this.key, holdId);\n if (this.closed) return null;\n const labels = [...new Set(result.items.map((item) => item.label))];\n if (!labels.length) return null;\n this.setHold(\n { holdId: result.holdId, labels, expiresAt: result.expiresAt, items: result.items },\n 'restored',\n );\n return this.hold_;\n }\n\n /**\n * P4 \"need more time?\": extend the OPEN hold's server-side expiry and re-arm\n * the client expiry timer to match (via setHold), so the controller doesn't\n * fire a false expiry and start polling. Returns the new hold, or null if\n * there's no open hold or the transport can't extend / the server refused\n * (hold gone, expired, or at its renewal cap). Never throws for the refusal\n * case — the caller decides the copy.\n */\n async extendHold(ttlMs?: number): Promise<HoldInfo | null> {\n const current = this.hold_;\n if (!current || !this.api.extend) return null;\n try {\n const result = await this.api.extend(this.key, current.holdId, ttlMs);\n if (this.hold_?.holdId !== current.holdId) return this.hold_; // superseded meanwhile\n // Keep the same labels/items — only the expiry moved. setHold re-arms the timer.\n this.setHold({ holdId: current.holdId, labels: current.labels, expiresAt: result.expiresAt, items: current.items });\n return this.hold_;\n } catch {\n return null;\n }\n }\n\n /** Public GA inventory derived from the live synthetic-unit status stream. */\n /**\n * Live seats-left per category key (status 'free' right now). Recompute on\n * onStatusChange — this is what a price panel's \"N left\" counters read.\n */\n categoryAvailability(): Record<string, number> {\n const out: Record<string, number> = {};\n const closedMembers = this.closedMemberIds();\n for (const [id, s] of this.seatById) {\n if (closedMembers.has(id)) continue; // closed sections aren't on sale\n if ((this.getStatus(id) ?? 'free') === 'free') {\n out[s.categoryKey] = (out[s.categoryKey] ?? 0) + 1;\n }\n }\n return out;\n }\n\n /** Seat ids belonging to a currently-closed section (excluded from counts). */\n private closedMemberIds(): Set<string> {\n const out = new Set<string>();\n const r = this.renderer;\n if (!r || !this.closedSections.size) return out;\n for (const id of this.closedSections) for (const sid of (r.sectionMembers?.(id) ?? [])) out.add(sid);\n return out;\n }\n\n getGAAreas(): { id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string; tiers?: CategoryTier[] }[] {\n const doc = this.visibleDoc();\n if (!doc) return [];\n return gaAreasOf(doc).map((area) => {\n const category = doc.categories.find((candidate) => candidate.key === area.categoryKey);\n return {\n id: area.id,\n label: area.label,\n capacity: Math.max(0, Math.floor(area.capacity)),\n available: gaUnitLabels(area).filter((label) => (this.liveStatuses.get(label) ?? 'free') === 'free').length,\n categoryKey: area.categoryKey,\n tiers: category?.tiers,\n price: category?.tiers?.[0]?.price ?? category?.price ?? 0,\n currency: this.currency,\n };\n });\n }\n\n /** Select a quantity from one GA area and hold it atomically. */\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldInfo | null> {\n const doc = this.visibleDoc();\n if (!doc || !Number.isFinite(qty) || qty < 1) return null;\n const area = gaAreasOf(doc).find((candidate) => candidate.id === areaId);\n if (!area) return null;\n const labels = gaUnitLabels(area)\n .filter((label) => !this.hold_?.labels.includes(label) && (this.liveStatuses.get(label) ?? 'free') === 'free')\n .slice(0, Math.floor(qty));\n if (labels.length !== Math.floor(qty)) return null;\n const selections = new Map<string, { label: string; tierId?: string | null }>();\n for (const item of this.hold_?.items ?? []) selections.set(item.label, { label: item.label, tierId: item.tierId });\n if (this.hold_ && !this.hold_?.items?.length) {\n for (const seat of this.hold_.seats) selections.set(seat.label, { label: seat.label, ...(seat.tierId ? { tierId: seat.tierId } : {}) });\n }\n for (const seat of this.renderer?.getSelection() ?? []) {\n const resolved = this.labelToSeat.get(seat.label);\n const chosen = resolved ? this.toSeat(resolved) : null;\n selections.set(seat.label, { label: seat.label, ...(chosen?.tierId ? { tierId: chosen.tierId } : {}) });\n }\n for (const label of labels) selections.set(label, { label, ...(options.tierId ? { tierId: options.tierId } : {}) });\n const combined = [...selections.values()];\n const result = await this.api.hold(this.key, combined, options.ttlMs, this.hold_?.holdId);\n this.setHold({ holdId: result.holdId, labels: combined.map((s) => s.label), expiresAt: result.expiresAt, items: result.items });\n return this.hold_;\n }\n\n /** Server-picks `qty` best free seats and holds them atomically. Throws on failure. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n // Drop any prior auto-hold first.\n if (this.hold_ && !(await this.release())) return null;\n try {\n const result = await this.api.bestAvailable(this.key, qty, categoryKey);\n r.clearSelection();\n const ids = result.labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) r.setStatus(ids, 'held');\n this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt, items: result.items });\n const seats = result.labels\n .map((l) => this.labelToSeat.get(l))\n .filter((s): s is ExpandedSeat => !!s)\n .map((s) => this.toSeat(s));\n this.opts.onSelectionChange?.(seats);\n return this.hold_;\n } catch (err) {\n const { status, reason } = errInfo(err);\n if (status === 409 && reason === 'event_closed') this.opts.onSalesClosed?.();\n throw err;\n }\n }\n\n /**\n * Complete a booking. Requires a transport that supports book() (the SDK\n * deliberately does not). `bookingRef` MUST be a real reference from the caller.\n * `labelsArg` lets the caller book its own cart (the live page's confirm-flow\n * cart can hold best-available seats that aren't in the renderer selection);\n * defaults to the renderer selection. Reuses an existing exact-match hold, else\n * holds first. Returns the labels booked, or null on failure (conflicts painted).\n */\n async book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null> {\n const r = this.renderer;\n if (!r) return null;\n if (!this.api.book) throw new Error('picker: transport has no book() — hold-only mode');\n const labels = labelsArg ?? r.getSelection().map((s) => s.label);\n if (!labels.length) return null;\n\n let holdId: string | undefined;\n try {\n if (this.hold_ && this.holdCovers(labels)) {\n holdId = this.hold_.holdId; // already held server-side — re-holding would 409\n } else {\n const replaceHoldId = this.hold_?.holdId;\n const h = await this.api.hold(\n this.key,\n labels.map((label) => {\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return { label, ...(resolved?.tierId ? { tierId: resolved.tierId } : {}) };\n }),\n undefined,\n replaceHoldId,\n );\n holdId = h.holdId;\n this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });\n }\n await this.api.book(this.key, labels, holdId, bookingRef);\n } catch (err) {\n const { status, conflicts, reason } = errInfo(err);\n this.clearHold();\n if (status === 409 && reason === 'event_closed') {\n this.opts.onSalesClosed?.();\n } else if (status === 409 && conflicts?.length) {\n // Paint the taken seats, deselect them, release the still-free remainder.\n const takenLabels = new Set(conflicts.map((c) => c.label));\n const takenIds = [...takenLabels].map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (takenIds.length) {\n r.setStatus(takenIds, 'booked');\n r.deselect(takenIds);\n }\n const stillFree = labels.filter((l) => !takenLabels.has(l));\n if (stillFree.length && holdId) void this.api.release(this.key, stillFree, holdId).catch(() => {});\n this.emitSelectionChange();\n } else if (holdId) {\n // Non-conflict failure after a hold landed — release it so seats aren't stranded.\n void this.api.release(this.key, labels, holdId).catch(() => {});\n }\n throw err;\n }\n // Success — optimistically paint booked, deselect just the booked seats\n // (not the whole selection — the cart may be an explicit subset), clear hold.\n const ids = labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n r.setStatus(ids, 'booked');\n r.deselect(ids);\n }\n this.clearHold();\n this.emitSelectionChange();\n this.opts.onBook?.(bookingRef);\n return labels;\n }\n\n /** Release the whole open hold (if any), repaint those seats free. */\n async release(): Promise<boolean> {\n const hold = this.hold_;\n if (!hold) return true;\n try {\n const result = await this.api.release(this.key, hold.labels, hold.holdId);\n if (!this.releaseConfirmed(result, hold.labels)) {\n await this.resnapshot();\n return false;\n }\n } catch (err) {\n this.emitError(err);\n return false;\n }\n if (this.hold_?.holdId !== hold.holdId) return true;\n this.clearHold();\n const ids = hold.labels.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n this.renderer?.deselect(ids);\n this.renderer?.setStatus(ids, 'free');\n }\n return true;\n }\n\n /**\n * Release just some labels from the open hold, keeping the rest held (used when\n * a buyer removes one seat chip). Clears the hold entirely once it empties.\n */\n async releaseLabels(labels: string[]): Promise<boolean> {\n const hold = this.hold_;\n if (!hold) return true;\n const drop = labels.filter((l) => hold.labels.includes(l));\n if (!drop.length) return true;\n try {\n const result = await this.api.release(this.key, drop, hold.holdId);\n if (!this.releaseConfirmed(result, drop)) {\n await this.resnapshot();\n return false;\n }\n } catch (err) {\n this.emitError(err);\n return false;\n }\n if (this.hold_?.holdId !== hold.holdId) return true;\n const remaining = hold.labels.filter((l) => !drop.includes(l));\n const remainingItems = hold.items?.filter((item) => !drop.includes(item.label));\n if (remaining.length) this.setHold({ ...hold, labels: remaining, items: remainingItems });\n else this.clearHold();\n const ids = drop.map((l) => this.labelToId.get(l)).filter((v): v is string => !!v);\n if (ids.length) {\n this.renderer?.deselect(ids);\n this.renderer?.setStatus(ids, 'free');\n }\n return true;\n }\n\n /** New transports return the exact labels released; tolerate older adapters. */\n private releaseConfirmed(result: unknown, requested: string[]): boolean {\n const released = (result as { released?: unknown } | null)?.released;\n return !Array.isArray(released) || requested.every((label) => released.includes(label));\n }\n\n // ---- renderer proxies (so consumers don't reach through) ------------------\n\n setStatus(ids: string[], status: SeatStatus): void {\n this.renderer?.setStatus(ids, status);\n }\n getStatus(id: string): SeatStatus | undefined {\n return this.renderer?.getStatus(id);\n }\n flashSeat(id: string, color?: string): void {\n this.renderer?.flashSeat(id, color);\n }\n zoomIn(): void {\n this.renderer?.zoomIn();\n }\n zoomOut(): void {\n this.renderer?.zoomOut();\n }\n zoomToFit(): void {\n this.renderer?.zoomToFit();\n }\n worldToScreen(p: { x: number; y: number }): { x: number; y: number } {\n return this.renderer?.worldToScreen(p) ?? { x: 0, y: 0 };\n }\n setSelectionFocus(seatId: string | null): void {\n this.renderer?.setSelectionFocus?.(seatId);\n }\n setAccessibilityFilter(types: string[] | null): void {\n this.renderer?.setAccessibilityFilter?.(types as never);\n }\n /**\n * \"Hide limited-view seats\" toggle — dims free seats flagged\n * restricted/obstructed view. Additive commercial parallel to the\n * accessibility filter; called via the concrete renderer (not on the shared\n * ISeatmapRenderer interface).\n */\n setCommercialLimitedFilter(on: boolean): void {\n (this.renderer as { setCommercialLimitedFilter?: (on: boolean) => void } | null)\n ?.setCommercialLimitedFilter?.(on);\n }\n\n // ---- multi-floor (Batch 5) ------------------------------------------------\n\n /** Floors for the buyer's switcher (>1 ⇒ show it). Single-floor ⇒ one entry. */\n getFloors(): { id: string; name: string }[] {\n return this.renderer?.getFloors?.() ?? [];\n }\n getActiveFloorId(): string {\n return this.renderer?.getActiveFloorId?.() ?? '';\n }\n /** Switch the shown floor (2D), then re-apply live seat statuses onto it. */\n setFloor(id: string): void {\n const r = this.renderer;\n if (!r?.setActiveFloor || id === r.getActiveFloorId?.()) return;\n r.setStacked?.(false); // leaving any 3D stack — back to a single floor\n r.setActiveFloor(id);\n void this.resnapshot(); // re-paint statuses on the newly-rendered floor\n this.emitSelectionChange();\n }\n\n /** 3D all-floors stacked overview ⇄ active floor. Re-applies statuses after. */\n setStacked(on: boolean): void {\n const r = this.renderer;\n if (!r?.setStacked || on === r.isStacked?.()) return;\n r.setStacked(on);\n void this.resnapshot(); // re-paint statuses across the rebuilt view\n }\n isMultiFloor(): boolean {\n return (this._doc?.floors?.length ?? 0) > 1;\n }\n\n /** Tap-a-deck-to-enter: leave the 3D stack, drop to flat 2D on `floorId`, and\n * tell the host so it can sync its 2D/3D toggle + floor-switcher state. */\n private handleDeckTap(floorId: string): void {\n const r = this.renderer;\n if (!r) return;\n r.setViewMode?.('flat');\n r.setStacked?.(false);\n r.setActiveFloor?.(floorId);\n void this.resnapshot();\n this.emitSelectionChange();\n this.opts.onDeckTap?.(floorId);\n }\n\n // ---- big-venue: sections / rungs / projection (Slice 5) -------------------\n\n /** Switch the map projection (2D flat ⇄ 3D isometric). No-op on a flat renderer. */\n setViewMode(mode: 'flat' | 'isometric'): void {\n this.renderer?.setViewMode?.(mode);\n }\n getViewMode(): 'flat' | 'isometric' {\n return this.renderer?.getViewMode?.() ?? 'flat';\n }\n /** Current LOD rung (for the ZONES/SECTIONS/SEATS pill). */\n getRung(): LodRung {\n return this.renderer?.getRung?.() ?? 'seats';\n }\n /** Jump to a rung; ZONES clears any focused summary (back to overview). */\n setRung(rung: LodRung): void {\n if (rung === 'zones') {\n this.overview();\n return;\n }\n this.renderer?.setRung?.(rung);\n }\n\n /** Price-band filter (F4): dim free seats whose category is outside `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter(keys: string[] | null): void {\n this.renderer?.setCategoryFilter?.(keys);\n }\n\n /** An explicit buyer price-filter action should not only dim the rest of the\n * chart: clear any older section drill-in and guide the camera to the seats\n * that remain relevant. Clearing the filter glides back to the full chart. */\n focusCategoryFilter(keys: string[] | null): void {\n const renderer = this.renderer;\n if (!renderer) return;\n renderer.clearSectionFocus?.();\n this.opts.onSectionFocus?.(null);\n // Multi-floor: the wanted categories may live on another deck entirely.\n // The renderer only knows the active floor's seats, so without switching\n // first the camera has nothing to frame and the filter is a silent no-op.\n if (keys?.length) {\n const target = this.floorForCategories(keys);\n if (target) this.setFloor(target);\n }\n if (renderer.focusCategories) renderer.focusCategories(keys);\n else renderer.zoomToFit();\n }\n\n /** The floor a buyer means when filtering to `keys`: the active floor when it\n * carries any of those categories, else the first floor that does (null =\n * stay put). Row overrides and GA areas count — a category can exist on a\n * floor only via a per-seat override. */\n private floorForCategories(keys: string[]): string | null {\n const doc = this._doc;\n if (!doc?.floors || doc.floors.length < 2) return null;\n const wanted = new Set(keys);\n const carries = (objects: ChartObject[]): boolean =>\n objects.some((o) =>\n (o.type === 'row'\n && (wanted.has(o.categoryKey)\n || (o.overrides ?? []).some((ov) => ov.categoryKey != null && wanted.has(ov.categoryKey))))\n || (o.type === 'gaArea' && wanted.has(o.categoryKey)),\n );\n const activeId = this.getActiveFloorId();\n const active = doc.floors.find((f) => f.id === activeId);\n if (active && carries(active.objects)) return null;\n return doc.floors.find((f) => carries(f.objects))?.id ?? null;\n }\n\n /** World-space rect currently visible + full chart bounds (F3 minimap frame). */\n getViewport(): { visible: { x: number; y: number; width: number; height: number }; bounds: { x: number; y: number; width: number; height: number } } | null {\n const r = this.renderer;\n if (!r?.getVisibleWorldRect || !r.getWorldBounds) return null;\n return { visible: r.getVisibleWorldRect(), bounds: r.getWorldBounds() };\n }\n /** Glide in on a section and surface its summary (same path as a section tap). */\n focusSection(id: string): void {\n this.handleSectionTap(id);\n }\n /** Zoom back out to the whole chart and clear the section-summary card + focus. */\n overview(): void {\n this.renderer?.clearSectionFocus?.();\n this.renderer?.zoomToFit();\n this.opts.onSectionFocus?.(null);\n }\n\n /** Glide the camera into a tapped section and emit its computed summary. Uses\n * the AXS focus treatment (dim + backdrop) when the engine supports it; a\n * closed section is framed but never opens a buyer card. */\n private handleSectionTap(id: string): void {\n const r = this.renderer;\n if (!r) return;\n if (r.focusSection) r.focusSection(id);\n else r.focusRegion?.(id);\n if (this.isSectionClosed(id)) {\n this.opts.onSectionFocus?.(null); // closed: no purchase card\n return;\n }\n this.opts.onSectionFocus?.(this.sectionSummary(id));\n }\n\n /**\n * Build a section summary from the renderer's spatial membership: section +\n * zone labels, live seats-left, price range, and the per-category breakdown.\n */\n private sectionSummary(id: string): SectionSummary | null {\n const r = this.renderer;\n const doc = this._doc;\n if (!r || !doc) return null;\n const sec = doc.objects.find(\n (o): o is SectionObject => o.type === 'section' && o.id === id,\n );\n if (!sec) return null;\n\n const memberIds = r.sectionMembers?.(id) ?? [];\n const byCat = new Map<string, number>();\n let seatsLeft = 0;\n for (const sid of memberIds) {\n const seat = this.seatById.get(sid);\n if (!seat) continue;\n byCat.set(seat.categoryKey, (byCat.get(seat.categoryKey) ?? 0) + 1);\n if (r.getStatus(sid) === 'free') seatsLeft++;\n }\n\n const categories: SectionCategory[] = [...byCat.entries()]\n .map(([key, count]) => {\n const cat = doc.categories.find((c) => c.key === key);\n return {\n key,\n count,\n label: cat?.label ?? key,\n color: cat?.color ?? '#6e7bff',\n price: cat?.price ?? 0,\n };\n })\n .sort((a, b) => a.price - b.price);\n\n const prices = categories.map((c) => c.price);\n const zone = sec.zone ? doc.zones?.find((z) => z.id === sec.zone) : undefined;\n const color = sec.color ?? zone?.color ?? categories[0]?.color ?? '#6e7bff';\n\n return {\n id,\n label: sec.label,\n zoneLabel: zone?.label ?? '',\n color,\n seatsLeft,\n priceMin: prices.length ? prices[0] : 0,\n priceMax: prices.length ? prices[prices.length - 1] : 0,\n categories,\n };\n }\n\n destroy(): void {\n this.closed = true;\n this.detachVisibilityListener();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.expiryTimer) {\n clearTimeout(this.expiryTimer);\n this.expiryTimer = null;\n }\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n /* ignore */\n }\n this.ws = null;\n }\n this.renderer?.destroy();\n this.renderer = null;\n }\n\n // ---- internals ------------------------------------------------------------\n\n private toSeat(s: ExpandedSeat): PickerSeat {\n const commercial = s.commercial ? { commercial: s.commercial } : undefined;\n const tiers = this.tiersFor(s.categoryKey);\n if (!tiers) {\n return { id: s.id, label: s.label, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), ...commercial };\n }\n const chosen = tiers.find((t) => t.id === this.seatTiers.get(s.id)) ?? tiers[0];\n return {\n id: s.id,\n label: s.label,\n categoryKey: s.categoryKey,\n price: chosen.price,\n tiers,\n tierId: chosen.id,\n ...commercial,\n };\n }\n /** Tooltip payload for a hovered seat — see PickerCallbacks.onSeatHover. */\n private describeSeat(s: ExpandedSeat): SeatHoverDetails {\n const cat = this._doc?.categories.find((c) => c.key === s.categoryKey);\n return {\n ...this.toSeat(s),\n categoryLabel: cat?.label ?? s.categoryKey,\n categoryColor: cat?.color ?? '#6e7bff',\n status: this.renderer?.getStatus(s.id) ?? 'free',\n currency: this.currency,\n ...this.seatContext.get(s.id),\n };\n }\n\n private priceFor(categoryKey: string): number {\n return this._doc?.categories.find((c) => c.key === categoryKey)?.price ?? 0;\n }\n private tiersFor(categoryKey: string): CategoryTier[] | undefined {\n const t = this._doc?.categories.find((c) => c.key === categoryKey)?.tiers;\n return t && t.length ? t : undefined;\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). Re-emits the\n * selection so the host's cart + the eventual hold carry the new tier + price.\n * `tierId = null` reverts to the category's first (default) tier. No-op if the\n * seat's category has no tiers or the id isn't one of them.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n const seat = this.seatById.get(seatId);\n if (!seat) return;\n const tiers = this.tiersFor(seat.categoryKey);\n if (!tiers) return;\n if (tierId == null) this.seatTiers.delete(seatId);\n else if (tiers.some((t) => t.id === tierId)) this.seatTiers.set(seatId, tierId);\n else return;\n this.emitSelectionChange();\n if (this.hold_) this.hold_ = { ...this.hold_, seats: this.seatsForLabels(this.hold_.labels) };\n }\n\n /** PickerSeats (with chosen tier) for a set of held labels. */\n private seatsForLabels(labels: string[]): PickerSeat[] {\n const out: PickerSeat[] = [];\n for (const l of labels) {\n const s = this.labelToSeat.get(l);\n if (s) out.push(this.toSeat(s));\n }\n return out;\n }\n private emitSelectionChange(): void {\n this.opts.onSelectionChange?.(this.getSelection());\n this.emitOrphanHint();\n }\n\n /** Whether the last emitted hint was non-null (avoids clearing repeatedly). */\n private hintShown = false;\n\n /**\n * Orphan-seat advice on manual selection: when the buyer's current picks\n * strand one (or more) single free seats between unavailable same-row\n * neighbors, surface a localized, non-blocking hint. Cleared (null) as soon\n * as the selection stops stranding anyone.\n */\n private emitOrphanHint(): void {\n if (!this.opts.onHint) return;\n const r = this.renderer;\n if (!r) return;\n const selected = new Set(r.getSelection().map((s) => s.id));\n const stranded = selected.size\n ? strandedSingles(this.seatById.values(), (id) => r.getStatus(id), selected)\n : [];\n if (stranded.length > 0) {\n this.hintShown = true;\n this.opts.onHint(t('picker.orphanHint'));\n } else if (this.hintShown) {\n this.hintShown = false;\n this.opts.onHint(null);\n }\n }\n\n /** Toggle colorblind-safe rendering at runtime (see PickerOptions.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.renderer?.setColorblindSafe?.(on);\n }\n private emitError(err: unknown): void {\n if (this.opts.onError) this.opts.onError(err);\n else console.error('[picker]', err);\n }\n\n private holdCovers(labels: string[]): boolean {\n const h = this.hold_;\n if (!h || h.labels.length !== labels.length || !labels.every((l) => h.labels.includes(l))) return false;\n const tiers = new Map((h.items ?? []).map((item) => [item.label, item.tierId]));\n return labels.every((label) => {\n const seat = this.labelToSeat.get(label);\n const currentTier = seat ? this.toSeat(seat).tierId ?? null : null;\n return !tiers.has(label) || tiers.get(label) === currentTier;\n });\n }\n\n private handle409Conflicts(err: unknown): void {\n const { status, conflicts } = errInfo(err);\n if (status !== 409 || !conflicts?.length) return;\n const r = this.renderer;\n if (!r) return;\n const takenIds = conflicts.map((c) => this.labelToId.get(c.label)).filter((v): v is string => !!v);\n if (takenIds.length) {\n r.deselect(takenIds);\n r.setStatus(takenIds, 'held');\n }\n this.emitSelectionChange();\n }\n\n /** Set the open hold + (re)arm the server-authoritative expiry timer. */\n private setHold(\n hold: Omit<HoldInfo, 'seats'> & { seats?: PickerSeat[] },\n source: 'created' | 'restored' = 'created',\n ): void {\n // Always resolve seats (with chosen tier) from the held labels so the host's\n // onHold — and any later book — carries the tier the buyer picked per seat.\n const full: HoldInfo = { ...hold, seats: this.seatsForLabels(hold.labels) };\n this.hold_ = full;\n this.renderer?.setOwnedHold?.(\n full.labels.map((label) => this.labelToId.get(label)).filter((id): id is string => !!id),\n );\n if (this.expiryTimer) clearTimeout(this.expiryTimer);\n const ms = Math.max(0, full.expiresAt - Date.now());\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), ms);\n if (source === 'restored') this.opts.onHoldRestored?.(full);\n else this.opts.onHold?.(full);\n }\n private clearHold(): void {\n this.hold_ = null;\n this.renderer?.setOwnedHold?.(null);\n if (this.expiryTimer) {\n clearTimeout(this.expiryTimer);\n this.expiryTimer = null;\n }\n }\n private async expireActiveHold(): Promise<void> {\n const hold = this.hold_;\n if (!hold) return;\n try {\n const snap = await this.api.objects(this.key);\n if (this.hold_?.holdId !== hold.holdId) return;\n this.applySeatsMap(snap.seats);\n } catch {\n // Do not report expiry from a disconnected/stale client. Reconcile once\n // the authoritative snapshot becomes reachable.\n if (this.hold_?.holdId === hold.holdId) {\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 2_000);\n }\n return;\n }\n if (this.hold_?.holdId !== hold.holdId) return; // booked snapshot cleared it\n if (hold.labels.some((label) => this.liveStatuses.get(label) === 'held')) {\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 1_000);\n return;\n }\n this.clearHold();\n this.opts.onHoldExpired?.();\n }\n\n private applySeatsMap(seats: Record<string, string>): void {\n const r = this.renderer;\n if (!r) return;\n this.liveStatuses = new Map(Object.entries(seats));\n if (this.allIds.length) r.setStatus(this.allIds, 'free');\n // setChart() rebuilds renderer state (floor/hidden-section changes), so\n // restore the buyer-ownership layer before repainting held statuses.\n r.setOwnedHold?.(\n (this.hold_?.labels ?? [])\n .map((label) => this.labelToId.get(label))\n .filter((id): id is string => !!id),\n );\n const byStatus: Record<SeatStatus, string[]> = { free: [], held: [], booked: [], not_for_sale: [] };\n for (const [label, st] of Object.entries(seats)) {\n const id = this.labelToId.get(label);\n if (id) byStatus[mapStatus(st)].push(id);\n }\n (['held', 'booked', 'not_for_sale'] as SeatStatus[]).forEach((st) => {\n if (byStatus[st].length) r.setStatus(byStatus[st], st);\n });\n this.opts.onStatusChange?.();\n this.clearBookedHoldIfSettled();\n }\n\n private clearBookedHoldIfSettled(): void {\n if (this.hold_?.labels.every((label) => this.liveStatuses.get(label) === 'booked')) this.clearHold();\n }\n\n private async resnapshot(): Promise<void> {\n try {\n const objs = await this.api.objects(this.key);\n this.applySeatsMap(objs.seats);\n } catch {\n /* transient — the socket delta stream keeps us fresh */\n }\n }\n\n /**\n * Re-pull the status snapshot on demand. Live surfaces rarely need this (the\n * socket keeps them fresh); local/mock transports with no socket call it\n * after they mutate state (e.g. the demo books a hold) so the renderer and\n * every onStatusChange consumer repaint from the new truth.\n */\n async refresh(): Promise<void> {\n await this.resnapshot();\n }\n\n // ---- realtime socket ------------------------------------------------------\n\n /**\n * Buyer catch-up on tab regain. While a tab is hidden Chrome pauses rAF, so\n * seat-status deltas that arrived over the WS mutated the scene graph but the\n * canvas colors never repainted. When the tab becomes visible again we (1)\n * resnapshot to pull authoritative state for anything the socket may have\n * missed while backgrounded, then (2) forceDraw() a synchronous repaint so the\n * seat colors are correct immediately rather than on the next incidental draw.\n *\n * Attached once per mount; guarded against double-attach and non-DOM\n * environments; detached in destroy() (no leaks).\n */\n private attachVisibilityListener(): void {\n if (this.onVisibilityChange) return; // already attached (guard double mount)\n if (typeof document === 'undefined' || typeof document.addEventListener !== 'function') return;\n const handler = (): void => {\n if (this.closed) return;\n if (document.visibilityState !== 'visible') return;\n // Re-fetch authoritative state, then paint it synchronously.\n void this.resnapshot().then(() => {\n if (!this.closed) this.renderer?.forceDraw();\n });\n };\n this.onVisibilityChange = handler;\n document.addEventListener('visibilitychange', handler);\n }\n\n private detachVisibilityListener(): void {\n if (!this.onVisibilityChange) return;\n if (typeof document !== 'undefined' && typeof document.removeEventListener === 'function') {\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\n }\n this.onVisibilityChange = null;\n }\n\n private connect(): void {\n if (this.closed) return;\n // A transport may be fully local (demo/mock) — an empty socketUrl means\n // \"no live feed\"; skip the connection instead of retrying forever.\n const url = this.api.socketUrl(this.key);\n if (!url) return;\n let ws: WebSocket;\n try {\n ws = new WebSocket(url);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n this.attempt = 0;\n void this.resnapshot();\n };\n ws.onmessage = (e) => {\n let msg: unknown;\n try {\n msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n } catch {\n return;\n }\n const r = this.renderer;\n if (!r || !msg || typeof msg !== 'object') return;\n const m = msg as { type?: string; hidden?: string[]; closed?: string[]; seats?: Record<string, string>; changes?: { label: string; status: string }[] };\n // Reconcile hidden sections whenever they arrive (dedicated 'hidden' message\n // OR a snapshot that carries them). Only rebuilds the chart when it changed.\n if (Array.isArray(m.hidden) && this.syncHidden(m.hidden)) {\n void this.resnapshot(); // repaint statuses onto the rebuilt chart\n this.opts.onStatusChange?.();\n }\n // Reconcile closed sections (Phase 2). Cheap grey restyle, no chart rebuild —\n // so flipping a section open/closed mid-sale repaints for connected buyers.\n if (Array.isArray(m.closed) && this.syncClosed(m.closed)) {\n this.opts.onStatusChange?.();\n }\n if (m.type === 'hidden') return; // dedicated hidden message carries no seats\n if (m.seats && typeof m.seats === 'object') {\n this.applySeatsMap(m.seats);\n } else if (Array.isArray(m.changes)) {\n for (const ch of m.changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const id = this.labelToId.get(ch.label);\n if (!id) continue;\n const next = mapStatus(ch.status);\n // Flash a live free→taken change — but not the buyer's OWN just-held\n // seats (a manual hold leaves them 'free' locally, so the server's\n // held-delta would otherwise flash them as if someone else grabbed them).\n if (\n this.opts.flashOnLiveChange &&\n next !== 'free' &&\n r.getStatus(id) === 'free' &&\n !this.hold_?.labels.includes(ch.label)\n ) {\n // Pulse color mirrors the manager board's status language:\n // amber for a hold landing, red for a booking.\n r.flashSeat(id, next === 'held' ? '#f4b740' : '#f43f5e');\n }\n r.setStatus([id], next);\n }\n // Stay-live-while-hidden (opt-in, default OFF). setStatus paints via\n // batchDraw (rAF), which Chrome pauses on a hidden tab — so an always-on\n // board (the future organizer control room) would freeze while\n // backgrounded. When enabled, force a synchronous repaint so a hidden\n // board keeps painting. The buyer widget leaves this off and relies on\n // the visibilitychange catch-up instead.\n if (\n this.opts.keepLiveWhileHidden &&\n typeof document !== 'undefined' &&\n document.visibilityState === 'hidden'\n ) {\n r.forceDraw();\n }\n this.clearBookedHoldIfSettled();\n this.opts.onStatusChange?.();\n }\n };\n ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.scheduleReconnect();\n };\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives reconnect */\n }\n };\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n}\n","/**\n * Synthetic view-from-seat panorama, generated from chart geometry alone.\n *\n * Draws a 2048×1024 equirectangular texture of a dark hall with the stage\n * placed at the correct bearing and angular size for THIS seat — closer seats\n * see a bigger stage, off-center seats see it at an angle. Used whenever the\n * organizer hasn't uploaded a real photo/360 for the seat; both go through the\n * same viewer.\n *\n * Equirectangular mapping: x = (yaw + 180°)/360° · W, y = (90° − pitch)/180° · H,\n * where yaw 0 = the direction the camera faces by default.\n */\n\nimport type { ExpandedSeat, Point } from '../core/types';\n\nconst W = 2048;\nconst H = 1024;\n/** Chart units → meters, for plausible eye-level proportions (seatSpacing 24 ≈ 0.55m). */\nconst UNIT = 0.55 / 24;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\nexport interface PanoramaResult {\n url: string;\n /** Meters from the stage, for the caption. */\n distanceM: number;\n}\n\nexport function generateSeatPanorama(\n seat: ExpandedSeat,\n focalPoint: Point,\n neighborSeats: ExpandedSeat[],\n): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distU = Math.hypot(dx, dy);\n const distM = Math.max(2, distU * UNIT);\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.42, '#11172a');\n sky.addColorStop(0.5, '#1a2238');\n sky.addColorStop(0.56, '#10141f');\n sky.addColorStop(1, '#07090f');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // ---- stage, centered at yaw 0 (the viewer opens facing it) -------------\n // Angular size from real proportions: stage ~8m wide, ~1m platform + 6m set.\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(45, (Math.atan2(5, distM) * 180) / Math.PI);\n const stageBasePitch = Math.max(-30, (-Math.atan2(1.1, distM) * 180) / Math.PI);\n\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n\n // glow behind the stage\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 10, W / 2, (sy0 + sy1) / 2, (sx1 - sx0) * 1.1);\n glow.addColorStop(0, 'rgba(129, 140, 248, 0.5)');\n glow.addColorStop(0.5, 'rgba(99, 102, 241, 0.16)');\n glow.addColorStop(1, 'rgba(99, 102, 241, 0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - (sx1 - sx0) * 0.6, sy0 - (sy1 - sy0) * 1.2, (sx1 - sx0) * 2.2, (sy1 - sy0) * 3.4);\n\n // stage box + lit backdrop\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.75;\n ctx.fillStyle = backdrop;\n const inset = (sx1 - sx0) * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + (sy1 - sy0) * 0.12, sx1 - sx0 - inset * 2, (sy1 - sy0) * 0.62);\n ctx.globalAlpha = 1;\n // stage lip\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - (sy1 - sy0) * 0.1, sx1 - sx0, (sy1 - sy0) * 0.1);\n\n // performer silhouettes, scaled by distance\n const performerH = (sy1 - sy0) * 0.45;\n ctx.fillStyle = 'rgba(8, 10, 16, 0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + (sx1 - sx0) * fx;\n const py = sy1 - (sy1 - sy0) * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - performerH * 0.82, performerH * 0.16, 0, Math.PI * 2); // head\n ctx.fill();\n ctx.fillRect(px - performerH * 0.14, py - performerH * 0.68, performerH * 0.28, performerH * 0.68); // body\n }\n\n // spotlight beams from above the stage\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + (sx1 - sx0) * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.lineTo(bx - (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // ---- rig lights along the ceiling all around ---------------------------\n ctx.fillStyle = 'rgba(199, 210, 254, 0.8)';\n for (let i = 0; i < 26; i++) {\n const x = (i / 26) * W;\n const y = pitchToY(55 + (i % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, 3.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // ---- audience: heads of nearby seats, at their true bearings -----------\n // Bearing relative to the stage direction so yaw 0 keeps facing the stage.\n const stageBearing = Math.atan2(dx, -dy); // screen coords, -y is \"up\" the hall\n ctx.fillStyle = 'rgba(16, 20, 30, 0.95)';\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const d = Math.hypot(ox, oy) * UNIT;\n if (d < 0.3 || d > 14) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const headPitch = (-Math.atan2(0.35, d) * 180) / Math.PI; // heads slightly below eye level\n const headR = Math.min(46, 260 / (d / UNIT / 24 + 1.2) / 4);\n const hx = yawToX(yaw);\n const hy = pitchToY(headPitch);\n ctx.beginPath();\n ctx.arc(hx, hy, headR, 0, Math.PI * 2);\n ctx.fill();\n ctx.beginPath(); // shoulders\n ctx.ellipse(hx, hy + headR * 1.4, headR * 1.7, headR * 0.9, 0, Math.PI, 0, true);\n ctx.fill();\n }\n\n // subtle vignette at the poles (hides equirect pinching)\n const poleFade = ctx.createLinearGradient(0, 0, 0, H);\n poleFade.addColorStop(0, 'rgba(0,0,0,0.85)');\n poleFade.addColorStop(0.12, 'rgba(0,0,0,0)');\n poleFade.addColorStop(0.88, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.85)');\n ctx.fillStyle = poleFade;\n ctx.fillRect(0, 0, W, H);\n\n return { url: canvas.toDataURL('image/jpeg', 0.82), distanceM: Math.round(distM) };\n}\n\n// ---------------------------------------------------------------------------\n// Compact forward-view thumbnail — a cheap (480×270) rectilinear preview of\n// what this seat faces, for inline display inside the buyer's confirm card.\n// Unlike the full equirectangular panorama it maps a ~100°×60° forward field\n// of view directly (no 360 squish), so it reads as a real POV at a glance and\n// costs a fraction of the full render. Same geometry → the two stay consistent.\n// ---------------------------------------------------------------------------\n\nconst TW = 480;\nconst TH = 270;\nconst HALF_HFOV = 50; // degrees left/right of the stage direction\nconst HALF_VFOV = 30; // degrees up/down of the horizon\n\nconst yawToTX = (yawDeg: number) => ((yawDeg + HALF_HFOV) / (2 * HALF_HFOV)) * TW;\nconst pitchToTY = (pitchDeg: number) => ((HALF_VFOV - pitchDeg) / (2 * HALF_VFOV)) * TH;\n\nexport function generateSeatThumb(seat: ExpandedSeat, focalPoint: Point, _neighborSeats?: ExpandedSeat[]): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = TW;\n canvas.height = TH;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distM = Math.max(2, Math.hypot(dx, dy) * UNIT);\n\n // hall shell (ceiling → wall → floor), horizon at mid-height\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.44, '#141b30');\n sky.addColorStop(0.5, '#1b2440');\n sky.addColorStop(0.58, '#10141f');\n sky.addColorStop(1, '#070910');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n // stage geometry (identical formulas to the full panorama)\n const stageHalfYaw = Math.min(HALF_HFOV - 2, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(HALF_VFOV - 2, (Math.atan2(5, distM) * 180) / Math.PI);\n const stageBasePitch = Math.max(-HALF_VFOV + 2, (-Math.atan2(1.1, distM) * 180) / Math.PI);\n const sx0 = yawToTX(-stageHalfYaw);\n const sx1 = yawToTX(stageHalfYaw);\n const sy0 = pitchToTY(stageTopPitch);\n const sy1 = pitchToTY(stageBasePitch);\n const sw = sx1 - sx0;\n const sh = sy1 - sy0;\n\n // glow\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.1);\n glow.addColorStop(0, 'rgba(129,140,248,0.5)');\n glow.addColorStop(0.5, 'rgba(99,102,241,0.15)');\n glow.addColorStop(1, 'rgba(99,102,241,0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - sw * 0.6, sy0 - sh * 1.2, sw * 2.2, sh * 3.4);\n\n // stage box + lit backdrop + lip\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sw, sh);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.78;\n ctx.fillStyle = backdrop;\n const inset = sw * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + sh * 0.12, sw - inset * 2, sh * 0.62);\n ctx.globalAlpha = 1;\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - sh * 0.1, sw, sh * 0.1);\n\n // performer silhouettes\n const ph = sh * 0.45;\n ctx.fillStyle = 'rgba(8,10,16,0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + sw * fx;\n const py = sy1 - sh * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - ph * 0.82, ph * 0.16, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillRect(px - ph * 0.14, py - ph * 0.68, ph * 0.28, ph * 0.68);\n }\n\n // spotlight beams\n ctx.globalAlpha = 0.15;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + sw * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.lineTo(bx - sw * 0.09, sy1);\n ctx.lineTo(bx + sw * 0.09, sy1);\n ctx.lineTo(bx + 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // a few rig lights across the ceiling\n ctx.fillStyle = 'rgba(199,210,254,0.75)';\n for (let i = 0; i < 8; i++) {\n ctx.beginPath();\n ctx.arc(((i + 0.5) / 8) * TW, pitchToTY(HALF_VFOV - 4 - (i % 2) * 3), 2.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // seat-back rows in the foreground for depth\n ctx.fillStyle = 'rgba(10,13,20,0.9)';\n ctx.fillRect(0, TH - 26, TW, 26);\n ctx.fillStyle = 'rgba(30,37,54,0.9)';\n for (let i = 0; i < 9; i++) ctx.fillRect(i * (TW / 9) + 6, TH - 22, TW / 9 - 12, 14);\n\n return { url: canvas.toDataURL('image/jpeg', 0.8), distanceM: Math.round(distM) };\n}\n","/**\n * Locale bundle loader — keeps non-English translations OUT of the initial\n * bundle (the 150 KB complete CDN budget is a product contract) and code-splits each\n * locale so a page/SDK only downloads the language it actually uses.\n *\n * `loadLocale('de')` dynamic-imports the German dictionary, registers it via\n * setLocale(), and resolves once it's active. English is built in, so\n * `loadLocale('en')` is synchronous and never fetches. Unknown/unsupported\n * codes fall back to English without throwing.\n */\nimport { setLocale, resolveLocale, type Dict, type Locale } from './index';\n\n/** Dynamic importers per non-English locale (English ships in the core). */\nconst LOADERS: Record<Exclude<Locale, 'en'>, () => Promise<{ default: Dict }>> = {\n es: () => import('./locales/es').then((m) => ({ default: m.es })),\n de: () => import('./locales/de').then((m) => ({ default: m.de })),\n fr: () => import('./locales/fr').then((m) => ({ default: m.fr })),\n};\n\nconst loaded = new Set<Locale>(['en']);\n\n/**\n * Resolve `code` to a supported locale, load its bundle if needed, and make it\n * active. Returns the locale that ended up active (English on any failure).\n */\nexport async function loadLocale(code?: string | null): Promise<Locale> {\n const locale = resolveLocale(code);\n if (locale === 'en' || loaded.has(locale)) {\n setLocale(locale);\n return locale;\n }\n try {\n const mod = await LOADERS[locale]();\n setLocale(locale, mod.default);\n loaded.add(locale);\n return locale;\n } catch {\n setLocale('en');\n return 'en';\n }\n}\n"],"mappings":"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","names":["t","t","objects","t","rgb","KImage","active","t"]}
|