@seatlayer/core 0.45.0 → 0.47.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.
Files changed (40) hide show
  1. package/dist/chunk-AZODENEL.js +97 -0
  2. package/dist/chunk-AZODENEL.js.map +1 -0
  3. package/dist/chunk-FVCOOLJO.js +335 -0
  4. package/dist/chunk-FVCOOLJO.js.map +1 -0
  5. package/dist/{chunk-5MRJCIZP.js → chunk-TCTAS4Z2.js} +88 -14
  6. package/dist/chunk-TCTAS4Z2.js.map +1 -0
  7. package/dist/{de-UHAOVDS3.js → de-ST4H423D.js} +6 -3
  8. package/dist/{de-UHAOVDS3.js.map → de-ST4H423D.js.map} +1 -1
  9. package/dist/{es-6TJS2L7S.js → es-WEC5NHRT.js} +6 -3
  10. package/dist/{es-6TJS2L7S.js.map → es-WEC5NHRT.js.map} +1 -1
  11. package/dist/{fr-MMSY7FPE.js → fr-SGBFNAQV.js} +6 -3
  12. package/dist/{fr-MMSY7FPE.js.map → fr-SGBFNAQV.js.map} +1 -1
  13. package/dist/index.cjs +251 -39
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +119 -4
  16. package/dist/index.d.ts +119 -4
  17. package/dist/index.js +152 -24
  18. package/dist/index.js.map +1 -1
  19. package/dist/{types-DBnRO2hX.d.cts → types-CE63BK0j.d.cts} +88 -10
  20. package/dist/{types-DBnRO2hX.d.ts → types-CE63BK0j.d.ts} +88 -10
  21. package/dist/view/panoramaDelivery.cjs +126 -0
  22. package/dist/view/panoramaDelivery.cjs.map +1 -0
  23. package/dist/view/panoramaDelivery.d.cts +34 -0
  24. package/dist/view/panoramaDelivery.d.ts +34 -0
  25. package/dist/view/panoramaDelivery.js +17 -0
  26. package/dist/view/panoramaDelivery.js.map +1 -0
  27. package/dist/view3d/crossfade/panorama.cjs +453 -0
  28. package/dist/view3d/crossfade/panorama.cjs.map +1 -0
  29. package/dist/view3d/crossfade/panorama.d.cts +110 -0
  30. package/dist/view3d/crossfade/panorama.d.ts +110 -0
  31. package/dist/view3d/crossfade/panorama.js +30 -0
  32. package/dist/view3d/crossfade/panorama.js.map +1 -0
  33. package/dist/view3d/index.cjs +1161 -128
  34. package/dist/view3d/index.cjs.map +1 -1
  35. package/dist/view3d/index.d.cts +60 -35
  36. package/dist/view3d/index.d.ts +60 -35
  37. package/dist/view3d/index.js +945 -300
  38. package/dist/view3d/index.js.map +1 -1
  39. package/package.json +28 -1
  40. package/dist/chunk-5MRJCIZP.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/ga.ts","../src/core/sections.ts","../src/core/chartRenderRules.ts","../src/core/renderedQuality.ts","../src/engine/SeatmapRenderer.ts","../src/core/chartBackgrounds.ts","../src/core/icons.ts","../src/core/spatialIndex.ts","../src/core/perspectiveProjection.ts","../src/lib/money.ts","../src/i18n/locales/en.ts","../src/i18n/index.ts","../src/core/shapeLineStyle.ts","../src/core/orphans.ts","../src/core/bestAvailable.ts","../src/core/tableInventory.ts","../src/picker/PickerController.ts","../src/view/sightline.ts","../src/view/generatePanorama.ts","../src/i18n/bundles.ts"],"sourcesContent":["import type { ChartDoc, GAAreaObject, GAInventorySegment } 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\n/** Strict, bounded validation for durable Join Areas inventory provenance. */\nexport function validGAInventorySegments(area: GAAreaObject): boolean {\n const segments = area.inventorySegments;\n if (segments === undefined) return true;\n if (!Array.isArray(segments) || segments.length < 1 || segments.length > 256) return false;\n let total = 0;\n const ranges = new Map<string, Array<{ start: number; end: number }>>();\n for (const segment of segments) {\n if (!segment || typeof segment.sourceAreaId !== 'string'\n || !segment.sourceAreaId.trim() || segment.sourceAreaId.length > 160\n || !Number.isInteger(segment.startIndex) || segment.startIndex < 0\n || !Number.isInteger(segment.count) || segment.count < 1\n || segment.startIndex + segment.count > MAX_GA_CAPACITY) return false;\n total += segment.count;\n if (total > MAX_GA_CAPACITY) return false;\n const sourceRanges = ranges.get(segment.sourceAreaId) ?? [];\n const end = segment.startIndex + segment.count;\n if (sourceRanges.some((range) => segment.startIndex < range.end && end > range.start)) return false;\n sourceRanges.push({ start: segment.startIndex, end });\n ranges.set(segment.sourceAreaId, sourceRanges);\n }\n return total === area.capacity;\n}\n\n/** Canonical source ranges. Invalid explicit provenance intentionally yields no\n * labels: chart validation blocks publication instead of inventing identities. */\nexport function gaInventorySegments(area: GAAreaObject): GAInventorySegment[] {\n const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));\n if (area.inventorySegments === undefined) {\n return capacity ? [{ sourceAreaId: area.id, startIndex: 0, count: capacity }] : [];\n }\n if (!validGAInventorySegments(area)) return [];\n return area.inventorySegments.map((segment) => ({ ...segment }));\n}\n\nexport function gaUnitLabels(area: GAAreaObject): string[] {\n return gaInventorySegments(area).flatMap((segment) => Array.from(\n { length: segment.count },\n (_, offset) => gaUnitLabel(segment.sourceAreaId, segment.startIndex + offset),\n ));\n}\n\n/** Append-only capacity semantics for an already joined GA surface. */\nexport function growJoinedGAInventory(area: GAAreaObject, nextCapacity: number): GAInventorySegment[] | undefined {\n if (area.inventorySegments === undefined || nextCapacity === area.capacity) return area.inventorySegments;\n if (nextCapacity < area.capacity) return undefined;\n const segments = gaInventorySegments(area);\n if (!segments.length) return undefined;\n const extra = nextCapacity - area.capacity;\n if (!extra) return segments;\n const ownRanges = segments.filter((segment) => segment.sourceAreaId === area.id);\n const startIndex = ownRanges.reduce((max, segment) => Math.max(max, segment.startIndex + segment.count), 0);\n const last = segments[segments.length - 1];\n if (last?.sourceAreaId === area.id && last.startIndex + last.count === startIndex) {\n last.count += extra;\n } else {\n if (segments.length >= 256) return undefined;\n segments.push({ sourceAreaId: area.id, startIndex, count: extra });\n }\n return segments;\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, owningSectionForObject } from './layout';\nimport { gaUnitLabels } from './ga';\n\n/**\n * The section 3D-geometry resolver + tier fallback constant now live in the leaf\n * `units.ts` module (so `layout.ts` can consume them without an import cycle).\n * Re-exported here to keep the historical `from './sections'` import path working.\n */\nexport { sectionGeometry, TIER_HEIGHT_M } from './units';\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\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 const owner = owningSectionForObject(objs, obj);\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 * 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\nimport type { AccessibilityType } from './types';\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/** Square viewBox every accessibility glyph path's coordinates live in. */\nexport const ACCESS_GLYPH_VIEWBOX = 24;\n\n/**\n * Per-accommodation pictograms drawn centred on accessible seats. Each is a\n * SOLID filled silhouette in the 0 0 24 24 viewBox, designed to stay legible at\n * the ~13px it renders on a seat dot (bold shapes, no thin strokes). A vector\n * path renders crisply at small sizes on every platform, unlike a colour emoji\n * whose canvas metrics/alignment are inconsistent cross-browser.\n *\n * The owner directive (OV-89): every accessibility type must render ITS OWN\n * meaningful glyph so a buyer *sees* what the seat provides — the coloured ring\n * still encodes the type by colour, but the on-seat icon now matches the\n * filter's meaning instead of every non-wheelchair type showing a bare ring.\n *\n * Every path below is numerically validated (bbox centred within 12±1.5, longer\n * axis spans 14–22 units) — see scratchpad/validate-glyphs.mjs in the authoring\n * session. Keep any edit passing that check.\n */\nexport const ACCESS_TYPE_GLYPH_PATHS: Record<AccessibilityType, string> = {\n // ISO-style wheelchair: seated figure (head + L-shaped body) over a ring wheel.\n wheelchair:\n 'M7.8 4.5a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0z'\n + 'M8 7L10.5 7L10.5 15L8 15Z'\n + 'M8 12.5L18 12.5L18 15L8 15Z'\n + 'M16 15L18 15L18 18L16 18Z'\n + 'M5.5 16a5.5 5.5 0 1 0 11 0a5.5 5.5 0 1 0 -11 0z'\n + 'M8 16a3 3 0 1 1 6 0a3 3 0 1 1 -6 0z',\n // Companion: two overlapping head-and-shoulders figures (seat + a guest).\n companion:\n 'M5.5 6.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0z'\n + 'M4.5 18.5L6 11.5L11 11.5L12.5 18.5Z'\n + 'M12.5 7.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0z'\n + 'M11.5 19L13 12.5L18 12.5L19.5 19Z',\n // Semi-ambulatory: walking figure leaning on a cane at its right side.\n 'semi-ambulatory':\n 'M8.3 3.8a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0z'\n + 'M9 6.2L12 6.6L11 13.5L8.6 13L9 6.2Z'\n + 'M8.6 13L11 13L9.5 21L7 21Z'\n + 'M10.4 13L12.6 13L13.6 21L11.2 21Z'\n + 'M11.2 7.2L14 8L14.6 9.6L11.9 8.9Z'\n + 'M14.4 6.8L15.9 6.8L16.4 21L14.8 21Z',\n // Hearing: a bold ear silhouette (assistive listening).\n hearing:\n 'M15.5 3.5'\n + 'C9 2.2 5.5 6 5.5 11.5'\n + 'C5.5 16 8 19.5 10.5 21'\n + 'C13.2 22.6 16.4 20.8 15.4 18'\n + 'C14.8 16.4 12.9 16.1 13 14'\n + 'C13.1 11.9 15.8 11.4 15.8 8.5'\n + 'C15.8 5.4 13 4 15.5 3.5Z',\n // CART captions: a rounded caption bubble with two bold caption bars cut out.\n cart:\n 'M5.5 6L18.5 6a2.5 2.5 0 0 1 2.5 2.5L21 15.5a2.5 2.5 0 0 1 -2.5 2.5L11 18L7 20.5L7.5 18L5.5 18a2.5 2.5 0 0 1 -2.5 -2.5L3 8.5a2.5 2.5 0 0 1 2.5 -2.5z'\n + 'M6.5 11L17.5 11L17.5 12.6L6.5 12.6z'\n + 'M6.5 14L17.5 14L17.5 15.6L6.5 15.6z',\n // Sign language: a raised open hand (palm with four fingers and a thumb).\n 'sign-language':\n 'M7 11L17 11L17 18a2 2 0 0 1 -2 2L9 20a2 2 0 0 1 -2 -2z'\n + 'M7.6 5L9.4 5L9.4 12L7.6 12z'\n + 'M9.9 3.5L11.7 3.5L11.7 12L9.9 12z'\n + 'M12.3 3.5L14.1 3.5L14.1 12L12.3 12z'\n + 'M14.6 5L16.4 5L16.4 12L14.6 12z'\n + 'M7.2 12.5L5 10.2L6.4 8.9L8.6 11.2Z',\n // Plus-size: a broad-shouldered wide figure.\n 'plus-size':\n 'M9.4 4.3a2.6 2.6 0 1 0 5.2 0a2.6 2.6 0 1 0 -5.2 0z'\n + 'M5 20L4 13C4 10.5 7 9.5 12 9.5C17 9.5 20 10.5 20 13L19 20Z',\n // Lift-up armrest: a chair side-profile with an up arrow over the armrest.\n 'lift-armrest':\n 'M5 6L8 6L8 19L5 19z'\n + 'M5 16L18 16L18 19L5 19z'\n + 'M8 12L17 12L17 14.5L8 14.5z'\n + 'M14 7L16 7L16 12L14 12z'\n + 'M12 7L18 7L15 3Z',\n};\n\n/**\n * Legacy default access pictogram — now the ISO-style wheelchair symbol. Kept as\n * an alias of {@link ACCESS_TYPE_GLYPH_PATHS.wheelchair} for back-compat with\n * callers that drew a single wheelchair glyph.\n */\nexport const ACCESS_GLYPH_PATH = ACCESS_TYPE_GLYPH_PATHS.wheelchair;\n\n/**\n * The glyph to draw for a seat's PRIMARY accommodation. Wheelchair wins whenever\n * present (its physical provision is the headline fact); otherwise the first\n * listed accommodation is shown. Returns null for a seat with no accommodations,\n * so callers can skip drawing a glyph.\n */\nexport function accessGlyphPath(accessibility: AccessibilityType[]): string | null {\n if (!accessibility?.length) return null;\n const primary = accessibility.includes('wheelchair') ? 'wheelchair' : accessibility[0];\n return ACCESS_TYPE_GLYPH_PATHS[primary] ?? null;\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 */\n/**\n * Acceptance bar for AUTHORED seat-number / row-label colors (the theme\n * swatches). These are short bold marks whose information is duplicated in\n * tooltips/chips, so the WCAG non-text 3:1 bar applies — under the 4.5:1\n * small-text bar a normal mid-tone category palette rejects EVERY authored\n * color (each seat silently falls back to black/white and the control feels\n * broken; owner-found 07-23). Auto-swap still guards anything below 3:1.\n */\nexport const AUTHORED_LABEL_MIN_CONTRAST = 3;\n\nexport function stateAwareBookableLabelInk(fill: string, preferred: string, minContrast: number = SMALL_TEXT_CONTRAST): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= minContrast) 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\n/**\n * Ink for the accessibility seat glyphs. Unlike seat-number text, these are\n * bold solid silhouettes — graphical objects, so the WCAG non-text bar (3:1)\n * applies, not the 4.5:1 small-text bar. Preferring white at ≥3:1 keeps the\n * glyph crisp on every mid/dark category colour (where a 4.5:1 text rule was\n * falling back to near-invisible dark-on-mid ink); genuinely light seat fills\n * still get the dark ink.\n */\nconst GLYPH_CONTRAST = 3;\nexport function accessGlyphInk(fill: string): string {\n const white = renderedTextContrast('#ffffff', fill);\n if (white != null && white >= GLYPH_CONTRAST) return '#ffffff';\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 '#ffffff';\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 minContrast: number = SMALL_TEXT_CONTRAST,\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, minContrast);\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","import {\n MIN_VISIBLE_BOOKABLE_LABEL_PX,\n renderedTextContrast,\n} from './chartRenderRules';\nimport type {\n RenderedBookableLabelEvidence,\n RenderedFreeTextEvidence,\n RenderedHierarchyLabelEvidence,\n RendererQualityEvidence,\n} from './types';\n\nexport const RENDERED_QUALITY_REPORT_VERSION = 3;\nconst MIN_TEXT_CONTRAST = 4.5;\nconst MIN_GRAPHICAL_CONTRAST = 3;\nconst MIN_POINTER_TARGET_PX = 24;\nconst MAX_SAMPLES_PER_FINDING = 20;\n\nexport type RenderedEvidenceState = 'overview' | 'interaction';\n\ninterface ScreenBox { x: number; y: number; width: number; height: number }\n\nexport type RenderedQualityFindingCode =\n | 'bookable-label-undersized'\n | 'bookable-label-contrast-low'\n | 'bookable-label-collision'\n | 'hierarchy-label-undersized'\n | 'hierarchy-label-contrast-low'\n | 'hierarchy-label-outside-section'\n | 'hierarchy-label-collision'\n | 'hierarchy-bookable-collision'\n | 'overview-section-category-paint'\n | 'overview-category-detail-visible'\n | 'overview-row-hints-visible'\n | 'overview-availability-clutter'\n | 'overview-ga-detail-visible'\n | 'free-text-undersized'\n | 'free-text-contrast-low'\n | 'free-text-collision'\n | 'free-text-bookable-collision'\n | 'free-text-hierarchy-collision'\n | 'ga-contrast-low'\n | 'detail-rung-missing'\n | 'detail-inventory-not-visible'\n | 'pointer-target-undersized'\n | 'pointer-target-inactive'\n | 'selected-state-missing'\n | 'selected-state-contrast-low'\n | 'held-state-missing'\n | 'booked-state-missing'\n | 'status-state-indistinct'\n | 'section-focus-missing'\n | 'category-filter-missing'\n | 'category-filter-ineffective'\n | 'target-category-not-visible'\n | 'target-category-filter-mismatch';\n\nexport interface RenderedQualitySample {\n primaryId: string;\n primaryLabel: string;\n secondaryId?: string;\n secondaryLabel?: string;\n measured?: number;\n minimum?: number;\n}\n\nexport interface RenderedQualityFinding {\n code: RenderedQualityFindingCode;\n message: string;\n count: number;\n samples: RenderedQualitySample[];\n}\n\nexport interface RenderedQualityReport {\n version: typeof RENDERED_QUALITY_REPORT_VERSION;\n passed: boolean;\n state: RenderedEvidenceState;\n /** Server-selected category exercised by a category-specific detail scene. */\n targetCategoryKey: string | null;\n /** Exact overview checks discharged by this browser-rendered report. */\n resolvedRules: string[];\n viewport: { width: number; height: number };\n canvasBackground: string;\n effectiveScale: number;\n rung: RendererQualityEvidence['rung'];\n inventory: {\n totalBookableUnits: number;\n totalLabelledBookableUnits: number;\n visibleBookableLabels: number;\n hiddenBookableLabels: number;\n visibleHierarchyLabels: number;\n visibleFreeTextLabels: number;\n visibleGAAreas: number;\n };\n overviewStyle?: RendererQualityEvidence['overviewStyle'];\n /**\n * Coordinate-free identity evidence from the exact buyer scene. The Worker\n * uses this to compare persisted reference semantics with what Chromium\n * actually painted, without exposing screen boxes or accepting geometry.\n */\n composition: {\n hierarchy: Array<{\n id: string;\n kind: 'section' | 'zone';\n label: string;\n visible: boolean;\n }>;\n labelledObjects: Array<{\n objectId: string;\n kind: RenderedFreeTextEvidence['kind'];\n text: string;\n visible: boolean;\n }>;\n gaAreas: Array<{\n areaId: string;\n label: string;\n categoryKey: string;\n sectionId?: string;\n visible: boolean;\n }>;\n bookableSectionIds: string[];\n categoryKeys: string[];\n /** Categories whose non-dimmed bookable paint is visible in this scene. */\n activeCategoryKeys: string[];\n };\n metrics: {\n minimumRenderedBookableLabelPx: number | null;\n minimumBookableLabelContrast: number | null;\n minimumRenderedHierarchyLabelPx: number | null;\n minimumHierarchyLabelContrast: number | null;\n minimumRenderedFreeTextPx: number | null;\n minimumFreeTextContrast: number | null;\n minimumGAContrast: number | null;\n minimumEffectivePointerTargetPx: number | null;\n selectedRingContrast: number | null;\n };\n interaction: {\n applicable: {\n detail: boolean;\n pointer: boolean;\n held: boolean;\n booked: boolean;\n sectionFocus: boolean;\n categoryFilter: boolean;\n };\n selectedUnits: number;\n heldUnits: number;\n bookedUnits: number;\n activePointerTargets: number;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n };\n findings: RenderedQualityFinding[];\n}\n\ntype VisibleWithBox<T extends { visible: boolean; screenBox?: ScreenBox }> = T & { screenBox: ScreenBox };\n\nfunction visibleWithBox<T extends { visible: boolean; screenBox?: ScreenBox }>(\n items: T[],\n): Array<VisibleWithBox<T>> {\n return items.filter((item): item is VisibleWithBox<T> => item.visible && Boolean(item.screenBox));\n}\n\nfunction intersects(left: ScreenBox, right: ScreenBox): boolean {\n return left.x < right.x + right.width && left.x + left.width > right.x\n && left.y < right.y + right.height && left.y + left.height > right.y;\n}\n\nfunction minimum(values: number[]): number | null {\n return values.length ? Math.round(Math.min(...values) * 100) / 100 : null;\n}\n\nfunction finding(\n code: RenderedQualityFindingCode,\n message: string,\n samples: RenderedQualitySample[],\n): RenderedQualityFinding | null {\n if (!samples.length) return null;\n return {\n code,\n message,\n count: samples.length,\n samples: samples.slice(0, MAX_SAMPLES_PER_FINDING),\n };\n}\n\nfunction labelSample(label: RenderedBookableLabelEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.seatId,\n primaryLabel: label.label,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction hierarchySample(label: RenderedHierarchyLabelEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.id,\n primaryLabel: label.label,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction freeTextSample(label: RenderedFreeTextEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.objectId,\n primaryLabel: label.text,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction collisionSample(\n primaryId: string,\n primaryLabel: string,\n secondaryId: string,\n secondaryLabel: string,\n): RenderedQualitySample {\n return { primaryId, primaryLabel, secondaryId, secondaryLabel };\n}\n\n/**\n * Inspect what the buyer renderer actually decided to paint at one exact\n * viewport. This is deliberately downstream of ChartDoc validation: screen\n * size, LOD visibility, fitted hierarchy text, transient paint, and label\n * collisions cannot be proven from stored geometry alone.\n */\nexport function inspectRenderedQualityEvidence(\n evidence: RendererQualityEvidence,\n state: RenderedEvidenceState = 'overview',\n targetCategoryKey: string | null = null,\n): RenderedQualityReport {\n const bookable = visibleWithBox(evidence.labels);\n const hierarchy = visibleWithBox(evidence.hierarchyLabels);\n const freeText = visibleWithBox(evidence.freeTextLabels);\n const visibleGA = evidence.gaAreas.filter((area) => area.visible);\n\n const bookableContrast = bookable.map((label) => renderedTextContrast(label.ink, label.fill) ?? 0);\n const hierarchyContrast = hierarchy.map((label) => renderedTextContrast(label.ink, label.fill) ?? 0);\n const freeTextContrast = freeText.map((label) => renderedTextContrast(label.ink, label.background) ?? 0);\n const gaContrast = visibleGA.map((area) => renderedTextContrast(area.effectiveBackground, evidence.canvasBackground) ?? 0);\n const targetLabels = targetCategoryKey\n ? evidence.labels.filter((label) => label.categoryKey === targetCategoryKey)\n : evidence.labels;\n const targetGAAreas = targetCategoryKey\n ? evidence.gaAreas.filter((area) => area.categoryKey === targetCategoryKey)\n : evidence.gaAreas;\n const selected = targetLabels.filter((label) => label.selected);\n const held = targetLabels.filter((label) => label.status === 'held');\n const booked = targetLabels.filter((label) => label.status === 'booked');\n const activePointerTargets = targetLabels.filter((label) => label.pointerTarget.active);\n const activeCategoryKeys = new Set([\n ...evidence.labels\n .filter((label) => label.visible && (label.opacity > 0.25 || label.selected || label.status !== 'free'))\n .map((label) => label.categoryKey),\n ...evidence.gaAreas\n .filter((area) => area.visible && area.opacity > 0.1)\n .map((area) => area.categoryKey),\n ]);\n const selectedRingContrast = selected.length\n ? minimum(selected.flatMap((label) => [\n renderedTextContrast(evidence.selectionRingColor, evidence.canvasBackground) ?? 0,\n renderedTextContrast(evidence.selectionRingColor, label.fill) ?? 0,\n ]))\n : null;\n\n const findings: Array<RenderedQualityFinding | null> = [];\n const overviewCountSamples = (count: number, label: string): RenderedQualitySample[] =>\n Array.from({ length: count }, (_, index) => ({\n primaryId: `overview:${index + 1}`,\n primaryLabel: label,\n }));\n if (state === 'overview' && evidence.rung === 'sections') {\n findings.push(finding(\n 'overview-section-category-paint',\n 'Section overview shells must use the neutral hierarchy palette, not category paint',\n overviewCountSamples(evidence.overviewStyle.categoryPaintedSectionShells, 'category-painted section shell'),\n ));\n findings.push(finding(\n 'overview-category-detail-visible',\n 'Category-tinted section detail must wait until section focus or seat zoom',\n overviewCountSamples(evidence.overviewStyle.visibleCategoryDetailOutlines, 'category detail outline'),\n ));\n findings.push(finding(\n 'overview-row-hints-visible',\n 'Row and seat patterns must not clutter the section overview',\n overviewCountSamples(evidence.overviewStyle.visibleSectionRowHints, 'section row hint'),\n ));\n findings.push(finding(\n 'overview-availability-clutter',\n 'Live availability counts belong in focused detail, not on section overview shells',\n overviewCountSamples(evidence.overviewStyle.visibleSectionAvailabilityLabels, 'section availability label'),\n ));\n findings.push(finding(\n 'overview-ga-detail-visible',\n 'Section-contained standing paint belongs in focused detail, not on section overview shells',\n overviewCountSamples(evidence.overviewStyle.visibleSectionGADetails, 'section-contained GA detail'),\n ));\n }\n findings.push(finding(\n 'bookable-label-undersized',\n 'Visible bookable labels must meet the rendered small-text size floor',\n bookable\n .filter((label) => label.renderedFontPx < evidence.minimumVisibleLabelPx)\n .map((label) => labelSample(label, label.renderedFontPx, evidence.minimumVisibleLabelPx)),\n ));\n\n if (state === 'interaction') {\n const labelledInventory = targetLabels.length > 0;\n const gaInventory = targetGAAreas.length > 0;\n const detailInventory = labelledInventory || gaInventory;\n const visibleTargetGA = targetGAAreas.filter((area) => area.visible);\n const sections = new Set([\n ...targetLabels.flatMap((label) => label.sectionId ? [label.sectionId] : []),\n ...targetGAAreas.flatMap((area) => area.sectionId ? [area.sectionId] : []),\n ]);\n const categories = new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ]);\n const inViewport = (label: RenderedBookableLabelEvidence) => (\n label.screenCenter.x >= 0 && label.screenCenter.x <= evidence.viewport.width\n && label.screenCenter.y >= 0 && label.screenCenter.y <= evidence.viewport.height\n );\n findings.push(finding(\n 'detail-rung-missing',\n 'Interaction evidence with bookable inventory must render the seat-detail rung',\n detailInventory && evidence.rung !== 'seats'\n ? [{ primaryId: 'renderer', primaryLabel: evidence.rung }]\n : [],\n ));\n findings.push(finding(\n 'detail-inventory-not-visible',\n 'Interaction evidence must frame at least one real bookable unit',\n detailInventory && !targetLabels.some(inViewport) && !visibleTargetGA.length\n ? [{ primaryId: 'renderer', primaryLabel: 'no target inventory in viewport' }]\n : [],\n ));\n findings.push(finding(\n 'pointer-target-inactive',\n 'Interaction evidence must expose a live production pointer target',\n (labelledInventory && !activePointerTargets.some(inViewport))\n || (!labelledInventory && gaInventory && !visibleTargetGA.some((area) => area.interactive))\n ? [{ primaryId: 'renderer', primaryLabel: 'no active pointer target in viewport' }]\n : [],\n ));\n findings.push(finding(\n 'pointer-target-undersized',\n 'Every active production pointer target must reach at least 24 CSS pixels',\n activePointerTargets\n .filter((label) => inViewport(label) && label.pointerTarget.effectiveMinimumPx < MIN_POINTER_TARGET_PX)\n .map((label) => labelSample(label, label.pointerTarget.effectiveMinimumPx, MIN_POINTER_TARGET_PX)),\n ));\n findings.push(finding(\n 'selected-state-missing',\n 'Interaction evidence must paint a selected unit and its renderer-owned ring',\n labelledInventory && (!selected.length || !selected.some((label) => evidence.selectionRingSeatIds.includes(label.seatId)))\n ? [{ primaryId: 'renderer', primaryLabel: 'selected state' }]\n : [],\n ));\n findings.push(finding(\n 'selected-state-contrast-low',\n 'The selected-state ring must maintain 3:1 graphical contrast with the canvas',\n selected.length && (selectedRingContrast ?? 0) < MIN_GRAPHICAL_CONTRAST\n ? [{\n primaryId: selected[0].seatId,\n primaryLabel: selected[0].label,\n measured: Math.round((selectedRingContrast ?? 0) * 100) / 100,\n minimum: MIN_GRAPHICAL_CONTRAST,\n }]\n : [],\n ));\n findings.push(finding(\n 'held-state-missing',\n 'Interaction evidence must paint a held state when the floor has at least two status-managed units',\n targetLabels.length >= 2 && !held.length\n ? [{ primaryId: 'renderer', primaryLabel: 'held state' }]\n : [],\n ));\n findings.push(finding(\n 'booked-state-missing',\n 'Interaction evidence must paint a taken state when the floor has at least three status-managed units',\n targetLabels.length >= 3 && !booked.length\n ? [{ primaryId: 'renderer', primaryLabel: 'booked state' }]\n : [],\n ));\n const heldSignatures = new Set(held.map((label) => `${label.fill.toLowerCase()}:${label.opacity}`));\n const bookedSignatures = new Set(booked.map((label) => `${label.fill.toLowerCase()}:${label.opacity}`));\n findings.push(finding(\n 'status-state-indistinct',\n 'Held and taken evidence must resolve to distinct renderer paint',\n held.length && booked.length && [...heldSignatures].some((signature) => bookedSignatures.has(signature))\n ? [{ primaryId: held[0].seatId, primaryLabel: held[0].label, secondaryId: booked[0].seatId, secondaryLabel: booked[0].label }]\n : [],\n ));\n findings.push(finding(\n 'section-focus-missing',\n 'Interaction evidence must exercise section focus and its backdrop when section membership exists',\n sections.size && (!evidence.focusedSectionId || !evidence.focusBackdropVisible)\n ? [{ primaryId: 'renderer', primaryLabel: 'section focus' }]\n : [],\n ));\n findings.push(finding(\n 'category-filter-missing',\n 'Interaction evidence must exercise a category filter when multiple categories exist',\n categories.size >= 2 && (!evidence.categoryFilterKeys || !evidence.categoryFilterKeys.length)\n ? [{ primaryId: 'renderer', primaryLabel: 'category filter' }]\n : [],\n ));\n const excludedFree = evidence.labels.filter((label) => (\n label.status === 'free'\n && !label.selected\n && evidence.categoryFilterKeys != null\n && !evidence.categoryFilterKeys.includes(label.categoryKey)\n ));\n const excludedGA = evidence.gaAreas.filter((area) => (\n evidence.categoryFilterKeys != null\n && !evidence.categoryFilterKeys.includes(area.categoryKey)\n ));\n findings.push(finding(\n 'category-filter-ineffective',\n 'The active category filter must visibly dim excluded free inventory',\n (excludedFree.length || excludedGA.length)\n && !excludedFree.some((label) => label.opacity <= 0.25)\n && !excludedGA.some((area) => area.opacity <= 0.1)\n ? [\n ...excludedFree.map((label) => labelSample(label, label.opacity)),\n ...excludedGA.map((area) => ({ primaryId: area.areaId, primaryLabel: area.label, measured: area.opacity })),\n ]\n : [],\n ));\n findings.push(finding(\n 'target-category-not-visible',\n 'A category-specific interaction scene must visibly paint its exact target category',\n targetCategoryKey && !activeCategoryKeys.has(targetCategoryKey)\n ? [{ primaryId: targetCategoryKey, primaryLabel: targetCategoryKey }]\n : [],\n ));\n findings.push(finding(\n 'target-category-filter-mismatch',\n 'A category-specific interaction scene must bind its filter to only the exact target category',\n targetCategoryKey && (\n evidence.categoryFilterKeys?.length !== 1\n || evidence.categoryFilterKeys[0] !== targetCategoryKey\n )\n ? [{ primaryId: targetCategoryKey, primaryLabel: targetCategoryKey }]\n : [],\n ));\n }\n findings.push(finding(\n 'bookable-label-contrast-low',\n 'Visible bookable labels must meet 4.5:1 contrast against their actual paint',\n bookable.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.fill) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [labelSample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n\n const bookableCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < bookable.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(bookable[index].screenBox, bookable[other].screenBox)) {\n bookableCollisions.push(collisionSample(\n bookable[other].seatId, bookable[other].label,\n bookable[index].seatId, bookable[index].label,\n ));\n }\n }\n }\n findings.push(finding(\n 'bookable-label-collision',\n 'Visible bookable labels must not overlap',\n bookableCollisions,\n ));\n\n findings.push(finding(\n 'hierarchy-label-undersized',\n 'Visible section and zone labels must meet the rendered small-text size floor',\n hierarchy\n .filter((label) => label.renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX)\n .map((label) => hierarchySample(label, label.renderedFontPx, MIN_VISIBLE_BOOKABLE_LABEL_PX)),\n ));\n findings.push(finding(\n 'hierarchy-label-contrast-low',\n 'Visible section and zone labels must meet 4.5:1 contrast against their backing paint',\n hierarchy.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.fill) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [hierarchySample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n findings.push(finding(\n 'hierarchy-label-outside-section',\n 'Visible section labels must remain inside the filled section surface and outside holes',\n hierarchy\n .filter((label) => label.kind === 'section' && label.fitsContainer === false)\n .map((label) => hierarchySample(label)),\n ));\n\n const hierarchyCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < hierarchy.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(hierarchy[index].screenBox, hierarchy[other].screenBox)) {\n hierarchyCollisions.push(collisionSample(\n hierarchy[other].id, hierarchy[other].label,\n hierarchy[index].id, hierarchy[index].label,\n ));\n }\n }\n }\n findings.push(finding(\n 'hierarchy-label-collision',\n 'Visible hierarchy labels must not overlap each other',\n hierarchyCollisions,\n ));\n\n const hierarchyBookableCollisions: RenderedQualitySample[] = [];\n for (const upper of hierarchy) {\n for (const unit of bookable) {\n if (intersects(upper.screenBox, unit.screenBox)) {\n hierarchyBookableCollisions.push(collisionSample(upper.id, upper.label, unit.seatId, unit.label));\n }\n }\n }\n findings.push(finding(\n 'hierarchy-bookable-collision',\n 'Visible hierarchy labels must not overlap bookable labels',\n hierarchyBookableCollisions,\n ));\n\n findings.push(finding(\n 'free-text-undersized',\n 'Visible chart text must meet the rendered small-text size floor',\n freeText\n .filter((label) => label.renderedFontPx < evidence.minimumVisibleLabelPx)\n .map((label) => freeTextSample(label, label.renderedFontPx, evidence.minimumVisibleLabelPx)),\n ));\n findings.push(finding(\n 'free-text-contrast-low',\n 'Visible chart text must meet 4.5:1 contrast against its measured background',\n freeText.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.background) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [freeTextSample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n\n const freeTextCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < freeText.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(freeText[index].screenBox, freeText[other].screenBox)) {\n freeTextCollisions.push(collisionSample(\n freeText[other].objectId, freeText[other].text,\n freeText[index].objectId, freeText[index].text,\n ));\n }\n }\n }\n findings.push(finding(\n 'free-text-collision',\n 'Visible chart text labels must not overlap each other',\n freeTextCollisions,\n ));\n\n const freeTextBookableCollisions: RenderedQualitySample[] = [];\n for (const text of freeText) {\n for (const unit of bookable) {\n if (intersects(text.screenBox, unit.screenBox)) {\n freeTextBookableCollisions.push(collisionSample(text.objectId, text.text, unit.seatId, unit.label));\n }\n }\n }\n findings.push(finding(\n 'free-text-bookable-collision',\n 'Visible chart text must not overlap bookable labels',\n freeTextBookableCollisions,\n ));\n\n const freeTextHierarchyCollisions: RenderedQualitySample[] = [];\n for (const text of freeText) {\n for (const upper of hierarchy) {\n if (intersects(text.screenBox, upper.screenBox)) {\n freeTextHierarchyCollisions.push(collisionSample(text.objectId, text.text, upper.id, upper.label));\n }\n }\n }\n findings.push(finding(\n 'free-text-hierarchy-collision',\n 'Visible chart text must not overlap hierarchy labels',\n freeTextHierarchyCollisions,\n ));\n\n findings.push(finding(\n 'ga-contrast-low',\n 'Visible GA surfaces must maintain 3:1 graphical contrast with the canvas',\n visibleGA.flatMap((area) => {\n const ratio = renderedTextContrast(area.effectiveBackground, evidence.canvasBackground) ?? 0;\n return ratio < MIN_GRAPHICAL_CONTRAST ? [{\n primaryId: area.areaId,\n primaryLabel: area.label,\n measured: Math.round(ratio * 100) / 100,\n minimum: MIN_GRAPHICAL_CONTRAST,\n }] : [];\n }),\n ));\n\n const materialFindings = findings.filter((item): item is RenderedQualityFinding => Boolean(item));\n return {\n version: RENDERED_QUALITY_REPORT_VERSION,\n passed: materialFindings.length === 0,\n state,\n targetCategoryKey,\n resolvedRules: [\n 'rendered-overview-label-size',\n 'rendered-overview-label-contrast',\n 'rendered-overview-label-collision',\n 'rendered-overview-hierarchy-containment',\n 'rendered-overview-section-first-style',\n 'rendered-overview-ga-contrast',\n ...(state === 'interaction' ? [\n 'rendered-detail-inventory',\n 'rendered-pointer-target',\n 'rendered-selected-held-taken-states',\n 'rendered-section-focus',\n 'rendered-category-filter',\n ] : []),\n ],\n viewport: evidence.viewport,\n canvasBackground: evidence.canvasBackground,\n effectiveScale: evidence.effectiveScale,\n rung: evidence.rung,\n inventory: {\n totalBookableUnits: evidence.totalBookableUnits,\n totalLabelledBookableUnits: evidence.totalLabelledBookableUnits,\n visibleBookableLabels: bookable.length,\n hiddenBookableLabels: evidence.hiddenLabels,\n visibleHierarchyLabels: hierarchy.length,\n visibleFreeTextLabels: freeText.length,\n visibleGAAreas: visibleGA.length,\n },\n overviewStyle: evidence.overviewStyle,\n composition: {\n hierarchy: evidence.hierarchyLabels\n .filter((label) => label.role === 'name')\n .map((label) => ({\n id: label.id,\n kind: label.kind,\n label: label.label,\n visible: label.visible,\n }))\n .sort((left, right) => left.kind.localeCompare(right.kind) || left.id.localeCompare(right.id)),\n labelledObjects: evidence.freeTextLabels\n .map((label) => ({\n objectId: label.objectId,\n kind: label.kind,\n text: label.text,\n visible: label.visible,\n }))\n .sort((left, right) => left.objectId.localeCompare(right.objectId) || left.kind.localeCompare(right.kind)),\n gaAreas: evidence.gaAreas\n .map((area) => ({\n areaId: area.areaId,\n label: area.label,\n categoryKey: area.categoryKey,\n ...(area.sectionId ? { sectionId: area.sectionId } : {}),\n visible: area.visible,\n }))\n .sort((left, right) => left.areaId.localeCompare(right.areaId)),\n bookableSectionIds: [...new Set(evidence.labels.flatMap((label) => label.sectionId ? [label.sectionId] : []))].sort(),\n categoryKeys: [...new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ])].sort(),\n activeCategoryKeys: [...activeCategoryKeys].sort(),\n },\n metrics: {\n minimumRenderedBookableLabelPx: minimum(bookable.map((label) => label.renderedFontPx)),\n minimumBookableLabelContrast: minimum(bookableContrast),\n minimumRenderedHierarchyLabelPx: minimum(hierarchy.map((label) => label.renderedFontPx)),\n minimumHierarchyLabelContrast: minimum(hierarchyContrast),\n minimumRenderedFreeTextPx: minimum(freeText.map((label) => label.renderedFontPx)),\n minimumFreeTextContrast: minimum(freeTextContrast),\n minimumGAContrast: minimum(gaContrast),\n minimumEffectivePointerTargetPx: minimum(activePointerTargets.map((label) => label.pointerTarget.effectiveMinimumPx)),\n selectedRingContrast: selectedRingContrast == null ? null : Math.round(selectedRingContrast * 100) / 100,\n },\n interaction: {\n applicable: {\n detail: targetLabels.length > 0 || targetGAAreas.length > 0,\n pointer: targetLabels.length > 0 || targetGAAreas.length > 0,\n held: targetLabels.length >= 2,\n booked: targetLabels.length >= 3,\n sectionFocus: targetLabels.some((label) => Boolean(label.sectionId))\n || targetGAAreas.some((area) => Boolean(area.sectionId)),\n categoryFilter: new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ]).size >= 2,\n },\n selectedUnits: selected.length,\n heldUnits: held.length,\n bookedUnits: booked.length,\n activePointerTargets: activePointerTargets.length,\n focusedSectionId: evidence.focusedSectionId,\n focusBackdropVisible: evidence.focusBackdropVisible,\n categoryFilterKeys: evidence.categoryFilterKeys,\n },\n findings: materialFindings,\n };\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 { Arrow } from 'konva/lib/shapes/Arrow';\nimport { Text } from 'konva/lib/shapes/Text';\nimport { Path } from 'konva/lib/shapes/Path';\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 RendererViewMode,\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 { distanceToRings, polygonNetArea } from '../core/polygonAnchor';\nimport { buyerBackgroundImage } from '../core/chartBackgrounds';\nimport { venueIconPath, VENUE_ICON_VIEWBOX, VENUE_ICON_STROKE } from '../core/icons';\nimport { sectionGeometry } from '../core/sections';\nimport { buildSeatIndex, queryRect, type SeatIndex } from '../core/spatialIndex';\nimport { CHART_UNITS_PER_METRE, SEATED_EYE_HEIGHT_M, sectionElevationTier } from '../core/units';\nimport {\n applyAffine,\n composeAffine,\n createPerspectiveCamera,\n decomposeAffineLinear,\n invertAffine,\n perspectiveTangentAffine,\n projectPerspectivePoint,\n type Affine2D,\n type PerspectiveCamera,\n} from '../core/perspectiveProjection';\nimport {\n ACCESS_GLYPH_VIEWBOX,\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 accessGlyphInk,\n accessGlyphPath,\n bookableMarkerLabel,\n compositeHexOver,\n isBookableLabelLegibleAtScale,\n AUTHORED_LABEL_MIN_CONTRAST,\n stateAwareBookableLabelInk,\n} from '../core/chartRenderRules';\nimport { t } from '../i18n';\nimport { formatMoney } from '../lib/money';\nimport { resolvedShapeLineStyle, shapeArrowMetrics } from '../core/shapeLineStyle';\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/** Wheelchair provision remains identifiable in the normal All-seats view. */\nconst WHEELCHAIR_GLYPH_MIN_PX = 10;\n/**\n * Minimum screen-space size of the wheelchair glyph while the buyer is\n * explicitly filtering for wheelchair provision. At venue-fit LOD a normal\n * seat can be only a couple of pixels wide; keeping the selected filter's\n * semantic marker at a stable size makes the result recognizable without\n * changing the seat's inventory silhouette or hit target.\n */\nconst FILTERED_WHEELCHAIR_GLYPH_MIN_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/** Window after a `tap` in which a `click` is the browser's ghost, not a real\n * mouse click. 700ms covers the legacy 300ms click delay with margin; mouse\n * and pen paths never set the timestamp, so they are unaffected. */\nconst GHOST_CLICK_MS = 700;\n/** World-space padding kept between an automatic row label and nearby ink. */\nconst ROW_LABEL_CLEARANCE = 2;\n/** Cell size for the tiny row/free-text collision index. Row labels are\n * normally 10–40 chart units wide, so 64 keeps each query to a few entries. */\nconst ROW_LABEL_COLLISION_CELL = 64;\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/** 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 shaded by four bounded availability\n * states (normal / nearly-gone / sold-out / closed) — never a continuous\n * price-or-demand heatmap ramp. See overviewStateFill / SectionAvailabilityState. */\nconst BLOCK_FILL_ALPHA = 1;\n/**\n * Section outlines are drawn TWICE — the colour-tinted outline underneath and\n * the neutral overview shell on top — so the border an author sees is the sum\n * of both. At 2px each that reads as a heavy double rule, and on a traced plan\n * whose sections now abut along a deliberate 2px gutter it swallows the gutter\n * entirely: neighbours look welded together rather than separated.\n *\n * One screen pixel per stroke keeps the boundary crisp at every zoom without\n * competing with the gap itself for the author's attention.\n */\nconst SECTION_STROKE_PX = 1;\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;\n/** Successive shrinks tried on a colliding section name before it is hidden. */\nconst SECTION_LABEL_SHRINK_STEPS = [0.85, 0.72, 0.62] as const;\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 bind to these by their stable KEY (sorted), never doc order, so\n * reordering categories never re-shuffles seat hues (OV-46). */\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';\n\n/** Konva `fontStyle` string from bold/italic flags (mirrors the designer). */\nfunction konvaFontStyle(bold?: boolean, italic?: boolean, defaultWeight = 'normal'): string {\n const weight = bold ? 'bold' : defaultWeight;\n return italic ? `italic ${weight}`.trim() : weight;\n}\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\ninterface WorldBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface RowLabelPlanEntry {\n text: string;\n x: number;\n y: number;\n rotation: number;\n fontSize: number;\n ink: string;\n opacity: number;\n /** Absent for a free-drag position, which must remain pixel-faithful. */\n automaticAway?: Point;\n}\n\nfunction worldBoxesOverlap(a: WorldBox, b: WorldBox): boolean {\n return a.x < b.x + b.width && b.x < a.x + a.width\n && a.y < b.y + b.height && b.y < a.y + a.height;\n}\n\n/** Small deterministic grid used only while rebuilding viewport labels. */\nclass WorldBoxIndex {\n private cells = new Map<string, WorldBox[]>();\n\n insert(box: WorldBox): void {\n for (const key of this.keys(box)) {\n const bucket = this.cells.get(key);\n if (bucket) bucket.push(box);\n else this.cells.set(key, [box]);\n }\n }\n\n collisionCount(box: WorldBox): number {\n const seen = new Set<WorldBox>();\n let count = 0;\n for (const key of this.keys(box)) {\n for (const existing of this.cells.get(key) ?? []) {\n if (seen.has(existing)) continue;\n seen.add(existing);\n if (worldBoxesOverlap(box, existing)) count++;\n }\n }\n return count;\n }\n\n private keys(box: WorldBox): string[] {\n const x0 = Math.floor(box.x / ROW_LABEL_COLLISION_CELL);\n const x1 = Math.floor((box.x + Math.max(0, box.width)) / ROW_LABEL_COLLISION_CELL);\n const y0 = Math.floor(box.y / ROW_LABEL_COLLISION_CELL);\n const y1 = Math.floor((box.y + Math.max(0, box.height)) / ROW_LABEL_COLLISION_CELL);\n const keys: string[] = [];\n for (let y = y0; y <= y1; y++) {\n for (let x = x0; x <= x1; x++) keys.push(`${x}:${y}`);\n }\n return keys;\n }\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\n/**\n * Bounded availability states an overview section shell can read (OV-69). This is\n * a four-bucket semantic ladder, deliberately NOT a continuous demand heatmap:\n * • normal — shown in the neutral shell fill.\n * • nearly-gone — >0 but ≤10% of the section's seats free: one desaturated step.\n * • sold-out — 0 seats free: a muted, flatter fill that reads unavailable.\n * • closed — operator turned the section off: its own darker slab (kept).\n * `closed` outranks the live-availability buckets — an operator close is authoritative.\n */\ntype SectionAvailabilityState = 'normal' | 'nearly-gone' | 'sold-out' | 'closed';\n\n/** Section is nearly gone once free seats drop to this fraction of its capacity. */\nconst SECTION_NEARLY_GONE_RATIO = 0.1;\n\n/** The one source of truth for a section shell's fill per availability state.\n * Both the live paint and the overview evidence set read from here, so the\n * \"clean shell never leaks category paint\" check treats these semantic fills as\n * legitimate (not category leakage). */\nfunction overviewStateFill(palette: OverviewPalette, state: SectionAvailabilityState): string {\n const base = palette.sectionFill;\n // Sold-out: drop lightness a notch then drain the cool cast so it reads as a\n // dead, muted block — distinct from the operator-closed darker-but-tinted slab.\n const soldOut = desaturate(darken(base, 0.2), 0.85);\n switch (state) {\n case 'closed':\n return darken(base, 0.12);\n case 'sold-out':\n return soldOut;\n case 'nearly-gone':\n // One measured step toward sold-out — never a smooth per-seat ramp.\n return lerpColor(base, soldOut, 0.4);\n case 'normal':\n default:\n return base;\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/** Mix a #rrggbb colour toward its own perceptual grey by `amt` (0..1) —\n * drains saturation without changing brightness, for the muted \"sold-out\" look. */\nfunction desaturate(hex: string, amt: number): string {\n const rgb = hexToRgb(hex);\n if (!rgb) return hex;\n const [r, g, b] = rgb;\n const grey = 0.299 * r + 0.587 * g + 0.114 * b;\n return toHex(r + (grey - r) * amt, g + (grey - g) * amt, b + (grey - b) * amt);\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/**\n * Interior anchors to try when fitting a section name, fattest first.\n *\n * `preferred` is the polygon's pole of inaccessibility, so it leads. The grid\n * fallbacks used to be ordered by distance to the bounding-box centre, which on\n * a concave shell ranks points by where the *box* middle is rather than by how\n * much room they have — the fitter then walked down font sizes at cramped\n * anchors before reaching a roomy one. Ordering by clearance from every ring\n * means the first anchor tried is always the one most likely to hold the label.\n */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\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 const rings = [outer, ...holes];\n return points\n .map((point) => ({ point, room: distanceToRings(point, rings) }))\n .sort((left, right) => right.room - left.room)\n .map((entry) => entry.point)\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\n/** Trace a closed polygon with rounded corners (radius clamped per corner to\n * half the shorter adjacent edge). Mirrors the designer's corner-smoothing so\n * the buyer map matches the authored GA shape (OV-66). */\nfunction roundedPolygonSubpath(\n context: { moveTo(x: number, y: number): void; arcTo(x1: number, y1: number, x2: number, y2: number, r: number): void; closePath(): void },\n points: Point[],\n radius: number,\n): void {\n const n = points.length;\n const start = { x: (points[n - 1].x + points[0].x) / 2, y: (points[n - 1].y + points[0].y) / 2 };\n context.moveTo(start.x, start.y);\n for (let i = 0; i < n; i += 1) {\n const curr = points[i];\n const next = points[(i + 1) % n];\n const prev = points[(i - 1 + n) % n];\n const rMax = Math.min(\n Math.hypot(curr.x - prev.x, curr.y - prev.y) / 2,\n Math.hypot(next.x - curr.x, next.y - curr.y) / 2,\n );\n context.arcTo(curr.x, curr.y, next.x, next.y, Math.max(0, Math.min(radius, rMax)));\n }\n context.closePath();\n}\n\nfunction polygonWithHolesShape(\n outer: Point[],\n holes: Point[][] | undefined,\n attrs: { fill?: string; stroke?: string; strokeWidth?: number; opacity?: number; listening?: boolean; cornerRadius?: number },\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 const cornerRadius = attrs.cornerRadius && attrs.cornerRadius > 0 ? attrs.cornerRadius : 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 if (cornerRadius > 0 && points.length >= 3) return roundedPolygonSubpath(context, points, cornerRadius);\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/** A section container that can be omitted from scene + hit paints without\n * toggling Konva's public `visible` attribute. `visible(false)` recursively\n * invalidates every descendant's absolute-visibility cache — exactly the O(N)\n * cliff viewport culling is meant to avoid on a 14k-seat chart. */\nclass ViewportGroup extends Group {\n private viewportCulled = false;\n\n setViewportCulled(culled: boolean): void {\n if (culled === this.viewportCulled) return;\n this.viewportCulled = culled;\n // Descendants may have cached absolute transforms from before an offscreen\n // camera move. Clear them once when the section re-enters, not on every\n // frame while it remains outside the viewport.\n if (!culled) super._clearSelfAndDescendantCache();\n }\n\n isViewportCulled(): boolean {\n return this.viewportCulled;\n }\n\n override drawScene(...args: Parameters<Group['drawScene']>): this {\n return this.viewportCulled ? this : super.drawScene(...args);\n }\n\n override drawHit(...args: Parameters<Group['drawHit']>): this {\n return this.viewportCulled ? this : super.drawHit(...args);\n }\n\n override _clearSelfAndDescendantCache(attr?: string): void {\n if (!this.viewportCulled) {\n super._clearSelfAndDescendantCache(attr);\n return;\n }\n // The group itself must follow its parent camera, but culled children are\n // neither drawn nor hit-tested. Their caches are refreshed on re-entry.\n this._clearCache(attr);\n }\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 roomiest-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n /** Net shell area — the de-collision tiebreak, so big stands keep their name. */\n labelArea: number;\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 * Resolved iso lift in world units = `sectionGeometry(section).height ×\n * CHART_UNITS_PER_METRE` (Phase B1). Uses the section's authored real height when\n * present, else the legacy `elevation × TIER_HEIGHT_M` fallback — which equals the\n * old `elevation × LIFT_PER_STEP`, so un-authored charts stay pixel-identical.\n * Computed once at build time; never per frame.\n */\n liftWorld: number;\n /** Authored section rake used by the Phase-C tangent surface. */\n rakeDeg: number;\n /** Focal point that defines front→back depth for this physical surface. */\n surfaceFocal: Point;\n /** Nearest member/outline distance to the focal point, in chart units. */\n frontDistanceWorld: number;\n /** Desired projected tangent plane, built only while perspective is active. */\n perspectiveAffine?: Affine2D;\n /** Child correction after the shared ground-plane affine. */\n perspectiveCorrection?: Affine2D;\n /** Camera depth used to order far sections before near sections. */\n perspectiveDepth?: number;\n /** Section-owned background root: side faces + top-surface child group. */\n rootGroupBg: Group;\n /** Original sibling order restored when leaving perspective. */\n bgZIndex: number;\n seatZIndex: number;\n /** Elevated background container; null for a flat section. */\n liftGroupBg: Group;\n /**\n * Every section owns one seat group. Besides making elevation one group\n * transform, this is the production viewport-culling boundary: offscreen\n * sections do not make Konva repaint thousands of invisible seats while a\n * buyer pans or zooms a focused part of a large venue.\n */\n liftGroupSeat: ViewportGroup;\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 private readonly exportMode: boolean;\n\n private stage: Stage;\n private bgLayer: Layer;\n private seatLayer: Layer;\n private overlayLayer: Layer;\n private labelGroup: Group;\n /** Per-elevated-section label containers. Keeping the labels grouped lets the\n * Phase-B lift move thousands of seat labels with one transform per section\n * instead of rewriting every label on every tween frame. */\n private labelLiftGroups = new Map<string, ViewportGroup>();\n /** Foreground decor images — drawn on the overlay layer, ABOVE the seats. */\n private fgDecorGroup: Group;\n\n private seats: ExpandedSeat[] = [];\n private seatById = new Map<string, ExpandedSeat>();\n /** One build per chart/floor; section membership queries only inspect seats in\n * the section bounds instead of rescanning the full 13k venue per section. */\n private seatIndex: SeatIndex | null = null;\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; points?: Point[] }>();\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 /** Coloured accommodation ring per accessible seat (few per chart). */\n private accessRingById = new Map<string, Circle>();\n /** Centred ♿ glyph per physical wheelchair provision. It keeps a small\n * screen-space floor at every LOD and grows when the Wheelchair filter is\n * active. Kept in a map so zoom updates touch only the handful of matching\n * seats, never all 13k nodes. */\n private accessGlyphById = new Map<string, Path>();\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 /** Vector venue-icon Path nodes + authored size; obey the free-text size floor. */\n private iconNodeById = new Map<string, { node: Path; fontSize: number }>();\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 /** Stable per-category-KEY colorblind hue (OV-46) — order-independent. */\n private cbHueByKey = new Map<string, string>();\n /** OV-45(a): authored row-letter labels for the buyer/preview map, resolved in\n * world space (matching seat labels) and honouring each row's labelPresentation\n * (position/rotation/visibility/style). Painted at the seats LOD rung. */\n private rowLabelPlan: RowLabelPlanEntry[] = [];\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 /** Seat-contained 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 /** Seat currently owning the shared hover ring (null while not hovering). */\n private hoveredId: string | null = null;\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 /** Seats outside every authored section retain the legacy path in one group. */\n private unsectionedSeatGroup: Group | null = null;\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 /** Non-listening visual dim outside the focused section. One overlay replaces\n * descendant opacity mutations across every seat in the venue. */\n private focusDimOverlay: Shape | 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 /** Public view target; perspective is a separate non-affine Phase-C lane. */\n private viewMode: RendererViewMode = 'flat';\n private perspectiveCamera: PerspectiveCamera | null = null;\n /** Ground-plane tangent applied once to every renderer layer. */\n private perspectiveBaseAffine: Affine2D | null = null;\n private perspectiveBaseInverse: Affine2D | null = null;\n /** Exact pinhole anchor expressed in the overlay tangent-layer coordinates. */\n private perspectiveSeatLocal = new Map<string, Point>();\n /** Exact projected point (before Stage pan/zoom), keyed by seat. */\n private perspectiveSeatProjected = new Map<string, Point>();\n /** Positive camera depth, used for deterministic far→near paint order. */\n private perspectiveSeatDepth = new Map<string, number>();\n /** Exact pinhole size ratio at each seat anchor. */\n private perspectiveSeatScale = new Map<string, number>();\n /** Seats whose native Konva nodes currently carry the exact projected pose.\n * Large sectioned venues apply these lazily as a section enters the live-seat\n * viewport; the overview rung hides the seat layer completely. */\n private perspectiveAppliedSeats = new Set<string>();\n private perspectiveBounds: { x: number; y: number; width: number; height: number } | null = null;\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 /** While the camera tween is active, defer polygon label fitting/collision to\n * the settled frame. Geometry remains smoothly stage-scaled, while expensive\n * point-in-polygon text work no longer repeats at 120 Hz. */\n private glideInProgress = false;\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 /** Current chart's buyer-visible image work. Failures are retained until ready(). */\n private assetGeneration = 0;\n private assetPromises: Promise<void>[] = [];\n private assetErrors: string[] = [];\n private assetCancels = new Set<() => void>();\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 * Ghost-click guard. Konva binds `_pointerup` to mouseup, touchend AND\n * pointerup, so `on('click tap')` is two handlers for one finger tap unless\n * the browser's synthesized compatibility click is suppressed. Konva only\n * suppresses it when the touch lands on a LISTENING SHAPE (Stage.js returns\n * early before its preventDefault() when `!shape || !shape.isListening()`),\n * so a near-miss rescued by nearestSeatToScreen used to fire `tap` (select)\n * then `click` (deselect) 1-3ms apart and net to nothing. With\n * SEAT_TAP_SLOP_PX=14 against a ~12px seat radius, that broken annulus is\n * ~3.7x the area of the seat itself — i.e. most successful mobile taps.\n * `touch-action: none` does NOT suppress compatibility mouse events.\n */\n private lastTapAt = 0;\n\n /**\n * True when this is the browser's synthesized compatibility click following a\n * finger tap we already handled. Discriminates on `e.type` deliberately —\n * `PointerEvent extends MouseEvent`, so an `instanceof MouseEvent` test\n * matches genuine pointer taps too. One shared timestamp across the layer and\n * stage handlers: a tap consumed at the layer must also suppress the ghost at\n * the stage, and only `click` is ever rejected, so bubbling stays intact.\n */\n private isGhostClick(e: KonvaEventObject<Event>): boolean {\n if (e.type === 'tap') { this.lastTapAt = performance.now(); return false; }\n return this.lastTapAt > 0 && performance.now() - this.lastTapAt < GHOST_CLICK_MS;\n }\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.exportMode = options.exportMode === true;\n this.currency = options.currency;\n\n const previousPixelRatio = Konva.pixelRatio;\n if (this.exportMode) this.dpr = 1;\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 if (!this.exportMode) {\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\n this.bgLayer = new Layer({ listening: !this.exportMode });\n this.seatLayer = new Layer({ listening: !this.exportMode });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n // Foreground decor sits above seats but below the hover/focus rings.\n this.fgDecorGroup = new Group({ listening: false });\n this.overlayLayer.add(this.fgDecorGroup);\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 // Export canvases intentionally use one physical pixel per stage pixel.\n // Restore the shared Konva default immediately so a live renderer created\n // while this exporter exists still receives its ordinary device ratio.\n if (this.exportMode) Konva.pixelRatio = previousPixelRatio;\n\n if (!this.exportMode) {\n this.wireInteraction();\n this.startFpsLoop();\n }\n\n if (import.meta.env.DEV && !this.exportMode) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (!this.exportMode && 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.cancelAssetLoads();\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.focusDimOverlay?.destroy();\n this.focusDimOverlay = null;\n // A prior overview may have left the layer bitmap-cached and non-listening.\n // A floor/chart replacement is a fresh live scene: clear both pieces of\n // cache state before adding its seats so direct Konva picking is truthful.\n this.seatLayer.clearCache();\n this.seatLayer.listening(!this.exportMode);\n this.seatLayer.destroyChildren();\n this.unsectionedSeatGroup = null;\n this.labelGroup.destroyChildren();\n this.labelLiftGroups.clear();\n this.fgDecorGroup.destroyChildren();\n this.circleById.clear();\n this.boothDims.clear();\n this.boothLabelById.clear();\n this.seatLabelById.clear();\n this.accessRingById.clear();\n this.accessGlyphById.clear();\n this.freeTextById.clear();\n this.iconNodeById.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.seatIndex = null;\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.viewMode = 'flat';\n this.perspectiveCamera = null;\n this.perspectiveBaseAffine = null;\n this.perspectiveBaseInverse = null;\n this.perspectiveSeatLocal.clear();\n this.perspectiveSeatProjected.clear();\n this.perspectiveSeatDepth.clear();\n this.perspectiveSeatScale.clear();\n this.perspectiveAppliedSeats.clear();\n this.perspectiveBounds = null;\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 this.hoveredId = null;\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 // OV-46: colorblind-safe hues bind to a category's stable KEY (deterministic\n // sorted order), never its position. Reordering categories (buyer legend\n // priority) must never re-shuffle which seat shows which hue.\n this.cbHueByKey.clear();\n [...this.catOrder].sort().forEach((key, i) => {\n this.cbHueByKey.set(key, CB_PALETTE[i % CB_PALETTE.length]);\n });\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, {\n width: obj.width, height: obj.height, rotation: obj.rotation,\n ...(obj.points && obj.points.length >= 3 ? { points: obj.points.map((p) => ({ x: p.x, y: p.y })) } : {}),\n });\n }\n }\n\n this.seats = expandChart(view, {\n // A stacked overview is presentation-only and never opens a seat POV. The\n // per-section renderer below still resolves each object's real floor base.\n floorBaseHeightM: this.stacked ? 0 : this.floorBaseHeightMFor(),\n });\n for (const s of this.seats) {\n this.seatById.set(s.id, s);\n this.statusById.set(s.id, 'free');\n }\n this.seatIndex = buildSeatIndex(this.seats, { seatRadius: this.seatR });\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 // Phase C projection is precomputed once per chart/floor. Entering the view\n // only moves existing Konva hit shapes to these exact anchors; pan/zoom never\n // recomputes pinhole geometry.\n this.buildPerspectiveProjection(view);\n\n this.renderBackground(view);\n // Rows/booths outside an authored section retain one always-visible legacy\n // container. Every section has its own group (created by renderSection), so\n // large venues can omit only whole, safely offscreen sections from paints.\n this.unsectionedSeatGroup = new Group({ listening: !this.exportMode });\n this.seatLayer.add(this.unsectionedSeatGroup);\n this.renderSeats();\n this.buildRowLabelPlan(view);\n // re-add overlay furniture wiped by destroyChildren above (order sets z:\n // labels + foreground decor sit under the hover/focus rings).\n this.overlayLayer.add(this.labelGroup);\n this.overlayLayer.add(this.fgDecorGroup);\n this.overlayLayer.add(this.hoverRing);\n this.overlayLayer.add(this.focusRing);\n\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 {\n ...doc,\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(doc),\n };\n if (this.stacked && doc.floors.length >= 2) {\n return {\n ...stackFloors(doc),\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(doc),\n };\n }\n const floor = doc.floors.find((f) => f.id === this.activeFloorId) ?? doc.floors[0];\n return {\n ...doc,\n objects: floor.objects,\n focalPoint: floor.focalPoint,\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(floor),\n floors: undefined,\n };\n }\n\n /** Physical floor height is authored data; the 900-unit stacked overview\n * spread is presentation-only and must never leak into real 3D geometry. */\n private floorBaseHeightMFor(objectId?: string): number {\n const floors = this.chartDoc?.floors;\n if (!floors?.length) return 0;\n const floorId = this.stacked && objectId\n ? this.objectFloor.get(objectId) ?? this.activeFloorId\n : this.activeFloorId;\n return floors.find((floor) => floor.id === floorId)?.baseHeightM ?? 0;\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 const rendered = this.renderedSeatPoint(seat);\n if (rendered.x < x0 || rendered.x > x1 || rendered.y < y0 || rendered.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 rendered = this.renderedSeatPoint(seat);\n const ring = new Circle({\n x: rendered.x,\n y: rendered.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 const projectionScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seatId) ?? 1\n : 1;\n ring.scale({ x: projectionScale, y: projectionScale });\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 outline = this.viewMode === 'perspective' && section.perspectiveAffine\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline.map((point) => {\n const lift = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n return { x: point.x + lift.x, y: point.y + lift.y };\n });\n const centre = outline.reduce(\n (sum, point) => ({ x: sum.x + point.x, y: sum.y + point.y }),\n { x: 0, y: 0 },\n );\n centre.x /= outline.length;\n centre.y /= outline.length;\n const halo = new Line({\n x: centre.x,\n y: centre.y,\n points: 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 const fromPoint = this.viewMode === 'perspective'\n ? this.perspectiveSeatProjected.get(from.id) ?? from\n : from;\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 candidatePoint = this.viewMode === 'perspective'\n ? this.perspectiveSeatProjected.get(s.id) ?? s\n : s;\n const dx = candidatePoint.x - fromPoint.x;\n const dy = candidatePoint.y - fromPoint.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(this.renderedSeatPoint(seat));\n const projectionScale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(id) ?? 1 : 1;\n this.focusRing.scale({ x: projectionScale, y: projectionScale });\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 rendered = this.renderedSeatPoint(seat);\n const ip = this.viewMode === 'perspective' && this.perspectiveBaseAffine\n ? applyAffine(this.perspectiveBaseAffine, rendered)\n : this.isoT === 0 ? rendered : this.isoForward(rendered);\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.viewMode === 'perspective' && this.perspectiveBounds\n ? this.perspectiveBounds\n : 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 // Picker hosts pass the ExpandedSeat object they received from callbacks.\n // Recognise that richer runtime shape so elevated-seat popovers anchor to\n // the painted seat rather than its pre-lift authoring coordinate. Plain\n // chart points retain the public Point contract and remain unchanged.\n const candidateId = (point as Partial<ExpandedSeat>).id;\n const seat = typeof candidateId === 'string' ? this.seatById.get(candidateId) : undefined;\n if (this.viewMode === 'perspective' && this.perspectiveBaseAffine) {\n const projected = seat\n ? this.perspectiveSeatProjected.get(seat.id) ?? applyAffine(this.perspectiveBaseAffine, point)\n : applyAffine(this.perspectiveBaseAffine, point);\n return { x: projected.x * s + this.stage.x(), y: projected.y * s + this.stage.y() };\n }\n const localPoint = seat ? this.renderedSeatPoint(seat) : point;\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 ? localPoint : this.isoForward(localPoint);\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 // A wheelchair filter can promote its matching glyphs above the normal\n // camera-size threshold, so recompute their visibility and screen-size\n // before repainting opacity for matching/nonmatching seats.\n this.updateAccessGlyphs(this.effScale());\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 // The overview is a bitmap; rebuild it so filter dimming and the promoted\n // wheelchair glyph are visible immediately instead of only after zoom.\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 = !this.exportMode\n && ga.sectionId != null\n && 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(!this.exportMode && !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 const point = this.renderedSeatPoint(seat);\n minX = Math.min(minX, point.x);\n maxX = Math.max(maxX, point.x);\n minY = Math.min(minY, point.y);\n maxY = Math.max(maxY, point.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: RendererViewMode): void {\n if (mode === 'perspective') {\n if (this.viewMode === mode) {\n this.afterViewChange();\n return;\n }\n const resetElevatedSeatGroups = this.viewMode === 'isometric' && this.isoT > 0;\n this.viewMode = mode;\n this.isoTarget = 1;\n this.isoT = 1;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n this.applyPerspective(resetElevatedSeatGroups);\n this.zoomToFit();\n return;\n }\n\n const target = mode === 'isometric' ? 1 : 0;\n const leavingPerspective = this.viewMode === 'perspective';\n this.viewMode = mode;\n this.isoTarget = target;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n if (leavingPerspective) {\n // A non-affine view cannot meaningfully tween through the old affine lean.\n // Snap to the requested endpoint (also the reduced-motion behaviour), then\n // let future flat⇄iso switches use the established 320-ms animation.\n this.isoT = target;\n this.applyIso();\n this.afterViewChange();\n return;\n }\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(): RendererViewMode {\n return this.viewMode;\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 if (this.viewMode === 'perspective' && this.perspectiveBaseAffine) {\n const xScale = Math.hypot(this.perspectiveBaseAffine.a, this.perspectiveBaseAffine.b);\n const yScale = Math.hypot(this.perspectiveBaseAffine.c, this.perspectiveBaseAffine.d);\n return this.stage.scaleX() * Math.min(xScale, yScale);\n }\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 /** Precompute the Phase-C pinhole camera and every exact seat anchor. */\n private buildPerspectiveProjection(view: ChartDoc): void {\n let maxSurfaceHeightWorld = 0;\n for (const seat of this.seats) {\n const surfaceM = Math.max(0, (seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - SEATED_EYE_HEIGHT_M);\n maxSurfaceHeightWorld = Math.max(maxSurfaceHeightWorld, surfaceM * CHART_UNITS_PER_METRE);\n }\n for (const object of view.objects) {\n if (object.type !== 'section') continue;\n maxSurfaceHeightWorld = Math.max(\n maxSurfaceHeightWorld,\n sectionGeometry(object, { floorBaseHeightM: this.floorBaseHeightMFor(object.id) }).height\n * CHART_UNITS_PER_METRE,\n );\n }\n const camera = createPerspectiveCamera(this.bounds, maxSurfaceHeightWorld);\n const base = perspectiveTangentAffine(camera, camera.target);\n const inverse = invertAffine(base);\n this.perspectiveCamera = camera;\n this.perspectiveBaseAffine = base;\n this.perspectiveBaseInverse = inverse;\n this.perspectiveSeatLocal.clear();\n this.perspectiveSeatProjected.clear();\n this.perspectiveSeatDepth.clear();\n this.perspectiveSeatScale.clear();\n this.perspectiveBounds = null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const seat of this.seats) {\n const surfaceM = Math.max(0, (seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - SEATED_EYE_HEIGHT_M);\n const projected = projectPerspectivePoint(camera, seat, surfaceM * CHART_UNITS_PER_METRE);\n const point = { x: projected.x, y: projected.y };\n this.perspectiveSeatProjected.set(seat.id, point);\n this.perspectiveSeatLocal.set(seat.id, applyAffine(inverse, point));\n this.perspectiveSeatDepth.set(seat.id, projected.depth);\n this.perspectiveSeatScale.set(seat.id, projected.scale);\n minX = Math.min(minX, projected.x);\n minY = Math.min(minY, projected.y);\n maxX = Math.max(maxX, projected.x);\n maxY = Math.max(maxY, projected.y);\n }\n for (const point of [\n { x: this.bounds.x, y: this.bounds.y },\n { x: this.bounds.x + this.bounds.width, y: this.bounds.y },\n { x: this.bounds.x + this.bounds.width, y: this.bounds.y + this.bounds.height },\n { x: this.bounds.x, y: this.bounds.y + this.bounds.height },\n ]) {\n const projected = projectPerspectivePoint(camera, point, 0);\n minX = Math.min(minX, projected.x);\n minY = Math.min(minY, projected.y);\n maxX = Math.max(maxX, projected.x);\n maxY = Math.max(maxY, projected.y);\n }\n const pad = Math.max(24, this.seatR * 3);\n this.perspectiveBounds = Number.isFinite(minX)\n ? { x: minX - pad, y: minY - pad, width: Math.max(1, maxX - minX + pad * 2), height: Math.max(1, maxY - minY + pad * 2) }\n : null;\n }\n\n /** Apply an affine to a Konva container while keeping `pivot` fixed logically. */\n private setContainerAffine(node: Group | Layer, affine: Affine2D, pivot: Point): void {\n const decomposed = decomposeAffineLinear(affine);\n node.offset(pivot);\n node.position(applyAffine(affine, pivot));\n node.rotation(decomposed.rotationDeg);\n node.scale({ x: decomposed.scaleX, y: decomposed.scaleY });\n node.skewX(decomposed.skewX);\n node.skewY(0);\n }\n\n private resetContainerTransform(node: Group | Layer): void {\n node.position({ x: 0, y: 0 });\n node.offset({ x: 0, y: 0 });\n node.scale({ x: 1, y: 1 });\n node.rotation(0);\n node.skewX(0);\n node.skewY(0);\n }\n\n /** Exact raked surface height used for the bounded section tangent plane. */\n private sectionSurfaceHeight(section: SectionRender, point: Point): number {\n const radial = Math.hypot(point.x - section.surfaceFocal.x, point.y - section.surfaceFocal.y);\n const depth = Math.max(0, radial - section.frontDistanceWorld);\n return section.liftWorld + depth * Math.tan((section.rakeDeg * Math.PI) / 180);\n }\n\n /** Desired perspective-space point for a section surface, before Stage pan/zoom. */\n private projectedSectionPoint(section: SectionRender, point: Point): Point {\n return section.perspectiveAffine\n ? applyAffine(section.perspectiveAffine, point)\n : applyAffine(this.perspectiveBaseAffine!, point);\n }\n\n /** Shared-layer local point which the ground affine paints at `projected`. */\n private perspectiveLocalPoint(projected: Point): Point {\n return this.perspectiveBaseInverse ? applyAffine(this.perspectiveBaseInverse, projected) : projected;\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 `liftWorld × isoT` world units\n * (= inverse-linear of the pure vertical lift). Zero at isoT=0. `liftWorld` is\n * the section's resolved real height in world units (Phase B1).\n */\n private isoLiftLocal(liftWorld: number): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const delta = liftWorld * this.isoT;\n return { x: -(delta / sg) * Math.sin(th), y: -(delta / sg) * Math.cos(th) };\n }\n\n /** Restore projection layers to identity (flat) — byte-for-byte the original.\n * `seatLayer` can be skipped when entering perspective from flat: assigning a\n * top-level transform invalidates all 14k descendant absolute transforms even\n * while the semantic overview keeps that layer fully transparent. */\n private resetLayerTransforms(includeSeatLayer = true): void {\n const layers = includeSeatLayer\n ? [this.bgLayer, this.seatLayer, this.overlayLayer]\n : [this.bgLayer, this.overlayLayer];\n for (const layer of layers) {\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 /** Restore section-owned containers before applying another projection. */\n private resetSectionProjection(resetSeatGroups = true): void {\n for (const section of this.sections) {\n this.resetContainerTransform(section.rootGroupBg);\n this.resetContainerTransform(section.liftGroupBg);\n if (resetSeatGroups) this.resetContainerTransform(section.liftGroupSeat);\n section.rootGroupBg.zIndex(section.bgZIndex);\n if (resetSeatGroups) section.liftGroupSeat.zIndex(section.seatZIndex);\n const labelGroup = this.labelLiftGroups.get(section.id);\n if (labelGroup && resetSeatGroups) this.resetContainerTransform(labelGroup);\n section.perspectiveAffine = undefined;\n section.perspectiveCorrection = undefined;\n section.perspectiveDepth = undefined;\n }\n }\n\n /** Move native seat/booth hit shapes to or from their exact pinhole anchors. */\n private applyExactSeatAnchors(perspective: boolean, seatIds?: Iterable<string>): void {\n const seats = seatIds\n ? [...seatIds].map((id) => this.seatById.get(id)).filter((seat): seat is ExpandedSeat => !!seat)\n : perspective\n ? this.seats\n : [...this.perspectiveAppliedSeats]\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat);\n for (const seat of seats) {\n if (perspective && this.perspectiveAppliedSeats.has(seat.id)) continue;\n // Seat-layer nodes use absolute projected coordinates instead of a\n // transformed 14k-descendant Layer. Overlay nodes continue to use the\n // inverse-base local point and are projected by overlayLayer itself.\n const point = perspective ? this.perspectiveSeatProjected.get(seat.id) ?? seat : seat;\n const scale = perspective ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n const shape = this.circleById.get(seat.id);\n shape?.position(point);\n shape?.scale({ x: scale, y: scale });\n const ring = this.accessRingById.get(seat.id);\n ring?.position(point);\n ring?.scale({ x: scale, y: scale });\n const glyph = this.accessGlyphById.get(seat.id);\n if (glyph) {\n const baseGlyphScale = (this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX;\n glyph.position(point);\n glyph.scale({ x: baseGlyphScale * scale, y: baseGlyphScale * scale });\n }\n const boothLabel = this.boothLabelById.get(seat.id);\n boothLabel?.position(point);\n boothLabel?.scale({ x: scale, y: scale });\n if (perspective) this.perspectiveAppliedSeats.add(seat.id);\n }\n if (!perspective) this.perspectiveAppliedSeats.clear();\n }\n\n /**\n * Phase C projected 2.5D. Seat/booth anchors are exact pinhole projections;\n * section top surfaces use one explicitly bounded tangent plane per authored\n * section. Native Konva shapes move with the anchors, so direct hit testing is\n * the same graph that paints the buyer-visible unit.\n */\n private applyPerspective(resetElevatedSeatGroups = true): void {\n const camera = this.perspectiveCamera;\n const base = this.perspectiveBaseAffine;\n const inverse = this.perspectiveBaseInverse;\n if (!camera || !base || !inverse) return;\n\n const lazySectionSeats = this.seats.length > 2_500 && this.sections.length > 0;\n // A large sectioned overview already owns a flat cached seat bitmap, but\n // the section LOD makes seatLayer fully transparent. Keep that dormant\n // bitmap until the camera reaches live seats: rebuilding 14k invisible\n // descendants during this mode switch costs ~95 ms and paints no pixels.\n if (this.cached && !lazySectionSeats) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n }\n this.resetLayerTransforms(resetElevatedSeatGroups);\n // Flat groups are already identity. Re-setting an identity transform on a\n // group with hundreds of children invalidates every descendant transform;\n // across 14k seats that alone blows the two-frame gate. Only an isometric\n // source view needs its elevated seat-group offsets explicitly cleared.\n this.resetSectionProjection(resetElevatedSeatGroups);\n // Background/overlay geometry benefits from one bounded tangent affine.\n // Exact native seat and booth nodes are placed directly at their pinhole\n // anchors, keeping hit testing exact without invalidating the full seat\n // graph through a top-level Layer transform.\n for (const layer of [this.bgLayer, this.overlayLayer]) {\n this.setContainerAffine(layer, base, camera.target);\n }\n this.perspectiveAppliedSeats.clear();\n // The semantic overview paints section shells and sets seatLayer opacity to\n // zero, so touching 14k invisible nodes here would create a ~200 ms toggle\n // stall for no pixels. Small charts stay eager; large sectioned charts move\n // each native hit shape exactly when its section reaches the live-seat rung.\n if (!lazySectionSeats) this.applyExactSeatAnchors(true);\n\n for (const section of this.sections) {\n const heightAt = (point: Point): number => this.sectionSurfaceHeight(section, point);\n const desired = perspectiveTangentAffine(camera, section.centroid, heightAt);\n const correction = composeAffine(inverse, desired);\n section.perspectiveAffine = desired;\n section.perspectiveCorrection = correction;\n section.perspectiveDepth = projectPerspectivePoint(\n camera,\n section.centroid,\n heightAt(section.centroid),\n ).depth;\n // Only the top shell uses the tangent plane. Seats remain in the root\n // section group at their exact precomputed anchors.\n this.setContainerAffine(section.liftGroupBg, correction, section.centroid);\n\n for (let index = 0; index < section.sideFaces.length; index++) {\n const p0 = section.outline[index];\n const p1 = section.outline[(index + 1) % section.outline.length];\n const base0 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p0, 0));\n const base1 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p1, 0));\n const top1 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p1, heightAt(p1)));\n const top0 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p0, heightAt(p0)));\n section.sideFaces[index].points([\n base0.x, base0.y,\n base1.x, base1.y,\n top1.x, top1.y,\n top0.x, top0.y,\n ]);\n section.sideFaces[index].opacity(0.9);\n }\n }\n\n // Far sections paint first; near sections and their exact hit shapes win an\n // overlap. Sorting O(section count), never O(seat count), on view entry only.\n const farToNear = [...this.sections].sort(\n (left, right) => (right.perspectiveDepth ?? 0) - (left.perspectiveDepth ?? 0),\n );\n for (const section of farToNear) {\n section.rootGroupBg.moveToTop();\n section.liftGroupSeat.moveToTop();\n }\n this.unsectionedSeatGroup?.moveToTop();\n\n this.syncSeatOverlayPositions();\n // setViewMode() fits the projected bounds immediately after this method.\n // Running viewport culling against the *old flat camera* would eagerly move\n // most 14k native seats even though the fitted overview hides seatLayer.\n if (!lazySectionSeats) this.updateSeatGroupVisibility();\n this.bgLayer.batchDraw();\n this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\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 this.resetSectionProjection();\n this.applyExactSeatAnchors(false);\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 this.updateSeatGroupVisibility();\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.liftWorld <= 0) continue;\n const off = this.isoLiftLocal(sec.liftWorld);\n sec.liftGroupBg?.position(off);\n sec.liftGroupSeat.position(off);\n this.labelLiftGroups.get(sec.id)?.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 this.syncSeatOverlayPositions();\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cancelAssetLoads();\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 if (this.exportMode) {\n return this.theme.fontFamily?.toLowerCase().includes('jetbrains')\n ? 'JetBrains Mono, monospace'\n : 'Inter, sans-serif';\n }\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.unsectionedSeatGroup ?? this.seatLayer;\n }\n\n /** True when a section belongs to the active logical section/zone focus. */\n private sectionMatchesFocus(section: SectionRender): boolean {\n const focus = this.focusedSectionId;\n return focus == null\n || section.id === focus\n || section.logicalId === focus\n || section.zone === focus;\n }\n\n /** Visual opacity after the section-focus overlay is composed. */\n private focusedSeatOpacity(id: string, localOpacity: number): number {\n if (!this.focusedSectionId) return localOpacity;\n const section = this.seatSection.get(id);\n return localOpacity * (section && this.sectionMatchesFocus(section) ? 1 : FOCUS_DIM_OPACITY);\n }\n\n /** Project a section outline through elevation + the active affine view and\n * then into viewport pixels. The result is conservative (AABB), so a visible\n * section is never clipped even for rotated or isometric outlines. */\n private sectionScreenBounds(section: SectionRender): { x: number; y: number; width: number; height: number } {\n if (this.viewMode === 'perspective' && section.perspectiveAffine) {\n const scale = this.stage.scaleX();\n const stageX = this.stage.x();\n const stageY = this.stage.y();\n return polyBounds(section.outline.map((point) => {\n const projected = this.projectedSectionPoint(section, point);\n return { x: projected.x * scale + stageX, y: projected.y * scale + stageY };\n }));\n }\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n const scale = this.stage.scaleX();\n const stageX = this.stage.x();\n const stageY = this.stage.y();\n return polyBounds(section.outline.map((point) => {\n const local = { x: point.x + offset.x, y: point.y + offset.y };\n const projected = this.isoT === 0 ? local : this.isoForward(local);\n return { x: projected.x * scale + stageX, y: projected.y * scale + stageY };\n }));\n }\n\n /** Hide only section groups wholly outside a padded viewport at the live-seat\n * rung. Overview caching always restores all groups first, so panning a\n * cached whole-venue bitmap can never reveal missing inventory. */\n private updateSeatGroupVisibility(): void {\n const liveSeats = this.exportMode || this.effScale() >= CACHE_THRESHOLD;\n // During a large-venue focus glide, transient camera rectangles can sweep\n // across thousands of seats that will be offscreen at the endpoint. Keep\n // the semantic shells visible through the motion and project native seats\n // once, for the settled viewport, rather than generating several expensive\n // intermediate scene paints that buyers never interact with.\n const deferPerspectiveSeatReveal = this.viewMode === 'perspective'\n && this.glideInProgress\n && this.seats.length > 2_500;\n const padding = 96;\n const width = this.stage.width();\n const height = this.stage.height();\n for (const section of this.sections) {\n let visible = true;\n if (liveSeats) {\n const bounds = this.sectionScreenBounds(section);\n visible = bounds.x + bounds.width >= -padding\n && bounds.y + bounds.height >= -padding\n && bounds.x <= width + padding\n && bounds.y <= height + padding;\n if (visible && this.viewMode === 'perspective' && !deferPerspectiveSeatReveal) {\n this.applyExactSeatAnchors(true, section.memberIds);\n }\n }\n section.liftGroupSeat.setViewportCulled(!visible);\n const labelGroup = this.labelLiftGroups.get(section.id);\n labelGroup?.setViewportCulled(!visible);\n }\n if (this.unsectionedSeatGroup && !this.unsectionedSeatGroup.visible()) {\n this.unsectionedSeatGroup.visible(true);\n }\n if (liveSeats && this.viewMode === 'perspective' && !deferPerspectiveSeatReveal) {\n this.applyExactSeatAnchors(true, this.seats\n .filter((seat) => !this.seatSection.has(seat.id))\n .map((seat) => seat.id));\n }\n }\n\n /** Seats worth considering for viewport labels. Section culling is a safe\n * coarse index; the later screen test remains the exact filter. */\n private visibleSeatCandidates(): ExpandedSeat[] {\n if (!this.sections.length) return this.seats;\n const candidates: ExpandedSeat[] = [];\n for (const section of this.sections) {\n if (section.liftGroupSeat.isViewportCulled()) continue;\n for (const id of section.memberIds) {\n const seat = this.seatById.get(id);\n if (seat) candidates.push(seat);\n }\n }\n for (const seat of this.seats) {\n if (!this.seatSection.has(seat.id)) candidates.push(seat);\n }\n return candidates;\n }\n\n private seatViewportCulled(id: string): boolean {\n return this.seatSection.get(id)?.liftGroupSeat.isViewportCulled() ?? false;\n }\n\n /** Local world coordinate at which an elevated seat is actually painted for\n * the current iso tween. Flat seats and the 2D endpoint are unchanged. */\n private renderedSeatPoint(seat: ExpandedSeat): Point {\n if (this.viewMode === 'perspective') return this.perspectiveSeatLocal.get(seat.id) ?? seat;\n const section = this.seatSection.get(seat.id);\n if (!section || section.liftWorld <= 0 || this.isoT === 0) return seat;\n const offset = this.isoLiftLocal(section.liftWorld);\n return { x: seat.x + offset.x, y: seat.y + offset.y };\n }\n\n /** Overlay labels mirror the seat-layer lift without an O(seats) per-frame\n * rewrite. The groups are rebuilt with the zoom-dependent label set. */\n private seatLabelContainer(id: string): Group {\n const section = this.seatSection.get(id);\n if (!section) return this.labelGroup;\n let group = this.labelLiftGroups.get(section.id);\n if (!group) {\n group = new ViewportGroup({\n listening: false,\n });\n group.setViewportCulled(section.liftGroupSeat.isViewportCulled());\n group.position(this.viewMode === 'perspective'\n ? { x: 0, y: 0 }\n : this.isoLiftLocal(section.liftWorld));\n this.labelGroup.add(group);\n this.labelLiftGroups.set(section.id, group);\n }\n return group;\n }\n\n /** Shared overlay furniture is not parented to section lift groups, so keep\n * the small transient set aligned explicitly. Selection is capped in buyer\n * mode, making this constant-sized work during the iso tween. */\n private syncSeatOverlayPositions(): void {\n if (this.hoveredId) {\n const seat = this.seatById.get(this.hoveredId);\n if (seat) {\n this.hoverRing.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n this.hoverRing.scale({ x: scale, y: scale });\n }\n }\n if (this.focusedId) {\n const seat = this.seatById.get(this.focusedId);\n if (seat) {\n this.focusRing.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n this.focusRing.scale({ x: scale, y: scale });\n }\n }\n for (const [id, marker] of this.selectionMarkers) {\n const seat = this.seatById.get(id);\n if (seat) {\n marker.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n marker.scale({ x: scale, y: scale });\n }\n }\n }\n\n private renderSeats(): void {\n // Stable far→near insertion makes exact perspective anchors occlude in the\n // camera-correct order without an O(seats) reorder when the buyer toggles\n // the view. Flat charts rarely overlap units; id is the deterministic tie.\n const paintOrder = [...this.seats].sort((left, right) =>\n (this.perspectiveSeatDepth.get(right.id) ?? 0) - (this.perspectiveSeatDepth.get(left.id) ?? 0));\n for (const seat of paintOrder) {\n if (seat.kind === 'booth') {\n this.renderBoothUnit(seat);\n continue;\n }\n const target = this.seatContainer(seat.id);\n // An empty wheelchair bay is still one sellable inventory unit, but its\n // square footprint must never masquerade as a fixed chair. `skip` seats\n // never reach this loop at all, preserving the three distinct states.\n const c: Shape = seat.wheelchairSpaceType === 'no-seat'\n ? new Rect({\n x: seat.x,\n y: seat.y,\n width: this.seatR * 2,\n height: this.seatR * 2,\n offsetX: this.seatR,\n offsetY: this.seatR,\n cornerRadius: 2,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n })\n : 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 // Every accommodation gets its colour-coded ring. The centred ♿ path is\n // reserved for actual wheelchair provision; CART, hearing and other\n // accommodations must never masquerade as wheelchair places.\n if (seat.accessible) {\n if (seat.wheelchairSpaceType !== 'no-seat') {\n const ring = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR + 1.5,\n stroke: accessibilityRingColor(seat.accessibility),\n strokeWidth: 2.5,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.accessRingById.set(seat.id, ring);\n target.add(ring);\n }\n if (seat.accessibility?.includes('wheelchair') && accessGlyphPath(seat.accessibility)) {\n const glyph = this.buildAccessGlyph(seat, typeof c.fill() === 'string' ? (c.fill() as string) : '');\n this.accessGlyphById.set(seat.id, glyph);\n target.add(glyph);\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 let labelX = seat.x;\n let labelY = seat.y;\n let node: Shape;\n if (dims.points && dims.points.length >= 3) {\n // Custom outline: local points relative to the booth centre (seat.x/y),\n // drawn as one closed unit. Label sits at the polygon centroid.\n node = new Line({\n x: seat.x,\n y: seat.y,\n points: dims.points.flatMap((p) => [p.x, p.y]),\n closed: true,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n labelX = seat.x + dims.points.reduce((a, p) => a + p.x, 0) / dims.points.length;\n labelY = seat.y + dims.points.reduce((a, p) => a + p.y, 0) / dims.points.length;\n } else {\n node = 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 }\n node.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, node);\n target.add(node);\n\n const t = new Text({\n x: labelX,\n y: labelY,\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.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(node, seat.id);\n }\n\n /**\n * Build the centred accessibility glyph for a seat. Sized relative to the seat\n * radius (so it always fills the marker at any zoom) and given a contrast-aware\n * fill against the seat's paint — recomputed per state in {@link paintSeat}.\n */\n private buildAccessGlyph(seat: ExpandedSeat, seatFill: string): Path {\n const k = (this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX;\n return new Path({\n x: seat.x,\n y: seat.y,\n // Non-null: buildAccessGlyph is only called for seats the gate confirmed\n // resolve to a primary-accommodation glyph.\n data: accessGlyphPath(seat.accessibility ?? []) ?? '',\n offsetX: ACCESS_GLYPH_VIEWBOX / 2,\n offsetY: ACCESS_GLYPH_VIEWBOX / 2,\n scaleX: k,\n scaleY: k,\n fill: accessGlyphInk(seatFill),\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n }\n\n /**\n * Keep physical wheelchair provision readable in screen space at every map\n * LOD. The active Wheelchair filter promotes it further. Iterates the small\n * wheelchair-seat set, never the full node graph.\n */\n private updateAccessGlyphs(scale: number): void {\n if (!this.accessGlyphById.size) return;\n for (const [id, glyph] of this.accessGlyphById) {\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(id) ?? 1\n : 1;\n const baseScale = ((this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX) * perspectiveScale;\n const emphasized = this.accessGlyphFilterEmphasized(id);\n const minimumScreenPx = emphasized\n ? FILTERED_WHEELCHAIR_GLYPH_MIN_PX\n : WHEELCHAIR_GLYPH_MIN_PX;\n const glyphScale = Math.max(\n baseScale,\n minimumScreenPx / (ACCESS_GLYPH_VIEWBOX * Math.max(scale, 0.001)),\n );\n glyph.scale({ x: glyphScale, y: glyphScale });\n glyph.visible(this.accessGlyphShouldShow(id));\n }\n }\n\n /** True only for a physical wheelchair provision matching an active buyer filter. */\n private accessGlyphFilterEmphasized(id: string): boolean {\n const seat = this.seatById.get(id);\n const filter = this.accessFilter;\n return !!seat\n && filter !== null\n && !!seat.accessibility?.includes('wheelchair')\n && (filter.length === 0 || filter.includes('wheelchair'))\n && seatMatchesAccess(seat, filter);\n }\n\n private accessGlyphShouldShow(id: string): boolean {\n return this.accessGlyphById.has(id) && this.accessGlyphEligible(id);\n }\n\n /**\n * Whether an accessible seat's glyph should show for its current status. It is\n * hidden on seats a buyer cannot take (sold, or another buyer's hold) where the\n * overlay status cue (diagonal mark / lock) carries the state instead — mirrors\n * the `unavailable` test in {@link updateLabels} so the two never collide.\n */\n private accessGlyphEligible(id: string): boolean {\n const status = this.statusById.get(id) ?? 'free';\n if (status === 'booked') return false;\n if (status === 'held' && !this.ownedHold.has(id) && !this.opts.manageMode) return false;\n return true;\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 // Key-based (OV-46): the hue follows the category's identity, not its order.\n return this.cbHueByKey.get(categoryKey) ?? CB_PALETTE[0];\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), AUTHORED_LABEL_MIN_CONTRAST);\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 // The empty bay keeps normal status/category paint for booking truth, while\n // its dashed square boundary supplies a non-colour cue that it is space for\n // a wheelchair rather than a physical chair.\n if (seat.wheelchairSpaceType === 'no-seat' && status === 'free') {\n c.stroke(accessibilityRingColor(seat.accessibility));\n c.strokeWidth(selected ? 3 : 2);\n c.dash([3, 2]);\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 // Section-focus dimming belongs to the section's parent Group. Keeping it\n // out of this per-seat paint path avoids 14k node mutations on focus.\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 // Keep the accessibility markers composed with the seat's final paint: the\n // glyph re-contrasts against the current fill (legible on any state incl.\n // colorblind hues), and both markers inherit the seat's opacity so filter/\n // focus dimming carries through instead of leaving a bright ring behind.\n const accessGlyph = this.accessGlyphById.get(id);\n if (accessGlyph) {\n const fill = c.fill();\n accessGlyph.fill(accessGlyphInk(typeof fill === 'string' ? fill : ''));\n accessGlyph.opacity(c.opacity());\n accessGlyph.visible(this.accessGlyphShouldShow(id));\n }\n this.accessRingById.get(id)?.opacity(c.opacity());\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.bgLayer.batchDraw();\n this.overlayLayer.batchDraw();\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.focusDimOverlay?.destroy();\n this.focusDimOverlay = null;\n this.bgLayer.batchDraw();\n this.overlayLayer.batchDraw();\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 const perspective = this.viewMode === 'perspective' && section.perspectiveAffine;\n const outline = perspective\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline;\n const holes = perspective\n ? section.holes.map((hole) => hole.map((point) =>\n this.perspectiveLocalPoint(this.projectedSectionPoint(section, point))))\n : section.holes;\n backdrop.add(polygonWithHolesShape(outline, holes, {\n fill: FOCUS_BACKDROP_FILL,\n stroke: rgba('#ffffff', 0.1),\n strokeWidth: 1,\n listening: false,\n }, perspective ? undefined : 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 this.drawFocusDimOverlay(sections);\n }\n\n /** Dim everything outside the active section with one paint-only shape. Group\n * opacity would make Konva recursively invalidate absolute-opacity caches on\n * all 14k descendants. The cut-out follows the live elevation offset and is\n * non-listening, so direct seat hit-testing is unchanged. */\n private drawFocusDimOverlay(sections: SectionRender[]): void {\n this.focusDimOverlay?.destroy();\n const span = Math.max(this.bounds.width, this.bounds.height, 1);\n const padding = span * 4 + 1_000;\n const outer: Point[] = [\n { x: this.bounds.x - padding, y: this.bounds.y - padding },\n { x: this.bounds.x + this.bounds.width + padding, y: this.bounds.y - padding },\n { x: this.bounds.x + this.bounds.width + padding, y: this.bounds.y + this.bounds.height + padding },\n { x: this.bounds.x - padding, y: this.bounds.y + this.bounds.height + padding },\n ];\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 overlay = new Shape({\n fill: this.canvasBackground,\n opacity: 1 - FOCUS_DIM_OPACITY,\n listening: false,\n perfectDrawEnabled: false,\n sceneFunc: (context, shape) => {\n const polygonPath = (points: Point[]): void => {\n if (!points.length) return;\n context.moveTo(points[0].x, points[0].y);\n for (let index = 1; index < points.length; index++) context.lineTo(points[index].x, points[index].y);\n context.closePath();\n };\n context.beginPath();\n polygonPath(outer);\n for (const section of sections) {\n const hole = this.viewMode === 'perspective' && section.perspectiveAffine\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline.map((point) => {\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n return { x: point.x + offset.x, y: point.y + offset.y };\n });\n // Outer is clockwise in canvas coordinates; reverse same-winding holes\n // so the default non-zero fill rule cuts a transparent focus window.\n polygonPath(signedArea(hole) > 0 ? [...hole].reverse() : hole);\n }\n context.fillStrokeShape(shape);\n },\n });\n this.overlayLayer.add(overlay);\n overlay.moveToTop();\n for (const marker of this.selectionMarkers.values()) marker.moveToTop();\n this.hoverRing.moveToTop();\n this.focusRing.moveToTop();\n this.focusDimOverlay = overlay;\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 const buyerBackground = buyerBackgroundImage(doc);\n if (buyerBackground) this.renderBackgroundImage(buyerBackground);\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 /**\n * Track an image through decode without ever leaving a rejected promise\n * unobserved. Ordinary picker rendering remains best-effort; export ready()\n * turns the retained failures into one actionable error.\n */\n private trackAssetImage(\n image: HTMLImageElement,\n source: string,\n label: string,\n onReady: () => void,\n ): void {\n const generation = this.assetGeneration;\n if (/^https?:\\/\\//i.test(source)) image.crossOrigin = 'anonymous';\n const work = new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n this.assetCancels.delete(cancel);\n resolve();\n };\n const cancel = () => {\n image.onload = null;\n image.onerror = null;\n try {\n image.removeAttribute('src');\n image.src = '';\n } catch {\n // Releasing the renderer must not be blocked by an Image implementation.\n }\n finish();\n };\n this.assetCancels.add(cancel);\n image.onload = () => {\n if (!this.exportMode) {\n if (generation === this.assetGeneration) onReady();\n finish();\n return;\n }\n const decoded = typeof image.decode === 'function' ? image.decode() : Promise.resolve();\n void decoded\n .then(() => {\n if (generation === this.assetGeneration) onReady();\n })\n .catch(() => {\n if (generation === this.assetGeneration) this.assetErrors.push(`${label} could not be decoded.`);\n })\n .finally(finish);\n };\n image.onerror = () => {\n if (generation === this.assetGeneration) this.assetErrors.push(`${label} could not be loaded.`);\n finish();\n };\n image.src = source;\n });\n this.assetPromises.push(work);\n }\n\n /** Cancel and release every image retained by the previous chart/export. */\n private cancelAssetLoads(): void {\n this.assetGeneration++;\n for (const cancel of [...this.assetCancels]) cancel();\n this.assetCancels.clear();\n this.assetPromises = [];\n this.assetErrors = [];\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 this.trackAssetImage(img, bg.url, 'Buyer background image', () => {\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 }\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 // Foreground decor rides the overlay layer (above every seat); background\n // decor stays on bgLayer, beneath sections and seats.\n if (obj.layer === 'foreground') this.fgDecorGroup.add(node);\n else this.bgLayer.add(node);\n this.trackAssetImage(img, obj.href, `Decor image “${obj.label || obj.id}”`, () => {\n const layer = node.getLayer();\n if (!layer) return; // chart swapped out before the image loaded\n layer.batchDraw();\n });\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.displayLabel ?? 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 // Modern venue icons draw as a single-color vector Path — pixel-identical to\n // the Designer. Legacy emoji icons (no iconKey) and captions fall through to\n // the Konva.Text path below, so old charts render unchanged.\n const iconPath = obj.semanticKind === 'icon' ? venueIconPath(obj.iconKey) : undefined;\n if (iconPath) {\n const scale = obj.fontSize / VENUE_ICON_VIEWBOX;\n const iconNode = new Path({\n x: obj.position.x,\n y: obj.position.y,\n data: iconPath,\n rotation: obj.rotation,\n scaleX: scale,\n scaleY: scale,\n stroke: stateAwareBookableLabelInk(background, preferredInk),\n strokeWidth: VENUE_ICON_STROKE,\n lineCap: 'round',\n lineJoin: 'round',\n fillEnabled: false,\n listening: false,\n perfectDrawEnabled: false,\n });\n this.iconNodeById.set(obj.id, { node: iconNode, fontSize: obj.fontSize });\n this.bgLayer.add(iconNode);\n return;\n }\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 fontStyle: konvaFontStyle(obj.bold, obj.italic, 'normal'),\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: obj.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 const isOpenPath = obj.kind === 'line' || obj.kind === 'polyline';\n // Author outline wins; stage keeps its lit edge; open paths always paint a\n // visible default stroke; reference focals keep their palette outline.\n const stroke = obj.stroke?.color\n ?? (isStage ? lighten(fill, 0.28) : referenceFocal ? palette.focalStroke : isOpenPath ? '#9aa3b5' : undefined);\n // Stage: darker at the back (min-y), brighter toward the audience edge (max-y).\n const strokeWidth = obj.stroke?.width ?? (isStage ? 1 : referenceFocal ? 2 : isOpenPath ? 2 : 0);\n const opacity = obj.opacity != null ? clamp(obj.opacity, 0.1, 1) : 1;\n let cx = 0;\n let cy = 0;\n if (isOpenPath && obj.points && obj.points.length >= 2) {\n // Open path: stroke-only, never filled, never hit-tested.\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 lineStyle = resolvedShapeLineStyle(obj);\n const arrow = shapeArrowMetrics(strokeWidth);\n const path = new Arrow({\n points: obj.points.flatMap((p) => [p.x, p.y]),\n closed: false,\n x: cx,\n y: cy,\n offsetX: cx,\n offsetY: cy,\n rotation: obj.rotation ?? 0,\n stroke,\n fill: stroke,\n strokeWidth,\n opacity,\n lineCap: lineStyle.lineCap,\n lineJoin: lineStyle.lineJoin,\n pointerAtBeginning: lineStyle.startEnding === 'arrow',\n pointerAtEnding: lineStyle.endEnding === 'arrow',\n ...arrow,\n listening: false,\n name: 'buyer-shape-open-path',\n });\n path.setAttr('shapeObjectId', obj.id);\n this.bgLayer.add(path);\n } else 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: clamp(obj.cornerRadius ?? 4, 0, Math.min(obj.width, obj.height) / 2),\n opacity,\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, opacity, 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, opacity, 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 cornerRadius: obj.cornerRadius,\n });\n poly.setAttr('gaId', obj.id);\n poly.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.isGhostClick(e)) return; // a double onGAClick would double-open the qty picker\n this.opts.onGAClick?.(obj.id);\n });\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.displayLabel ?? 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.displayLabel ?? 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 const bounds = polyBounds(obj.outline);\n const candidates = this.seatIndex\n ? queryRect(this.seatIndex, bounds)\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat)\n : this.seats;\n for (const seat of candidates) {\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 // Every section gets a seat group even at height zero: that parent is the\n // safe unit for production viewport culling on very large live-seat scenes.\n // Side faces (a zone-coloured quad per outline edge) extrude only as isoT rises.\n const elevation = sectionElevationTier(obj.elevation);\n // Real iso lift (Phase B1): authored height when present, else the elevation\n // tier fallback — which reproduces the legacy `elevation × LIFT_PER_STEP`.\n const geometry = sectionGeometry(obj, {\n floorBaseHeightM: this.floorBaseHeightMFor(obj.id),\n });\n const liftWorld = geometry.height * CHART_UNITS_PER_METRE;\n const rootGroupBg = new Group({ listening: false });\n this.bgLayer.add(rootGroupBg);\n const liftGroupBg = new Group({ listening: false });\n rootGroupBg.add(liftGroupBg);\n const liftGroupSeat = new ViewportGroup({ listening: true });\n this.seatLayer.add(liftGroupSeat);\n const sideFaces: Line[] = [];\n if (liftWorld > 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 rootGroupBg.add(face); // behind the top-surface group\n }\n }\n // Top surface must paint above its side faces in both iso and perspective.\n liftGroupBg.moveToTop();\n const bgTarget: Group = liftGroupBg;\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,\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 labelArea: polygonNetArea(obj.outline, obj.holes),\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 liftWorld,\n rakeDeg: geometry.rake,\n surfaceFocal: memberIds.length\n ? { ...(this.seatById.get(memberIds[0])?.focalPoint ?? this.isoCentre) }\n : { ...(this.chartDoc?.focalPoint ?? this.isoCentre) },\n frontDistanceWorld: 0,\n rootGroupBg,\n bgZIndex: rootGroupBg.zIndex(),\n seatZIndex: liftGroupSeat.zIndex(),\n liftGroupBg,\n liftGroupSeat,\n sideFaces,\n };\n const surfaceCandidates = memberIds\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat);\n const distanceCandidates: Point[] = surfaceCandidates.length ? surfaceCandidates : obj.outline;\n sec.frontDistanceWorld = Math.min(...distanceCandidates.map((point) => Math.hypot(\n point.x - sec.surfaceFocal.x,\n point.y - sec.surfaceFocal.y,\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 availability shading + retained availability text. */\n private refreshSectionFill(sec: SectionRender): void {\n sec.blockPoly.fill(this.sectionBlockFill(sec));\n // The overview shell itself carries the sold-out/nearly-gone signal; this\n // text stays for the focused/detail + a11y layers (kept hidden on the shell).\n sec.subLabel.text(\n this.sectionAvailabilityState(sec) === 'sold-out'\n ? t('map.soldOut')\n : t('map.seatsLeft', { count: sec.free }),\n );\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 /** Resolve the four-bucket overview availability state for a section (OV-69).\n * `closed` (operator) outranks live availability; the availability buckets\n * only apply to seated sections (GA-only shells have no seat capacity here). */\n private sectionAvailabilityState(sec: SectionRender): SectionAvailabilityState {\n if (this.isSectionClosed(sec)) return 'closed';\n if (sec.total <= 0) return 'normal';\n if (sec.free <= 0) return 'sold-out';\n if (sec.free <= sec.total * SECTION_NEARLY_GONE_RATIO) return 'nearly-gone';\n return 'normal';\n }\n\n /** Overview shells stay neutral except for the bounded availability shading\n * (nearly-gone / sold-out) and the operator `closed` slab — never category\n * or price paint, which is deferred to section focus/seat detail. */\n private sectionBlockFill(sec: SectionRender): string {\n return overviewStateFill(overviewPalette(this.canvasBackground), this.sectionAvailabilityState(sec));\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 const deferPerspectiveSeatReveal = this.viewMode === 'perspective'\n && this.glideInProgress\n && this.seats.length > 2_500;\n this.seatLayer.opacity(sectionOverview || deferPerspectiveSeatReveal ? 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 // Fitted polygon labels are expensive (point-in-polygon + text measure).\n // Refit only after a meaningful camera change. The stage still scales text\n // smoothly between checkpoints; exact screen-pixel fitting catches up at\n // the next checkpoint (or once an animated glide settles).\n const rescale = !this.glideInProgress\n && (this.lodScale === 0 || Math.abs(scale - this.lodScale) / (this.lodScale || 1) > 0.08);\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 // The paint-only focus overlay already dims seats, blocks, and labels as\n // one composed scene. Avoid applying the old per-node factor underneath\n // it (which would double-dim section shells to ~2.5%).\n const dim = this.focusDimOverlay\n ? 1\n : (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 && sectionLabelT > 0.01) this.fitSectionRungLabels(sec, sx);\n const labelOpacity = sectionLabelT * (1 - zoneT) * dim;\n sec.nameLabel.opacity(sec.nameLabelFits ? labelOpacity : 0);\n // Availability now reads from the shell FILL (nearly-gone / sold-out\n // shading, OV-69), so the availability text stays a focused/detail + a11y\n // affordance — deliberately not a second map label on the 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 if (!this.glideInProgress && (sectionLabelT > 0.01 || zoneOpacity > 0.01)) {\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 }\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, and keep section\n * names off each other.\n *\n * This used to assume section labels \"do not collide by construction\",\n * because each is proven to fit inside its own shell. That holds only while\n * shells are disjoint. Hand-traced and imported plans routinely produce\n * shells that touch or overlap slightly along a shared edge, and a label\n * fitted into one can then land under its neighbour's — which is exactly the\n * unreadable smear a 36-section arena showed. Section labels now block each\n * other too, largest shell first so the big stands keep their names.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; area?: number; 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) {\n cands.push({ node: sec.nameLabel, tier: 1, section: true, area: sec.labelArea, box: boxOf(sec.nameLabel) });\n }\n }\n if (cands.length < 2) return;\n // Zone pills first (they are the coarser tier), then sections by shell size\n // so a slice never takes the slot from the stand beside it.\n cands.sort((a, b) => a.tier - b.tier\n || (b.area ?? 0) - (a.area ?? 0)\n || 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 // Shrink before hiding — the rule the Designer's own culler already follows.\n //\n // Dropping a colliding pill outright is defensible on an authoring canvas,\n // where the author knows what they drew. On the BUYER map it is not: a\n // section with no name is one the buyer cannot match to the section printed\n // on their ticket, and on a traced arena that was most of the bowl at\n // overview zoom. A smaller readable name beats a missing one.\n //\n // The floor is the same legibility floor the fitter uses, so nothing shrinks\n // into unreadability; anything still colliding at that size is genuinely out\n // of room and is hidden as before, returning as zoom spreads the sections.\n for (const c of cands) {\n if (!collides(c.box)) {\n kept.push(c.box);\n continue;\n }\n let placed = false;\n if (c.section) {\n const fontSize = c.node.fontSize();\n const y = c.node.y();\n for (const factor of SECTION_LABEL_SHRINK_STEPS) {\n const candidate = fontSize * factor;\n if (candidate * sx < MIN_SECTION_LABEL_PX) break;\n this.sizeLabel(c.node, candidate, y);\n const box = boxOf(c.node);\n if (!collides(box)) {\n kept.push(box);\n placed = true;\n break;\n }\n }\n if (!placed) this.sizeLabel(c.node, fontSize, y);\n }\n if (!placed) c.node.opacity(0);\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 if (this.viewMode === 'perspective' && this.perspectiveBaseInverse) {\n return applyAffine(this.perspectiveBaseInverse, iso);\n }\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) => {\n if (this.viewMode === 'perspective' && sec.perspectiveAffine) {\n return pointInPolygonWithHoles(\n world,\n sec.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(sec, point))),\n sec.holes.map((hole) => hole.map((point) =>\n this.perspectiveLocalPoint(this.projectedSectionPoint(sec, point)))),\n );\n }\n const offset = sec.liftWorld > 0 ? this.isoLiftLocal(sec.liftWorld) : { x: 0, y: 0 };\n return pointInPolygonWithHoles(\n { x: world.x - offset.x, y: world.y - offset.y },\n sec.outline,\n sec.holes,\n );\n });\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 rendered = this.renderedSeatPoint(seat);\n const marker = new Group({\n name: 'selection-ring',\n x: rendered.x,\n y: rendered.y,\n rotation: dims?.rotation ?? 0,\n listening: false,\n perfectDrawEnabled: false,\n opacity: this.selectionFocusId && !candidate ? 0.2 : 1,\n });\n if (this.viewMode === 'perspective') {\n const projectionScale = this.perspectiveSeatScale.get(id) ?? 1;\n marker.scale({ x: projectionScale, y: projectionScale });\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 // Keep a committed selection inside the authored seat footprint. Charts\n // commonly place adjacent seats only a small gap apart, so an outside\n // selection ring made neighbouring secured seats appear to merge.\n marker.add(new Circle({\n ...common,\n radius: Math.max(1, this.seatR - 1.25),\n strokeWidth: Math.min(2.5, Math.max(1.8, this.seatR * 0.22)),\n }));\n if (candidate) {\n // The pre-add confirmation may extend just beyond the seat, but stays\n // compact enough to respect the original chart's row/column spacing.\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 2,\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) => {\n if (this.viewMode === 'perspective' && section.perspectiveAffine) {\n return polyBounds(section.outline.map((point) => this.projectedSectionPoint(section, point)));\n }\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n // Camera position is expressed in the stage's post-affine world space.\n // Frame the outline after both the section lift and the active iso\n // projection; feeding local lifted bounds to focusRegion applies the\n // affine a second time and can send a balcony below the viewport.\n const points = section.outline.map((point) => {\n const local = { x: point.x + offset.x, y: point.y + offset.y };\n return this.isoT === 0 ? local : this.isoForward(local);\n });\n return polyBounds(points);\n });\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 let best: string | null = null;\n let bestD = Infinity;\n const stageScale = this.stage.scaleX() || 1;\n for (const seat of this.seats) {\n if (!this.selection.has(seat.id) && !this.isSelectable(seat.id)) continue;\n const centre = this.worldToScreen(seat);\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\n // Perspective markers are native seat-layer nodes at exact projected\n // coordinates. They do not inherit the section-shell tangent affine.\n const reachPx = this.seatR * stageScale * perspectiveScale + slopPx;\n const d = Math.hypot(centre.x - screen.x, centre.y - screen.y);\n if (d <= reachPx && 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 if (this.isGhostClick(e)) return; // protected only incidentally; lost when cached\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.hoveredId = id;\n this.hoverRing.position(this.renderedSeatPoint(seat));\n const projectionScale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(id) ?? 1 : 1;\n this.hoverRing.scale({ x: projectionScale, y: projectionScale });\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.hoveredId = null;\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 if (this.isGhostClick(e)) return; // near-miss rescue below is the ghost-click path\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 sectionId = this.sectionAt(pointer);\n if (sectionId) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(sectionId);\n else this.focusRegion(sectionId);\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 pointer = this.stage.getPointerPosition();\n if (!pointer) return null;\n const p = this.screenToWorld(pointer);\n let best: string | null = null;\n let bestD = Infinity;\n for (const s of this.seats) {\n const rendered = this.renderedSeatPoint(s);\n const dx = rendered.x - p.x;\n const dy = rendered.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.updateSeatGroupVisibility();\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.updateSeatGroupVisibility();\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 this.glideInProgress = true;\n const step = (now: number): void => {\n if (this.destroyed) { this.glideRaf = 0; this.glideInProgress = false; 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 // Cull before crossing out of the overview bitmap: updateLOD may uncache\n // the live graph on this exact frame, which must already be bounded.\n this.updateSeatGroupVisibility();\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.glideInProgress = false;\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 this.glideInProgress = false;\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 localPerspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\n const seatEffectiveScale = (this.viewMode === 'perspective' ? stageScale : effectiveScale)\n * localPerspectiveScale;\n const authoredFontSize = seat.kind === 'booth'\n ? BOOTH_LABEL_FONT_SIZE\n : SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const labelEffectiveScale = this.viewMode === 'perspective' && seat.kind !== 'booth'\n ? effectiveScale * localPerspectiveScale\n : seatEffectiveScale;\n const renderedFontPx = rounded((label?.fontSize() ?? authoredFontSize) * labelEffectiveScale);\n const screen = this.worldToScreen(seat);\n const outside = screen.x < 0 || screen.x > viewport.width || screen.y < 0 || screen.y > viewport.height;\n // Focus dimming and viewport culling are parent-group states, so evidence\n // must report composed scene opacity/visibility rather than the child's\n // local attribute in isolation.\n const opacity = this.focusedSeatOpacity(seat.id, shape?.getAbsoluteOpacity() ?? 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 * localPerspectiveScale : 0;\n const labelHeight = label\n ? label.height() * (this.viewMode === 'perspective' && seat.kind === 'booth' ? stageScale : effectiveScale)\n * localPerspectiveScale\n : 0;\n const directWidthPx = shape instanceof Rect\n ? shape.width() * stageScale * localPerspectiveScale\n : this.seatR * 2 * seatEffectiveScale;\n const directHeightPx = shape instanceof Rect\n ? shape.height() * (this.viewMode === 'perspective' ? stageScale : effectiveScale) * localPerspectiveScale\n : this.seatR * 2 * seatEffectiveScale;\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 * seatEffectiveScale + SEAT_TAP_SLOP_PX);\n const fill = shape?.fill();\n const ink = label?.fill();\n const accessGlyph = this.accessGlyphById.get(seat.id);\n const accessGlyphScale = accessGlyph?.getAbsoluteScale();\n return {\n seatId: seat.id,\n label: seat.label,\n kind: seat.kind === 'booth' ? 'booth' : 'seat',\n markerShape: seat.kind === 'booth'\n ? 'booth'\n : seat.wheelchairSpaceType === 'no-seat'\n ? 'square'\n : 'circle',\n ...(seat.wheelchairSpaceType ? { wheelchairSpaceType: seat.wheelchairSpaceType } : {}),\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 // When no label node exists (the seat is unlabelled at this zoom), fall\n // back to the ink this seat WOULD be painted with — the same expression\n // the seat-level evidence below uses — not to the raw theme default.\n //\n // The old fallback reported `DEF_SEAT_LABEL` (#0b1220) regardless of the\n // seat's paint, so a held seat with no label read as dark ink on\n // HELD_FILL (#6b7280) = 3.87:1 and a booked one as 1.82:1 against\n // TAKEN_FILL. That is a contrast violation the renderer never commits:\n // `seatLabelInk` runs every real label through `stateAwareBookableLabelInk`,\n // which returns #ffffff for both of those fills. A catalog visual audit\n // read this fallback as though it were painted and reported a\n // bookable-state contrast failure on 46 of 50 templates that does not\n // exist on screen.\n ink: typeof ink === 'string' ? ink : (shape ? this.seatLabelInk(seat, shape) : this.seatPreferredLabelInk(seat)),\n opacity: rounded(opacity),\n ...(accessGlyph ? {\n accessibilityMarker: {\n glyphVisible: accessGlyph.isVisible(),\n glyphWidthPx: rounded(ACCESS_GLYPH_VIEWBOX * Math.abs(accessGlyphScale?.x ?? 0)),\n emphasizedByFilter: this.accessGlyphFilterEmphasized(seat.id),\n },\n } : {}),\n pointerTarget: {\n active: !this.cached\n && !this.seatViewportCulled(seat.id)\n && Boolean(shape?.isVisible())\n && Boolean(shape?.isListening())\n && 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 lift = section && section.liftWorld > 0\n ? this.isoLiftLocal(section.liftWorld)\n : { x: 0, y: 0 };\n const screenBounds = pointsBounds(worldCorners.map((corner) => this.worldToScreen({\n x: corner.x + lift.x,\n y: corner.y + lift.y,\n })));\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 // Every bounded availability-state fill (normal / nearly-gone / sold-out /\n // closed) is a legitimate semantic shell — not category paint leaking in.\n const neutralSectionFills = new Set(\n (['normal', 'nearly-gone', 'sold-out', 'closed'] as const)\n .map((state) => overviewStateFill(palette, state).toLowerCase()),\n );\n const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);\n return {\n viewport,\n projection: this.viewMode,\n ...(this.viewMode === 'perspective' ? {\n perspective: {\n model: 'pinhole-exact-seat-anchors' as const,\n sectionSurfaceModel: 'tangent-plane' as const,\n exactSeatAnchorCount: this.perspectiveSeatProjected.size,\n depthSorted: true as const,\n },\n } : {}),\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.updateSeatGroupVisibility();\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.exportMode) return;\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.exportMode\n ? Math.max(this.effScale(), BLOCK_MELT_TOP + 0.01, LABEL_SCALE)\n : 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 // Reveal/hide the per-seat accessibility glyphs for this zoom BEFORE the\n // cache decision below, so the seat-layer bitmap bakes them in/out to match.\n this.updateAccessGlyphs(scale);\n const shouldCache = !this.exportMode && scale < CACHE_THRESHOLD;\n // Perspective section overviews deliberately paint only the bounded shells;\n // the entire native seat layer is opacity 0. Do not synchronously rebuild a\n // 14k-node bitmap that cannot contribute a pixel. If a prior flat overview\n // cache exists it may remain dormant; otherwise disable its hit canvas until\n // the camera crosses into the live-seat rung.\n const suppressPerspectiveSeatCache = this.viewMode === 'perspective'\n && this.hasSections\n && this.seats.length > 2_500\n && shouldCache;\n if (suppressPerspectiveSeatCache) {\n this.seatLayer.listening(false);\n return;\n }\n if (shouldCache && !this.cached) {\n this.cacheSeatLayer();\n } else if (!shouldCache && (this.cached || !this.seatLayer.listening())) {\n // Reveal live seats without Konva's deep cache wipe: releasing only the\n // overview bitmap keeps every seat's local transform/clientRect warm, so\n // the first melt into a section paints at ordinary pan cost (OV-80).\n if (this.cached) this.releaseSeatLayerBitmap();\n this.seatLayer.listening(!this.exportMode);\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 // A cached overview is one pan-able whole-venue bitmap; never bake it from\n // a prior detail view's culled section set.\n this.updateSeatGroupVisibility();\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 * Drop the seat-layer overview bitmap while PRESERVING every descendant's\n * cached local transform + clientRect.\n *\n * Konva's public `Layer.clearCache()` releases the bitmap and then runs a deep\n * `_clearSelfAndDescendantCache()` that clears those caches on all 14k seat\n * nodes. Recomputing them on the single frame the melt first reveals a section's\n * live seats is the ~480ms first-drill stall (OV-80). A camera glide only marks\n * each seat's ABSOLUTE_TRANSFORM dirty (recomputed lazily at ordinary pan cost)\n * and never moves a seat's LOCAL transform, so the local caches stay valid —\n * keeping them lets the first melt paint at pan cost, matching the ~17ms of\n * every subsequent glide on the same section. Any edit that actually moves a\n * seat invalidates its own transform cache through the attr setter, so only\n * still-valid caches survive here.\n */\n private releaseSeatLayerBitmap(): void {\n const layer = this.seatLayer as unknown as {\n _cache: Map<\n 'canvas',\n {\n scene: { _canvas: HTMLCanvasElement };\n filter: { _canvas: HTMLCanvasElement };\n hit: { _canvas: HTMLCanvasElement };\n }\n >;\n };\n const entry = layer._cache.get('canvas');\n if (!entry) return;\n Konva.Util.releaseCanvas(entry.scene._canvas, entry.filter._canvas, entry.hit._canvas);\n layer._cache.delete('canvas');\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 // Same warm-cache-preserving reveal as updateLOD() (OV-80): a returning\n // tab already on the live-seat rung keeps its seat transforms cached.\n this.releaseSeatLayerBitmap();\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 /**\n * Resolve every buyer-visible image requested by the current chart. Export\n * callers get a hard error with the affected layer name; the interactive\n * renderer never calls this and retains its existing best-effort behaviour.\n */\n async ready(): Promise<void> {\n const generation = this.assetGeneration;\n const fontSet = typeof document !== 'undefined' && 'fonts' in document\n ? document.fonts\n : null;\n await Promise.all([\n ...this.assetPromises.slice(),\n ...(fontSet ? [\n fontSet.ready.then(() => undefined),\n fontSet.load('700 24px Inter').then(() => undefined),\n fontSet.load('600 12px \"JetBrains Mono\"').then(() => undefined),\n ] : []),\n ]);\n if (generation !== this.assetGeneration) {\n throw new Error('The chart changed while its export assets were loading.');\n }\n if (this.assetErrors.length) {\n throw new Error(`Export stopped because ${this.assetErrors.join(' ')}`);\n }\n if (this.exportMode) {\n this.fitExportContent();\n this.forceDraw();\n }\n }\n\n /** Exact visible scene bounds in chart coordinates after fonts/assets exist. */\n private exportSceneBounds(): { x: number; y: number; width: number; height: number } {\n const rects = [this.bgLayer, this.seatLayer, this.overlayLayer]\n .map((layer) => layer.getClientRect({ relativeTo: this.stage }))\n .filter((rect) => rect.width > 0 && rect.height > 0);\n if (!rects.length) return this.bounds;\n const minX = Math.min(...rects.map((rect) => rect.x));\n const minY = Math.min(...rects.map((rect) => rect.y));\n const maxX = Math.max(...rects.map((rect) => rect.x + rect.width));\n const maxY = Math.max(...rects.map((rect) => rect.y + rect.height));\n return {\n x: minX,\n y: minY,\n width: Math.max(1, maxX - minX),\n height: Math.max(1, maxY - minY),\n };\n }\n\n /** Fit exact rendered nodes, including rotated text/decor, with pixel padding. */\n private fitExportContent(): void {\n if (!this.exportMode) return;\n const width = this.stage.width();\n const height = this.stage.height();\n const padding = Math.max(12, Math.min(36, Math.min(width, height) * 0.025));\n const fit = () => {\n const bounds = this.exportSceneBounds();\n const availableWidth = Math.max(1, width - padding * 2);\n const availableHeight = Math.max(1, height - padding * 2);\n const scale = Math.min(availableWidth / bounds.width, availableHeight / bounds.height) || 1;\n this.fitScale = scale;\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: (width - bounds.width * scale) / 2 - bounds.x * scale,\n y: (height - bounds.height * scale) / 2 - bounds.y * scale,\n });\n this.afterViewChange();\n };\n // The first fit can rebuild viewport labels; a second pass includes their\n // exact font metrics and rotated boxes in the final frame.\n fit();\n fit();\n }\n\n /**\n * Capture a clean, opaque fixed-size canvas. The CSS host background is\n * painted explicitly because Konva layers themselves are transparent.\n */\n captureCanvas(): HTMLCanvasElement {\n if (!this.exportMode) {\n throw new Error('captureCanvas() is available only on a renderer created with exportMode.');\n }\n this.forceDraw();\n let scene: HTMLCanvasElement;\n try {\n scene = this.stage.toCanvas({ pixelRatio: 1, imageSmoothingEnabled: true });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new Error(`The chart canvas could not be captured. A buyer-visible image may block export. ${detail}`);\n }\n const canvas = document.createElement('canvas');\n canvas.width = this.stage.width();\n canvas.height = this.stage.height();\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas 2D is unavailable; this browser cannot create an export.');\n context.fillStyle = this.canvasBackground;\n context.fillRect(0, 0, canvas.width, canvas.height);\n try {\n context.drawImage(scene, 0, 0);\n } finally {\n scene.width = 1;\n scene.height = 1;\n }\n return canvas;\n }\n\n private updateFreeTextVisibility(): void {\n const effectiveScale = this.exportMode\n ? Math.max(this.effScale(), LABEL_SCALE)\n : 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 // Vector venue icons share the free-text rendered-size floor.\n for (const { node, fontSize } of this.iconNodeById.values()) {\n node.visible(isBookableLabelLegibleAtScale(fontSize, effectiveScale));\n }\n }\n\n /** OV-45(a): resolve authored row-letter labels for the buyer/preview map, in\n * world space, matching the Designer's placement contract (start/end/both/none\n * preset, a free-drag `position` that wins over the preset, rotation, and\n * labelStyle colour/size fed through the same auto-contrast guard). Segmented\n * rows keep their own logical-label handling and are resolved by their owner. */\n private buildRowLabelPlan(view: ChartDoc): void {\n this.rowLabelPlan = [];\n const background = this.theme.background ?? '#0e1117';\n const seatsByRow = new Map<string, ExpandedSeat[]>();\n for (const seat of this.seats) {\n if (seat.kind === 'booth') continue;\n const key = seat.logicalRowId ?? seat.rowId;\n (seatsByRow.get(key) ?? seatsByRow.set(key, []).get(key)!).push(seat);\n }\n const seatOrder = (seat: ExpandedSeat): number => seat.logicalSeatIndex\n ?? Number(seat.id.split(':').pop() ?? 0);\n for (const obj of view.objects) {\n if (obj.type !== 'row') continue;\n // A segmented row paints ONE logical label, owned by its first component.\n if (obj.segmentedRow && obj.segmentedRow.componentIndex !== 0) continue;\n const presentation = obj.segmentedRow?.labelPresentation ?? obj.labelPresentation;\n if (presentation?.visible === false || presentation?.positionPreset === 'none') continue;\n const key = obj.segmentedRow ? obj.segmentedRow.groupId : obj.id;\n const seats = (seatsByRow.get(key) ?? []).slice().sort((a, b) => seatOrder(a) - seatOrder(b));\n if (!seats.length) continue;\n const first = seats[0];\n const last = seats[seats.length - 1];\n const labelStyle = presentation?.labelStyle;\n const ink = stateAwareBookableLabelInk(\n background,\n labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? '#e6e9f0',\n AUTHORED_LABEL_MIN_CONTRAST,\n );\n const fontSize = labelStyle?.size ?? 12;\n const rotation = presentation?.rotation ?? 0;\n const text = obj.segmentedRow?.displayLabel ?? obj.displayLabel ?? obj.label;\n const opacity = this.objectFilteredOut(obj) ? 0.15 : 1;\n const push = (x: number, y: number, automaticAway?: Point) => this.rowLabelPlan.push({\n text, x, y, rotation, fontSize, ink, opacity, ...(automaticAway ? { automaticAway } : {}),\n });\n if (presentation?.position) {\n // Free-drag wins: the stored point is the label's visual centre (WYSIWYG\n // with the Designer canvas and its placement handle).\n push(presentation.position.x, presentation.position.y);\n continue;\n }\n const gap = this.seatR + 12;\n const preset = presentation?.positionPreset ?? 'start';\n if (preset === 'start' || preset === 'both') {\n const radians = (obj.rotation * Math.PI) / 180;\n const away = { x: -Math.cos(radians), y: -Math.sin(radians) };\n push(first.x + away.x * gap, first.y + away.y * gap, away);\n }\n if (preset === 'end' || preset === 'both') {\n // Curved rows finish on a different tangent from the one they start on.\n const radians = ((obj.rotation + obj.curve) * Math.PI) / 180;\n const away = { x: Math.cos(radians), y: Math.sin(radians) };\n push(last.x + away.x * gap, last.y + away.y * gap, away);\n }\n }\n }\n\n /** Axis-aligned world bounds of a centred, potentially rotated row label. */\n private rowLabelBox(\n label: Text,\n position: Point,\n padding = ROW_LABEL_CLEARANCE,\n ): WorldBox {\n const radians = (label.rotation() * Math.PI) / 180;\n const cos = Math.abs(Math.cos(radians));\n const sin = Math.abs(Math.sin(radians));\n const halfWidth = (label.width() * cos + label.height() * sin) / 2 + padding;\n const halfHeight = (label.width() * sin + label.height() * cos) / 2 + padding;\n return {\n x: position.x - halfWidth,\n y: position.y - halfHeight,\n width: halfWidth * 2,\n height: halfHeight * 2,\n };\n }\n\n /**\n * Keep an automatic start/end label out of seat markers and already-painted\n * text. The authored point is never altered. Candidates are deliberately\n * bounded and deterministic: the closest clear offset wins; if a chart is so\n * dense that none is clear, the least-colliding candidate wins so the required\n * row label remains present rather than being silently dropped.\n */\n private resolveAutomaticRowLabelPosition(\n label: Text,\n plan: RowLabelPlanEntry,\n occupiedText: WorldBoxIndex,\n ): Point {\n const base = { x: plan.x, y: plan.y };\n const away = plan.automaticAway;\n if (!away) return base;\n const normal = { x: -away.y, y: away.x };\n const step = Math.max(7, Math.min(16, plan.fontSize * 0.75));\n const offsets: Point[] = [{ x: 0, y: 0 }];\n for (let ring = 1; ring <= 4; ring++) {\n const distance = step * ring;\n offsets.push(\n { x: normal.x * distance, y: normal.y * distance },\n { x: -normal.x * distance, y: -normal.y * distance },\n { x: away.x * distance, y: away.y * distance },\n { x: (away.x + normal.x) * distance, y: (away.y + normal.y) * distance },\n { x: (away.x - normal.x) * distance, y: (away.y - normal.y) * distance },\n );\n }\n\n let best = base;\n let bestCollisions = Infinity;\n let bestDistance = Infinity;\n for (const offset of offsets) {\n const candidate = { x: base.x + offset.x, y: base.y + offset.y };\n const box = this.rowLabelBox(label, candidate);\n const seatCollisions = this.seatIndex\n ? queryRect(this.seatIndex, box, { mode: 'overlap' }).length\n : 0;\n const collisions = seatCollisions + occupiedText.collisionCount(box);\n const distance = Math.hypot(offset.x, offset.y);\n if (collisions < bestCollisions || (collisions === bestCollisions && distance < bestDistance)) {\n best = candidate;\n bestCollisions = collisions;\n bestDistance = distance;\n }\n if (collisions === 0) break;\n }\n return best;\n }\n\n /** Row labels never carry status; the buyer just dims them under the same\n * category/price filters that dim their seats. */\n private objectFilteredOut(obj: { categoryKey?: string }): boolean {\n const key = obj.categoryKey;\n if (!key) return false;\n return Boolean((this.categoryHighlight && key !== this.categoryHighlight)\n || (this.categoryFilter && !this.categoryFilter.has(key)));\n }\n\n private updateLabels(): void {\n const effectiveScale = this.exportMode\n ? Math.max(this.effScale(), LABEL_SCALE)\n : 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 && Boolean(shape?.isVisible())\n && this.focusedSeatOpacity(id, shape?.getAbsoluteOpacity() ?? 1) >= 0.5,\n );\n }\n this.labelGroup.destroyChildren();\n this.labelLiftGroups.clear();\n this.seatLabelById.clear();\n if (!show) {\n this.overlayLayer.batchDraw();\n return;\n }\n let count = 0;\n for (const seat of this.visibleSeatCandidates()) {\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 const screen = this.worldToScreen(seat);\n if (screen.x < -20 || screen.x > this.stage.width() + 20\n || screen.y < -20 || screen.y > this.stage.height() + 20) continue;\n // An accessible seat shows its accommodation glyph in place of the seat\n // number (the glyph replaces the number), and keeps its semantic ring.\n if (this.accessGlyphById.has(seat.id) && this.accessGlyphShouldShow(seat.id)) continue;\n const shape = this.circleById.get(seat.id);\n if (!shape?.isVisible() || this.focusedSeatOpacity(seat.id, shape.getAbsoluteOpacity()) < 0.5) continue;\n const status = this.statusById.get(seat.id) ?? 'free';\n const labelPoint = this.renderedSeatPoint(seat);\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\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: labelPoint.x, y: labelPoint.y, listening: false });\n cue.scale({ x: perspectiveScale, y: perspectiveScale });\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.seatLabelContainer(seat.id).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: labelPoint.x,\n y: labelPoint.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 t.scale({ x: perspectiveScale, y: perspectiveScale });\n this.seatLabelContainer(seat.id).add(t);\n this.seatLabelById.set(seat.id, t);\n if (++count >= MAX_LABELS) break;\n }\n // OV-45(a): authored row letters, world-space like seat labels, at the seats\n // rung. Culled by screen bounds; centred and honouring per-row rotation/style.\n // Automatic start/end labels avoid neighbouring inventory and other visible\n // copy. Free-drag positions remain exact WYSIWYG authoring coordinates.\n const occupiedText = new WorldBoxIndex();\n for (const { node } of this.freeTextById.values()) {\n if (!node.isVisible()) continue;\n const box = node.getClientRect({\n relativeTo: this.bgLayer,\n skipShadow: true,\n skipStroke: true,\n });\n occupiedText.insert({\n x: box.x - ROW_LABEL_CLEARANCE,\n y: box.y - ROW_LABEL_CLEARANCE,\n width: box.width + ROW_LABEL_CLEARANCE * 2,\n height: box.height + ROW_LABEL_CLEARANCE * 2,\n });\n }\n for (const rl of this.rowLabelPlan) {\n const screen = this.worldToScreen({ x: rl.x, y: rl.y });\n if (screen.x < -40 || screen.x > this.stage.width() + 40\n || screen.y < -40 || screen.y > this.stage.height() + 40) continue;\n const t = new Text({\n x: rl.x,\n y: rl.y,\n text: rl.text,\n fontSize: rl.fontSize,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: rl.ink,\n rotation: rl.rotation,\n opacity: rl.opacity,\n shadowColor: '#05070c',\n shadowBlur: rl.ink.toLowerCase() === '#ffffff' ? 5 : 0,\n shadowOpacity: rl.ink.toLowerCase() === '#ffffff' ? 0.8 : 0,\n shadowForStrokeEnabled: false,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n const resolved = this.resolveAutomaticRowLabelPosition(t, rl, occupiedText);\n t.position(resolved);\n t.setAttr('rowLabel', true);\n occupiedText.insert(this.rowLabelBox(t, resolved));\n this.labelGroup.add(t);\n }\n // Keep freshly-built seat labels upright under the iso layer skew.\n if (this.isoT > 0 && this.viewMode !== 'perspective') 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","import type {\n Category,\n ChartDoc,\n ChartObject,\n ChartReferenceImage,\n Floor,\n} from './types';\n\ntype BackgroundOwner = Pick<ChartDoc, 'referenceImage' | 'backgroundImage'>\n | Pick<Floor, 'referenceImage' | 'backgroundImage'>;\n\n/**\n * Canonical trace lookup with backward compatibility for documents authored\n * before reference and buyer backgrounds became separate fields.\n *\n * Any historical `backgroundImage` carrying a private `assetId` is trace-only,\n * even if it also contains a URL. That fail-closed rule prevents a mistakenly\n * persisted runtime URL from making a private blueprint buyer-visible.\n */\nexport function traceReferenceImage(owner: BackgroundOwner): ChartReferenceImage | undefined {\n return owner.referenceImage ?? (owner.backgroundImage?.assetId ? owner.backgroundImage : undefined);\n}\n\n/** Buyer-visible aesthetic background; private asset-backed values fail closed. */\nexport function buyerBackgroundImage(owner: BackgroundOwner): ChartReferenceImage | undefined {\n const background = owner.backgroundImage;\n return background?.url && !background.assetId ? background : undefined;\n}\n\nfunction buyerBackgroundProjection(owner: BackgroundOwner): ChartReferenceImage | undefined {\n const background = buyerBackgroundImage(owner);\n if (!background?.url) return undefined;\n // Calibration and derived source scale are private authoring evidence. Even a\n // historical URL-only layer must not expose source coordinates to buyers.\n const { calibration: _calibration, derivedScale: _derivedScale, assetId: _assetId, ...placement } = background;\n return placement;\n}\n\n/**\n * Promote historical private `backgroundImage.assetId` values into the\n * canonical `referenceImage` field in place. The migration is deterministic,\n * keeps placement/calibration bytes intact, and never overwrites an explicit\n * canonical trace. A conflicting second legacy asset is left in place so\n * validation can report it instead of silently dropping authored data.\n */\nexport function migrateLegacyBackgroundLayersInPlace(doc: ChartDoc): ChartDoc {\n const migrate = (owner: BackgroundOwner): void => {\n const legacy = owner.backgroundImage;\n if (!legacy?.assetId) return;\n if (!owner.referenceImage) {\n owner.referenceImage = legacy;\n owner.backgroundImage = undefined;\n }\n };\n migrate(doc);\n for (const floor of doc.floors ?? []) migrate(floor);\n return doc;\n}\n\nfunction buyerObject(object: ChartObject): ChartObject {\n const clean = { ...object } as ChartObject & Record<string, unknown>;\n // Private source ids, source hashes and scan provenance are authoring-only.\n delete clean.referenceScan;\n delete clean.referenceInventorySource;\n delete clean.referenceSource;\n delete clean.referenceInventoryExclusion;\n return clean;\n}\n\nfunction buyerCategory(category: Category): Category {\n const clean = { ...category };\n delete clean.referenceCategorySource;\n return clean;\n}\n\n/**\n * Produce the document a buyer is allowed to receive. This is deliberately a\n * projection, not a mutation: immutable publications and organizer drafts keep\n * their trace evidence, while every public response loses the trace bitmap,\n * calibration/source coordinates and object/category reference provenance.\n */\nexport function buyerFacingChartDoc(doc: ChartDoc): ChartDoc {\n const buyerBackground = buyerBackgroundProjection(doc);\n const floors = doc.floors?.map((floor) => ({\n ...floor,\n objects: floor.objects.map(buyerObject),\n referenceImage: undefined,\n backgroundImage: buyerBackgroundProjection(floor),\n }));\n return {\n ...doc,\n categories: doc.categories.map(buyerCategory),\n objects: doc.objects.map(buyerObject),\n referenceImage: undefined,\n backgroundImage: buyerBackground,\n ...(floors ? { floors } : {}),\n };\n}\n\n/** True when a scope has two different trace candidates and cannot be migrated safely. */\nexport function hasConflictingLegacyTrace(owner: BackgroundOwner): boolean {\n return !!owner.referenceImage?.assetId\n && !!owner.backgroundImage?.assetId\n && owner.referenceImage.assetId !== owner.backgroundImage.assetId;\n}\n","// Venue wayfinding icon registry.\n//\n// Icons are authored as single-color vector paths in a 24×24 viewBox, drawn in a\n// consistent stroke style (Lucide/Material-Symbols aesthetic — 2-unit stroke,\n// round caps/joins, no fill). Both the Designer canvas and the buyer\n// SeatmapRenderer draw the SAME path so a placed marker looks identical\n// everywhere, unlike the emoji glyphs it replaces (which rendered per-OS).\n//\n// Identity + backward compatibility: a placed icon is a TextObject with\n// `semanticKind:'icon'`. NEW placements also carry `iconKey` referencing an entry\n// here and render as a vector Path. LEGACY placements carry only an emoji in\n// `text` (no iconKey) and keep rendering through the shared text/glyph path. The\n// two coexist forever; nothing rewrites old charts.\n\n/** Logical grouping for the Designer palette (plain-language section headers). */\nexport type VenueIconGroup = 'facilities' | 'food-drink' | 'navigation' | 'accessibility';\n\nexport interface VenueIcon {\n /** Stable registry key persisted on the object as `iconKey`. Never shown to users. */\n key: string;\n /** Plain-language name (button label, tooltip, accessible name). */\n label: string;\n group: VenueIconGroup;\n /** SVG path `d` in a 0 0 24 24 viewBox, stroke-styled (fill:none). */\n path: string;\n}\n\n/** The viewBox side length every icon path is authored against. */\nexport const VENUE_ICON_VIEWBOX = 24;\n/** Stroke width in viewBox units; scales with the object's size like a font. */\nexport const VENUE_ICON_STROKE = 2;\n\n/** Human-readable section headers for the palette groups. */\nexport const VENUE_ICON_GROUP_LABELS: Record<VenueIconGroup, string> = {\n facilities: 'Facilities',\n 'food-drink': 'Food & drink',\n navigation: 'Getting around',\n accessibility: 'Accessibility',\n};\n\n/** Display order of the groups in the palette. */\nexport const VENUE_ICON_GROUP_ORDER: VenueIconGroup[] = [\n 'facilities',\n 'food-drink',\n 'navigation',\n 'accessibility',\n];\n\n// Shared sub-marks reused across a couple of icons.\nconst WHEELCHAIR =\n 'M13 4.6a1.6 1.6 0 1 0-3.2 0 1.6 1.6 0 0 0 3.2 0 M11 6.5V13h5l2.4 6 M15 16.4A5 5 0 1 1 9 11.3';\n\nexport const VENUE_ICONS: VenueIcon[] = [\n // ---- Facilities --------------------------------------------------------\n {\n key: 'restroom-men',\n label: \"Men's restroom\",\n group: 'facilities',\n path: 'M16 7a4 4 0 1 0-8 0 4 4 0 0 0 8 0 M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2',\n },\n {\n key: 'restroom-women',\n label: \"Women's restroom\",\n group: 'facilities',\n path: 'M15 5a3 3 0 1 0-6 0 3 3 0 0 0 6 0 M12 8l-4 10h8l-4-10 M10 18v4 M14 18v4',\n },\n {\n key: 'restroom-accessible',\n label: 'Accessible restroom',\n group: 'facilities',\n path: WHEELCHAIR,\n },\n {\n key: 'first-aid',\n label: 'First aid',\n group: 'facilities',\n path: 'M5 4h14a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z M12 8v8 M8 12h8',\n },\n {\n key: 'coat-check',\n label: 'Coat check',\n group: 'facilities',\n path: 'M12 6a2 2 0 0 1 0-4 2 2 0 0 1 1.6 3.2L21 13H3l8.4-7.8 M3 13h18',\n },\n {\n key: 'atm',\n label: 'ATM / cash',\n group: 'facilities',\n path: 'M2 6h20v12H2V6Z M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0 M6 9h.01 M18 15h.01',\n },\n {\n key: 'info',\n label: 'Info point',\n group: 'facilities',\n path: 'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M12 11v5 M12 8h.01',\n },\n {\n key: 'lost-found',\n label: 'Lost & found',\n group: 'facilities',\n path: 'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14 M16 16l5 5 M9 8.5a2 2 0 1 1 3 1.7c-.8.5-1 .8-1 1.8 M11 15h.01',\n },\n {\n key: 'restrooms',\n label: 'Restrooms',\n group: 'facilities',\n path: 'M6 3h12a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M9 18v-3.5a3 3 0 0 1 6 0V18',\n },\n {\n key: 'charging',\n label: 'Charging point',\n group: 'facilities',\n path: 'M3 8h13v8H3V8Z M16 10h3v4h-3 M9.6 9l-2 3.5h2.5l-1.5 3',\n },\n {\n key: 'smoking',\n label: 'Smoking area',\n group: 'facilities',\n path: 'M2 15h13v3H2v-3Z M18 16h2 M19 8c0 1 1 1.5 1 2.5S19 12 19 13',\n },\n {\n key: 'no-smoking',\n label: 'No smoking',\n group: 'facilities',\n path: 'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M5.6 5.6l12.8 12.8 M7 13h6v2H7v-2Z',\n },\n // ---- Food & drink ------------------------------------------------------\n {\n key: 'food',\n label: 'Food',\n group: 'food-drink',\n path: 'M7 3v6a2 2 0 0 0 4 0V3 M9 11v10 M17 3c-1.6 1-2.2 3-2.2 6 0 2 .9 3.2 2.2 3.6V21',\n },\n {\n key: 'bar',\n label: 'Bar',\n group: 'food-drink',\n path: 'M4 5h16l-8 8-8-8Z M12 13v6 M8 20h8',\n },\n {\n key: 'coffee',\n label: 'Café / coffee',\n group: 'food-drink',\n path: 'M4 8h13v4a5 5 0 0 1-5 5H9a5 5 0 0 1-5-5V8Z M17 9h2a2 2 0 0 1 0 4h-2 M8 2v2 M11 2v2 M4 21h14',\n },\n {\n key: 'water',\n label: 'Water / drinks',\n group: 'food-drink',\n path: 'M12 22a7 7 0 0 1-7-7c0-5 7-12 7-12s7 7 7 12a7 7 0 0 1-7 7Z',\n },\n {\n key: 'merch',\n label: 'Merch / shop',\n group: 'food-drink',\n path: 'M6 8h12l-1 12H7L6 8Z M9 8V6a3 3 0 0 1 6 0v2',\n },\n {\n key: 'screen',\n label: 'Screen',\n group: 'facilities',\n path: 'M3 4h18v12H3V4Z M9 20h6 M12 16v4 M10 8l4 2-4 2V8Z',\n },\n {\n key: 'sound-booth',\n label: 'Sound booth',\n group: 'facilities',\n path: 'M6 4v16 M6 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4 M12 4v16 M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M18 4v16 M18 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4',\n },\n // ---- Getting around ----------------------------------------------------\n {\n key: 'entrance',\n label: 'Entrance',\n group: 'navigation',\n path: 'M14 3h5a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-5 M3 12h11 M10 8l4 4-4 4',\n },\n {\n key: 'exit',\n label: 'Exit',\n group: 'navigation',\n path: 'M10 3H5a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h5 M14 12h7 M17 8l4 4-4 4',\n },\n {\n key: 'emergency-exit',\n label: 'Emergency exit',\n group: 'navigation',\n path: 'M14 4.6a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0 M12.5 8l-3.5 2 1.6 3.6-2 4.4 M12.5 10l3.5 1.5 M9 10.5l-3.5 1 M15 12h6 M18 9l3 3-3 3',\n },\n {\n key: 'stairs',\n label: 'Stairs',\n group: 'navigation',\n path: 'M3 20v-4h4v-4h4v-4h4V4h5',\n },\n {\n key: 'elevator',\n label: 'Elevator',\n group: 'navigation',\n path: 'M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M8 11l1.5-2 1.5 2 M8 14l1.5 2 1.5-2 M15 8v8',\n },\n {\n key: 'parking',\n label: 'Parking',\n group: 'navigation',\n path: 'M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M9 17V7h4a3 3 0 0 1 0 6H9',\n },\n // ---- Accessibility -----------------------------------------------------\n {\n key: 'wheelchair',\n label: 'Wheelchair access',\n group: 'accessibility',\n path: WHEELCHAIR,\n },\n {\n key: 'hearing',\n label: 'Hearing assistance',\n group: 'accessibility',\n path: 'M8 20a4 4 0 0 1-2-3c0-1 .5-2 .5-3a4.5 4.5 0 1 1 9 0c0 1.4-1 2-2 2.4-1.2.5-1.5 1-1.5 2.2 M17 6a5 5 0 0 1 1 6 M19.5 4a8 8 0 0 1 1.2 9',\n },\n];\n\n/**\n * Décor-stamp-only glyphs. Some Designer décor presets (e.g. a structural wall)\n * are not buyer-placeable wayfinding markers, so they must NOT appear in the\n * IconPalette / VENUE_ICONS registry — but their flyout stamp button still needs\n * a vector preview in the same stroke language so the Décor row reads as one\n * system (OV-82). Authored against the same 0 0 24 24 viewBox / 2-unit stroke.\n */\nexport const DECOR_STAMP_ICON_PATHS: Record<string, string> = {\n // Running-bond brick courses — a plain structural divider.\n wall: 'M3 5h18v14H3V5Z M3 9.7h18 M3 14.3h18 M9 5v4.7 M15 5v4.7 M6 9.7v4.6 M12 9.7v4.6 M18 9.7v4.6 M9 14.3v4.7 M15 14.3v4.7',\n};\n\nconst BY_KEY = new Map<string, VenueIcon>(VENUE_ICONS.map((icon) => [icon.key, icon]));\n\n/** Resolve a registry entry by key, or undefined for legacy/unknown keys. */\nexport function venueIcon(key: string | undefined | null): VenueIcon | undefined {\n return key ? BY_KEY.get(key) : undefined;\n}\n\n/** Vector path for a key, or undefined when the key is not in the registry. */\nexport function venueIconPath(key: string | undefined | null): string | undefined {\n return venueIcon(key)?.path;\n}\n\n/** True when `key` names a real registry icon (MCP/validation fail-closed guard). */\nexport function isVenueIconKey(key: unknown): key is string {\n return typeof key === 'string' && BY_KEY.has(key);\n}\n\n/** Every valid registry key (for MCP enum + validation messages). */\nexport const VENUE_ICON_KEYS: string[] = VENUE_ICONS.map((icon) => icon.key);\n","/**\n * Pure-TypeScript spatial index for seat hit-testing.\n *\n * WHY THIS EXISTS\n * ---------------\n * `src/engine/SeatmapRenderer.ts` currently leans on Konva's built-in hit graph\n * (the `listening` property, ~58 call sites) for \"which seat did the pointer\n * land on\". No other renderer we care about ships an equivalent: React Native\n * Skia has nothing at all, and Flutter / SwiftUI / Compose canvases all expect\n * the app to own hit-testing. So the index has to exist on every path — and on\n * the web it additionally lets us drop Konva's hit graph, which is a real win at\n * 5k–13k seats (no per-seat hit-canvas rasterisation, no hit-graph traversal).\n *\n * This module is deliberately DEPENDENCY-FREE: no DOM, no Konva, no browser\n * globals. It runs unchanged in a Web Worker, in workerd, and under React\n * Native. All coordinates are WORLD space — converting screen→world is the\n * caller's job, exactly as `SeatmapRenderer.screenToWorld` does today.\n *\n * STRUCTURE: uniform grid, not a quadtree\n * ---------------------------------------\n * Seats in a venue chart are close to uniformly dense by construction — they sit\n * in rows on a near-regular pitch. That is the single case a uniform grid is\n * optimal for, and it beats a quadtree on every axis that matters here:\n * O(n) build with no rebalancing, flat typed-array storage (one contiguous\n * scan per query, no pointer chasing), and O(1) expected candidates per point\n * query. A quadtree only starts to pay when density varies by orders of\n * magnitude across the extent, which a seating chart does not do. If a future\n * chart shape ever breaks that assumption, `gridStats()` exposes the occupancy\n * numbers needed to prove it before reaching for a tree.\n *\n * Each seat is inserted into EVERY cell its axis-aligned bounding box overlaps\n * (not just the cell holding its centre). That is what makes {@link hitTest}\n * examine exactly one cell: any seat whose shape contains a point also has an\n * AABB containing that point, so it is guaranteed to be registered in that\n * point's cell.\n */\n\nimport type { ExpandedSeat, Point } from './types';\n\n/**\n * Default seat radius in world units. Mirrors `SEAT_RADIUS` in\n * `SeatmapRenderer.ts` and `DesignerController.ts` (both 9). The renderer scales\n * this by `theme.seatScale` clamped to [0.7, 1.6]; callers that do the same must\n * pass the scaled value via {@link BuildOptions.seatRadius} so the index agrees\n * with what is actually drawn.\n */\nexport const DEFAULT_SEAT_RADIUS = 9;\n\n/**\n * Hit geometry for one seat. Real seats are circles; trade-show booths render as\n * rotated rounded rects whose dimensions live on the booth object in the\n * ChartDoc, not on `ExpandedSeat` — so the caller supplies them through\n * {@link BuildOptions.shapeOf} rather than this module reaching for the doc.\n */\nexport type SeatShape =\n | { kind: 'circle'; r: number }\n | { kind: 'rect'; width: number; height: number; rotation?: number };\n\nexport interface BuildOptions {\n /** Radius for circular seats when {@link shapeOf} is absent. Default {@link DEFAULT_SEAT_RADIUS}. */\n seatRadius?: number;\n /**\n * Per-seat hit geometry. Return `null`/`undefined` to fall back to a circle of\n * `seatRadius`. Called exactly once per seat during construction.\n */\n shapeOf?: (seat: ExpandedSeat) => SeatShape | null | undefined;\n /**\n * Upper bound on grid cells, to stop a chart with one far-flung stray object\n * from allocating a huge sparse grid. Default `max(64, 4 * seats.length)`.\n * When the natural cell size would exceed this, cells are grown until it fits.\n */\n maxCells?: number;\n}\n\nexport interface QueryOptions {\n /**\n * Restrict results to seats this predicate accepts — used to reproduce the\n * renderer's `isSelectable(id) || selection.has(id)` gate. Kept as a query\n * argument rather than build state on purpose: seat statuses change on every\n * websocket tick, and the geometry does not.\n */\n filter?: (id: string, seat: ExpandedSeat) => boolean;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface RectQueryOptions extends QueryOptions {\n /**\n * `'center'` (default) keeps a seat when its CENTRE falls inside the rect,\n * bounds inclusive. This is what `SeatmapRenderer.finishMarquee` does today,\n * so it is the default in order to be a drop-in replacement.\n *\n * `'overlap'` keeps a seat when its hit SHAPE intersects the rect at all —\n * the right mode for \"which seats are on screen\" viewport culling and\n * label-rendering passes, where a partially visible seat still counts.\n */\n mode?: 'center' | 'overlap';\n}\n\ninterface IndexedSeat {\n seat: ExpandedSeat;\n shape: SeatShape;\n /** Half-extents of the shape's axis-aligned bounding box (rotation applied). */\n hx: number;\n hy: number;\n}\n\nexport interface SeatIndex {\n readonly seats: readonly ExpandedSeat[];\n /** @internal */\n readonly entries: readonly IndexedSeat[];\n /** @internal */\n readonly minX: number;\n /** @internal */\n readonly minY: number;\n /** @internal */\n readonly cell: number;\n /** @internal */\n readonly cols: number;\n /** @internal */\n readonly rows: number;\n /** @internal Prefix-sum offsets into {@link items}; length cols*rows+1. */\n readonly cellStart: Int32Array;\n /** @internal Seat indices grouped by cell. */\n readonly items: Int32Array;\n /** @internal Per-seat visit stamps, for dedup across multi-cell scans. */\n readonly stamp: Int32Array;\n /** @internal Monotonically increasing stamp epoch. */\n epoch: number;\n}\n\n/** Axis-aligned half-extents of a shape, accounting for rotation. */\nfunction halfExtents(shape: SeatShape): { hx: number; hy: number } {\n if (shape.kind === 'circle') return { hx: shape.r, hy: shape.r };\n const hw = shape.width / 2;\n const hh = shape.height / 2;\n const rot = shape.rotation ?? 0;\n if (!rot) return { hx: hw, hy: hh };\n const rad = (rot * Math.PI) / 180;\n const c = Math.abs(Math.cos(rad));\n const s = Math.abs(Math.sin(rad));\n return { hx: hw * c + hh * s, hy: hw * s + hh * c };\n}\n\n/** Exact containment test for one seat's hit shape. */\nfunction shapeContains(e: IndexedSeat, px: number, py: number): boolean {\n const dx = px - e.seat.x;\n const dy = py - e.seat.y;\n if (e.shape.kind === 'circle') {\n return dx * dx + dy * dy <= e.shape.r * e.shape.r;\n }\n const rot = e.shape.rotation ?? 0;\n let lx = dx;\n let ly = dy;\n if (rot) {\n // Rotate the point INTO the rect's local frame (i.e. by -rotation).\n const rad = (-rot * Math.PI) / 180;\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n lx = dx * c - dy * s;\n ly = dx * s + dy * c;\n }\n return Math.abs(lx) <= e.shape.width / 2 && Math.abs(ly) <= e.shape.height / 2;\n}\n\n/** Does a seat's hit shape intersect an axis-aligned rect? */\nfunction shapeIntersectsRect(e: IndexedSeat, x0: number, y0: number, x1: number, y1: number): boolean {\n if (e.shape.kind === 'circle') {\n // Closest point on the rect to the circle centre.\n const cx = Math.min(Math.max(e.seat.x, x0), x1);\n const cy = Math.min(Math.max(e.seat.y, y0), y1);\n const dx = e.seat.x - cx;\n const dy = e.seat.y - cy;\n return dx * dx + dy * dy <= e.shape.r * e.shape.r;\n }\n // Rects: separating-axis test over the 4 candidate axes (2 per box). For the\n // unrotated case this degenerates to a plain AABB overlap.\n const rot = e.shape.rotation ?? 0;\n if (!rot) {\n return (\n e.seat.x - e.hx <= x1 && e.seat.x + e.hx >= x0 && e.seat.y - e.hy <= y1 && e.seat.y + e.hy >= y0\n );\n }\n const rad = (rot * Math.PI) / 180;\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n const hw = e.shape.width / 2;\n const hh = e.shape.height / 2;\n // Rect corners in world space.\n const corners: Array<[number, number]> = [\n [-hw, -hh],\n [hw, -hh],\n [hw, hh],\n [-hw, hh],\n ].map(([lx, ly]) => [e.seat.x + lx * c - ly * s, e.seat.y + lx * s + ly * c] as [number, number]);\n const query: Array<[number, number]> = [\n [x0, y0],\n [x1, y0],\n [x1, y1],\n [x0, y1],\n ];\n const axes: Array<[number, number]> = [\n [1, 0],\n [0, 1],\n [c, s],\n [-s, c],\n ];\n for (const [ax, ay] of axes) {\n let minA = Infinity;\n let maxA = -Infinity;\n for (const [px, py] of corners) {\n const d = px * ax + py * ay;\n if (d < minA) minA = d;\n if (d > maxA) maxA = d;\n }\n let minB = Infinity;\n let maxB = -Infinity;\n for (const [px, py] of query) {\n const d = px * ax + py * ay;\n if (d < minB) minB = d;\n if (d > maxB) maxB = d;\n }\n if (maxA < minB || maxB < minA) return false;\n }\n return true;\n}\n\n/**\n * Build a uniform-grid index over `seats`. O(n) in time and memory.\n *\n * CELL SIZE\n * ---------\n * The nominal cell is `4 × maxHalfExtent`, i.e. twice the largest seat's\n * bounding-box width. Two properties fall out of that choice:\n *\n * - A seat's AABB is at most half a cell across, so it lands in at most 2×2 = 4\n * cells. Build stays O(n) with a small constant, and the index does not blow\n * up in memory from duplicated references.\n * - For the default 9px seat radius the cell is 36 world units, versus a real\n * row/seat pitch of roughly 20–26. That works out to ~1–2 seats per occupied\n * cell, so a point query examines about one or two candidates. Halving the\n * cell would quadruple cell count to shave a fraction of a candidate;\n * doubling it would put ~6 seats in every cell. 4× the half-extent is the\n * flat part of that curve.\n *\n * The one pathological input is a chart whose bounds are enormous relative to\n * its seat count — a single stray object parked far from the venue. `maxCells`\n * caps the grid and grows the cell size until it fits, trading query sharpness\n * for bounded memory. Real charts never hit it.\n */\nexport function buildSeatIndex(seats: readonly ExpandedSeat[], opts: BuildOptions = {}): SeatIndex {\n const seatRadius = opts.seatRadius ?? DEFAULT_SEAT_RADIUS;\n const n = seats.length;\n const entries: IndexedSeat[] = new Array(n);\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let maxHalf = 0;\n\n for (let i = 0; i < n; i++) {\n const seat = seats[i];\n const shape = opts.shapeOf?.(seat) ?? { kind: 'circle' as const, r: seatRadius };\n const { hx, hy } = halfExtents(shape);\n entries[i] = { seat, shape, hx, hy };\n if (seat.x - hx < minX) minX = seat.x - hx;\n if (seat.y - hy < minY) minY = seat.y - hy;\n if (seat.x + hx > maxX) maxX = seat.x + hx;\n if (seat.y + hy > maxY) maxY = seat.y + hy;\n if (hx > maxHalf) maxHalf = hx;\n if (hy > maxHalf) maxHalf = hy;\n }\n\n if (n === 0) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n\n // Guard degenerate inputs: zero-extent shapes, or every seat stacked on one\n // point. A cell size of 0 would make the coordinate maths produce NaN.\n const nominal = maxHalf > 0 ? maxHalf * 4 : 1;\n const spanX = Math.max(maxX - minX, 0);\n const spanY = Math.max(maxY - minY, 0);\n const maxCells = Math.max(64, opts.maxCells ?? n * 4);\n\n let cell = nominal;\n let cols = Math.max(1, Math.ceil(spanX / cell) || 1);\n let rows = Math.max(1, Math.ceil(spanY / cell) || 1);\n // Grow the cell until the grid fits the budget. Each doubling quarters the\n // cell count, so this converges in a handful of iterations even for absurd\n // spans, and cannot loop forever once cols and rows both reach 1.\n while (cols * rows > maxCells && (cols > 1 || rows > 1)) {\n cell *= 2;\n cols = Math.max(1, Math.ceil(spanX / cell) || 1);\n rows = Math.max(1, Math.ceil(spanY / cell) || 1);\n }\n\n const cellCount = cols * rows;\n const cellStart = new Int32Array(cellCount + 1);\n\n // Pass 1 — count how many cells each seat's AABB touches.\n let total = 0;\n for (let i = 0; i < n; i++) {\n const e = entries[i];\n const cx0 = clampInt(Math.floor((e.seat.x - e.hx - minX) / cell), 0, cols - 1);\n const cx1 = clampInt(Math.floor((e.seat.x + e.hx - minX) / cell), 0, cols - 1);\n const cy0 = clampInt(Math.floor((e.seat.y - e.hy - minY) / cell), 0, rows - 1);\n const cy1 = clampInt(Math.floor((e.seat.y + e.hy - minY) / cell), 0, rows - 1);\n for (let cy = cy0; cy <= cy1; cy++) {\n for (let cx = cx0; cx <= cx1; cx++) {\n cellStart[cy * cols + cx + 1]++;\n total++;\n }\n }\n }\n\n // Prefix sum → per-cell start offsets.\n for (let c = 0; c < cellCount; c++) cellStart[c + 1] += cellStart[c];\n\n // Pass 2 — scatter seat indices into their cells.\n const items = new Int32Array(total);\n const cursor = cellStart.slice(0, cellCount);\n for (let i = 0; i < n; i++) {\n const e = entries[i];\n const cx0 = clampInt(Math.floor((e.seat.x - e.hx - minX) / cell), 0, cols - 1);\n const cx1 = clampInt(Math.floor((e.seat.x + e.hx - minX) / cell), 0, cols - 1);\n const cy0 = clampInt(Math.floor((e.seat.y - e.hy - minY) / cell), 0, rows - 1);\n const cy1 = clampInt(Math.floor((e.seat.y + e.hy - minY) / cell), 0, rows - 1);\n for (let cy = cy0; cy <= cy1; cy++) {\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = cy * cols + cx;\n items[cursor[c]++] = i;\n }\n }\n }\n\n return {\n seats,\n entries,\n minX,\n minY,\n cell,\n cols,\n rows,\n cellStart,\n items,\n stamp: new Int32Array(n),\n epoch: 0,\n };\n}\n\nfunction clampInt(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n\n/**\n * The seat whose hit shape contains `p`, or null.\n *\n * On overlap — seats drawn close enough that their circles intersect — the seat\n * whose CENTRE is nearest to `p` wins. That matches what a user perceives (you\n * hit the thing you aimed at) and, unlike Konva, is order-independent: Konva's\n * hit graph resolves overlap by draw order, returning the topmost/last-added\n * node regardless of how far off-centre the pointer was.\n */\nexport function hitTest(index: SeatIndex, p: Point, opts: QueryOptions = {}): string | null {\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n const cx = Math.floor((p.x - minX) / cell);\n const cy = Math.floor((p.y - minY) / cell);\n if (cx < 0 || cy < 0 || cx >= cols || cy >= rows) return null;\n\n // Every seat containing p has an AABB containing p, so it is registered in\n // p's own cell — one cell is a complete candidate set.\n const c = cy * cols + cx;\n const end = cellStart[c + 1];\n let best = -1;\n let bestD = Infinity;\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n if (!shapeContains(e, p.x, p.y)) continue;\n const dx = p.x - e.seat.x;\n const dy = p.y - e.seat.y;\n const d = dx * dx + dy * dy;\n // Ties break toward the lower seat index so the answer never depends on\n // grid layout or cell-scan order — it matches a plain array-order scan.\n if (d < bestD || (d === bestD && i < best)) {\n bestD = d;\n best = i;\n }\n }\n return best < 0 ? null : entries[best].seat.id;\n}\n\n/**\n * Nearest seat CENTRE strictly within `radius` world units of `p`, or null.\n *\n * This is the near-miss rescue from `SeatmapRenderer.nearestSeatToScreen`,\n * lifted verbatim. The caller computes the radius the same way the renderer\n * does today:\n *\n * const reachWorld = seatR + slopPx / stageScale; // SEAT_TAP_SLOP_PX = 14\n * nearestWithin(index, screenToWorld(pointer), reachWorld, { filter });\n *\n * Note the comparison is STRICTLY less-than, mirroring the renderer's\n * `bestD = reachWorld; ... if (d < bestD)` loop: a seat centre sitting exactly\n * `reachWorld` away does not qualify. Distance is measured to the seat centre,\n * not the shape edge — so for the default circle, \"centre within seatR + slop\"\n * is identical to \"edge within slop\", which is what the renderer's docstring\n * describes.\n */\nexport function nearestWithin(\n index: SeatIndex,\n p: Point,\n radius: number,\n opts: QueryOptions = {},\n): string | null {\n if (!(radius > 0)) return null;\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n\n const cx0 = Math.max(0, Math.floor((p.x - radius - minX) / cell));\n const cx1 = Math.min(cols - 1, Math.floor((p.x + radius - minX) / cell));\n const cy0 = Math.max(0, Math.floor((p.y - radius - minY) / cell));\n const cy1 = Math.min(rows - 1, Math.floor((p.y + radius - minY) / cell));\n if (cx0 > cx1 || cy0 > cy1) return null;\n\n // A seat centre within `radius` of p lies inside the box p ± radius, and a\n // seat is always registered in the cell holding its own centre — so scanning\n // the cells overlapping that box is complete.\n let best = -1;\n let bestD = radius * radius;\n const stamp = index.stamp;\n const ep = ++index.epoch;\n for (let cy = cy0; cy <= cy1; cy++) {\n const rowBase = cy * cols;\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = rowBase + cx;\n const end = cellStart[c + 1];\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n if (stamp[i] === ep) continue; // already considered via another cell\n stamp[i] = ep;\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n const dx = p.x - e.seat.x;\n const dy = p.y - e.seat.y;\n const d = dx * dx + dy * dy;\n // Lower seat index wins ties — identical to the renderer's first-wins\n // `for (const seat of this.seats)` loop.\n if (d < bestD || (d === bestD && i < best)) {\n bestD = d;\n best = i;\n }\n }\n }\n }\n return best < 0 ? null : entries[best].seat.id;\n}\n\n/**\n * Seat ids inside a world-space rect. Negative width/height are normalised, so a\n * marquee dragged up-and-left works without the caller sorting the corners.\n *\n * Default `mode: 'center'` reproduces `SeatmapRenderer.finishMarquee` exactly:\n * a seat is kept when its centre is within the rect, bounds INCLUSIVE. Use\n * `mode: 'overlap'` for viewport culling, where a seat straddling the edge\n * should still be drawn.\n *\n * Results come back in ascending seat-array order, so the output is stable\n * across calls regardless of grid layout.\n */\nexport function queryRect(index: SeatIndex, rect: Rect, opts: RectQueryOptions = {}): string[] {\n const x0 = Math.min(rect.x, rect.x + rect.width);\n const x1 = Math.max(rect.x, rect.x + rect.width);\n const y0 = Math.min(rect.y, rect.y + rect.height);\n const y1 = Math.max(rect.y, rect.y + rect.height);\n const mode = opts.mode ?? 'center';\n\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n const cx0 = Math.max(0, Math.floor((x0 - minX) / cell));\n const cx1 = Math.min(cols - 1, Math.floor((x1 - minX) / cell));\n const cy0 = Math.max(0, Math.floor((y0 - minY) / cell));\n const cy1 = Math.min(rows - 1, Math.floor((y1 - minY) / cell));\n if (cx0 > cx1 || cy0 > cy1) return [];\n\n const found: number[] = [];\n const stamp = index.stamp;\n const ep = ++index.epoch;\n for (let cy = cy0; cy <= cy1; cy++) {\n const rowBase = cy * cols;\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = rowBase + cx;\n const end = cellStart[c + 1];\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n if (stamp[i] === ep) continue; // seat spans several cells\n stamp[i] = ep;\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n const ok =\n mode === 'center'\n ? e.seat.x >= x0 && e.seat.x <= x1 && e.seat.y >= y0 && e.seat.y <= y1\n : shapeIntersectsRect(e, x0, y0, x1, y1);\n if (ok) found.push(i);\n }\n }\n }\n found.sort((a, b) => a - b);\n return found.map((i) => entries[i].seat.id);\n}\n\n/**\n * Occupancy stats for the built grid. Diagnostic only — this is the evidence to\n * check before anyone argues the uniform grid has stopped being good enough and\n * a tree is warranted.\n */\nexport function gridStats(index: SeatIndex): {\n cell: number;\n cols: number;\n rows: number;\n cells: number;\n occupiedCells: number;\n refs: number;\n maxPerCell: number;\n meanPerOccupiedCell: number;\n} {\n const cells = index.cols * index.rows;\n let occupied = 0;\n let maxPerCell = 0;\n for (let c = 0; c < cells; c++) {\n const len = index.cellStart[c + 1] - index.cellStart[c];\n if (len > 0) occupied++;\n if (len > maxPerCell) maxPerCell = len;\n }\n const refs = index.items.length;\n return {\n cell: index.cell,\n cols: index.cols,\n rows: index.rows,\n cells,\n occupiedCells: occupied,\n refs,\n maxPerCell,\n meanPerOccupiedCell: occupied ? refs / occupied : 0,\n };\n}\n","import type { Point } from './types';\n\n/** Axis-aligned chart bounds used to derive a stable, document-relative camera. */\nexport interface PerspectiveBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * A deterministic pinhole camera for the projected 2.5D buyer/Designer views.\n * Coordinates stay in chart units so the ordinary Stage camera (pan/zoom) can\n * remain the only screen-space transform.\n */\nexport interface PerspectiveCamera {\n target: Point;\n /** Horizontal distance from target to camera, in chart units. */\n distance: number;\n /** Camera height above the chart datum, in chart units. */\n height: number;\n /** Pinhole focal length, in chart units. */\n focalLength: number;\n /** Small plan rotation which keeps the venue from reading as a flat elevation. */\n yawRad: number;\n}\n\n/** Canvas/Konva affine: x' = a·x + c·y + e; y' = b·x + d·y + f. */\nexport interface Affine2D {\n a: number;\n b: number;\n c: number;\n d: number;\n e: number;\n f: number;\n}\n\nexport interface PerspectivePoint extends Point {\n /** Positive camera-space distance; larger values are farther away. */\n depth: number;\n /** Perspective size multiplier at this point (1 at the camera target). */\n scale: number;\n}\n\n/**\n * Choose a camera from venue bounds rather than fixed pixels. The camera rises\n * above the tallest authored surface, so even the (deliberately generous)\n * 120-m validation ceiling cannot cross the near plane.\n */\nexport function createPerspectiveCamera(\n bounds: PerspectiveBounds,\n maxSurfaceHeightWorld = 0,\n): PerspectiveCamera {\n const span = Math.max(1, bounds.width, bounds.height);\n const target = {\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n };\n const distance = span * 1.55;\n const height = Math.max(span * 0.82, Math.max(0, maxSurfaceHeightWorld) + span * 0.45);\n return {\n target,\n distance,\n height,\n focalLength: Math.hypot(distance, height),\n yawRad: (-8 * Math.PI) / 180,\n };\n}\n\n/** Project one 3D chart point through the pinhole camera. */\nexport function projectPerspectivePoint(\n camera: PerspectiveCamera,\n point: Point,\n heightWorld = 0,\n): PerspectivePoint {\n const dx = point.x - camera.target.x;\n const dy = point.y - camera.target.y;\n const cos = Math.cos(camera.yawRad);\n const sin = Math.sin(camera.yawRad);\n const x = dx * cos - dy * sin;\n const y = dx * sin + dy * cos;\n const translatedY = y - camera.distance;\n const translatedZ = heightWorld - camera.height;\n const cameraLength = Math.hypot(camera.distance, camera.height);\n const depth = (-camera.distance * translatedY - camera.height * translatedZ) / cameraLength;\n const up = (-camera.height * translatedY + camera.distance * translatedZ) / cameraLength;\n // Camera construction keeps authored surfaces in front of the near plane.\n // The clamp is still a fail-safe for malformed data loaded without validation.\n const safeDepth = Math.max(cameraLength * 0.08, depth);\n const scale = camera.focalLength / safeDepth;\n return {\n x: camera.target.x + x * scale,\n y: camera.target.y - up * scale,\n depth: safeDepth,\n scale,\n };\n}\n\nexport function applyAffine(affine: Affine2D, point: Point): Point {\n return {\n x: affine.a * point.x + affine.c * point.y + affine.e,\n y: affine.b * point.x + affine.d * point.y + affine.f,\n };\n}\n\nexport function invertAffine(affine: Affine2D): Affine2D {\n const determinant = affine.a * affine.d - affine.b * affine.c;\n if (!Number.isFinite(determinant) || Math.abs(determinant) < 1e-9) {\n throw new Error('perspective projection produced a singular affine');\n }\n const a = affine.d / determinant;\n const b = -affine.b / determinant;\n const c = -affine.c / determinant;\n const d = affine.a / determinant;\n return {\n a,\n b,\n c,\n d,\n e: -(a * affine.e + c * affine.f),\n f: -(b * affine.e + d * affine.f),\n };\n}\n\n/** Return `left(right(point))`. */\nexport function composeAffine(left: Affine2D, right: Affine2D): Affine2D {\n return {\n a: left.a * right.a + left.c * right.b,\n b: left.b * right.a + left.d * right.b,\n c: left.a * right.c + left.c * right.d,\n d: left.b * right.c + left.d * right.d,\n e: left.a * right.e + left.c * right.f + left.e,\n f: left.b * right.e + left.d * right.f + left.f,\n };\n}\n\n/**\n * First-order projection around one object/section anchor. The height callback\n * may describe a raked surface; sampling one chart unit along x/y captures its\n * local slope. Per-section tangents are the intentional shell-performance\n * contract. Buyer seat anchors are projected exactly by `projectPerspectivePoint`;\n * only non-interactive section surfaces use this bounded approximation.\n */\nexport function perspectiveTangentAffine(\n camera: PerspectiveCamera,\n anchor: Point,\n heightAt: (point: Point) => number = () => 0,\n): Affine2D {\n const origin = projectPerspectivePoint(camera, anchor, heightAt(anchor));\n const alongXPoint = { x: anchor.x + 1, y: anchor.y };\n const alongYPoint = { x: anchor.x, y: anchor.y + 1 };\n const alongX = projectPerspectivePoint(camera, alongXPoint, heightAt(alongXPoint));\n const alongY = projectPerspectivePoint(camera, alongYPoint, heightAt(alongYPoint));\n const a = alongX.x - origin.x;\n const b = alongX.y - origin.y;\n const c = alongY.x - origin.x;\n const d = alongY.y - origin.y;\n return {\n a,\n b,\n c,\n d,\n e: origin.x - a * anchor.x - c * anchor.y,\n f: origin.y - b * anchor.x - d * anchor.y,\n };\n}\n\n/** Parameters accepted by Konva's rotation/scale/skew decomposition. */\nexport function decomposeAffineLinear(affine: Affine2D): {\n rotationDeg: number;\n scaleX: number;\n scaleY: number;\n skewX: number;\n} {\n const scaleX = Math.hypot(affine.a, affine.b);\n const determinant = affine.a * affine.d - affine.b * affine.c;\n return {\n rotationDeg: (Math.atan2(affine.b, affine.a) * 180) / Math.PI,\n scaleX,\n scaleY: determinant / Math.max(scaleX, 1e-9),\n skewX: (affine.a * affine.c + affine.b * affine.d) / Math.max(determinant, 1e-9),\n };\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/**\n * How many decimal places a currency has — 2 for USD/EUR, 0 for JPY/KRW/VND,\n * 3 for KWD/BHD/JOD.\n *\n * Derived from Intl rather than from a table, because ICU already carries ISO\n * 4217's exponents and a second hand-maintained list is a second thing to get\n * wrong. (`workers/api/src/payments/money.ts` DOES keep a table, on purpose: it\n * must THROW for a currency checkout cannot transact. Display has no such duty\n * — it renders whatever the ledger already recorded, including a currency\n * checkout would refuse.)\n *\n * Falls back to 2 for a code Intl rejects, so a bad row cannot blank a chart.\n */\nexport function currencyExponent(currency: string = DEFAULT_CURRENCY): number {\n try {\n return formatter(currency, undefined).resolvedOptions().maximumFractionDigits ?? 2;\n } catch {\n return 2;\n }\n}\n\n/**\n * Minor units → major units. `9000` USD cents is `90`; `9000` JPY is `9000`.\n *\n * Every money field the API returns is an integer in the currency's smallest\n * unit (`grossMinor`, `total_minor`). Dividing by 100 at a call site is right\n * for most currencies and silently wrong for the rest — 100x wrong for yen.\n */\nexport function fromMinorUnits(minor: number, currency: string = DEFAULT_CURRENCY): number {\n return minor / 10 ** currencyExponent(currency);\n}\n\n/** \"$90\" / \"¥9,000\" — a minor-unit integer rendered for display. */\nexport function formatMinor(minor: number, currency: string = DEFAULT_CURRENCY): string {\n return formatMoney(fromMinorUnits(minor, currency), currency);\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.holdExpired': 'Your hold expired — the seats were released. Pick again.',\n 'picker.poweredBy': 'Powered by SeatLayer',\n 'picker.testMode': 'TEST MODE',\n 'picker.orphanHint': 'This leaves a single seat stranded — consider shifting one seat over.',\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.soldOut': 'SOLD OUT',\n 'map.fromPrice': 'FROM {price}',\n 'map.statusHeld': 'On hold',\n 'map.statusTaken': 'Taken',\n\n // buyer picker widget (src/picker/widget/SeatPicker.ts)\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 — sold-out and nearly-gone sections shade to show availability at a glance',\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.entrance': 'Entrance',\n 'picker.tapSeatHint': 'Tap any seat to check its view',\n 'picker.ticketTierFor': 'Ticket tier for {label}',\n 'picker.viewFromSeat': 'View from seat {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'PREVIEW',\n 'picker.sightline': '≈ {m} m to stage · clear sightline',\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 'picker.bestSeatsPremium': 'Best seats',\n 'picker.premiumFallbackNote': 'No premium block of {count} — showing best overall',\n};\n","/**\n * i18n core — deliberately tiny and framework-free so the embed SDK can share\n * it without dragging in a runtime library — every KB here lands in the complete\n * CDN bundle every buyer downloads, which is ~207 KB gzipped as of 0.37.0+.\n * (This used to cite a \"150 KB product contract\". That number was never true of\n * any shipped bundle — the dashboard advertised it while the artifact measured\n * 215 KB — so it is stated as the measured figure now, not as a budget nobody\n * was holding. See docs/hosted-checkout-programme-2026-08-03.md §W4.)\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","import type {\n ShapeLineCap,\n ShapeLineEnding,\n ShapeLineJoin,\n ShapeObject,\n} from './types';\n\nexport const SHAPE_LINE_CAPS = ['butt', 'round', 'square'] as const satisfies readonly ShapeLineCap[];\nexport const SHAPE_LINE_JOINS = ['miter', 'round', 'bevel'] as const satisfies readonly ShapeLineJoin[];\nexport const SHAPE_LINE_ENDINGS = ['none', 'arrow'] as const satisfies readonly ShapeLineEnding[];\n\n/** These defaults match the renderer behaviour that predates persisted line styling. */\nexport const DEFAULT_SHAPE_LINE_CAP: ShapeLineCap = 'round';\nexport const DEFAULT_SHAPE_LINE_JOIN: ShapeLineJoin = 'round';\nexport const DEFAULT_SHAPE_LINE_ENDING: ShapeLineEnding = 'none';\n\nexport function isOpenShapeKind(kind: ShapeObject['kind']): kind is 'line' | 'polyline' {\n return kind === 'line' || kind === 'polyline';\n}\n\n/**\n * Shape kinds whose geometry is a `points[]` array, so they can be edited\n * vertex by vertex. Lives here rather than in the Designer because both the\n * controller's boundary/handle code and `controller/shapesTextDecorFacet` need\n * the same answer, and the Designer previously carried a private copy of the\n * open-shape rule alongside `isOpenShapeKind`.\n */\nexport function isPointShapeKind(kind: ShapeObject['kind']): kind is 'polygon' | 'line' | 'polyline' {\n return kind === 'polygon' || isOpenShapeKind(kind);\n}\n\nexport function resolvedShapeLineStyle(shape: Pick<ShapeObject, 'lineCap' | 'lineJoin' | 'startEnding' | 'endEnding'>) {\n return {\n lineCap: shape.lineCap ?? DEFAULT_SHAPE_LINE_CAP,\n lineJoin: shape.lineJoin ?? DEFAULT_SHAPE_LINE_JOIN,\n startEnding: shape.startEnding ?? DEFAULT_SHAPE_LINE_ENDING,\n endEnding: shape.endEnding ?? DEFAULT_SHAPE_LINE_ENDING,\n };\n}\n\n/** Keep arrowheads legible for hairlines without letting a 40-unit stroke\n * create unbounded decorations. Both renderers consume this exact contract. */\nexport function shapeArrowMetrics(strokeWidth: number): { pointerLength: number; pointerWidth: number } {\n return {\n pointerLength: Math.min(48, Math.max(8, strokeWidth * 3)),\n pointerWidth: Math.min(40, Math.max(8, strokeWidth * 2.25)),\n };\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 * Best-available seat selection — a PURE, fully unit-testable ranking function.\n *\n * This is the CLIENT-side twin of the server's atomic best-available route\n * (workers/api/src/bestAvailable.ts). The server owns the authoritative pick +\n * hold for the default \"Find best seats\" flow; this pure copy lets the buyer\n * widget run a premium-biased pre-pass locally (it already holds the full seat\n * geometry + commercial flags + live availability) and then hold the resulting\n * block through the normal hold endpoint. The baseline behaviour is kept\n * identical to the server so the two never disagree on what \"best\" means.\n *\n * \"Best\" means, in priority order:\n * 0. (opt-in) a run made entirely of `commercial.premium` seats — only when\n * `preferPremium` is set; absent = this term is inert (byte-identical).\n * 1. A single contiguous run of `qty` adjacent-available seats in ONE row\n * (a booked/held/missing/wrong-category seat breaks contiguity).\n * 2. …that does NOT strand a single isolated free seat (\"orphan\") beside the\n * run — leaving a pair or more is fine, leaving a lone singleton is not.\n * 3. …whose centroid is closest to the focal point (the stage).\n * 4. Deterministic tie-break by rowId then seat index (so it's testable).\n *\n * When no single-row run of `qty` exists, it falls back to the `qty` available\n * seats closest to the focal point overall (which may span rows).\n */\nimport type { ExpandedSeat, Point } from './types';\n\nexport type BestAvailableReason = 'not_enough_together' | 'sold_out';\n\nexport interface BestAvailableResult {\n labels: string[];\n reason?: BestAvailableReason;\n}\n\nexport interface BestAvailableOpts {\n qty: number;\n categoryKey?: string;\n /** Restrict the pick to one authored navigation zone. */\n zoneId?: string;\n focal: Point;\n /**\n * Additive premium bias. When true, candidate scoring STRONGLY prefers seats\n * carrying `commercial.premium` (a fully-premium run beats any run holding a\n * non-premium seat, ahead of orphan/distance). Undefined/false leaves scoring\n * byte-identical to the baseline algorithm — the premium term never runs.\n */\n preferPremium?: boolean;\n}\n\n/** Seat index within its row, parsed from the `${rowId}:${index}` id. */\nfunction seatIndex(seat: ExpandedSeat, fallback: number): number {\n if (Number.isInteger(seat.logicalSeatIndex)) return seat.logicalSeatIndex!;\n const i = seat.id.lastIndexOf(':');\n if (i < 0) return fallback;\n const n = Number(seat.id.slice(i + 1));\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction dist2(a: Point, b: Point): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return dx * dx + dy * dy;\n}\n\n/** Centroid of a set of seats. */\nfunction centroid(seats: ExpandedSeat[]): Point {\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\nfunction candidateFocal(seats: ExpandedSeat[], fallback: Point): Point {\n return seats.find((seat) => seat.focalPoint)?.focalPoint ?? fallback;\n}\n\nfunction isPremium(seat: ExpandedSeat): boolean {\n return seat.commercial?.premium === true;\n}\n\ninterface Slot {\n seat: ExpandedSeat;\n index: number;\n /** Eligible = available AND (no category filter OR category matches). */\n elig: boolean;\n}\n\ninterface Candidate {\n labels: string[];\n seats: ExpandedSeat[];\n rowId: string;\n startIndex: number;\n /** 1 when taking this run strands a lone free seat; 0 otherwise. */\n orphan: number;\n /** Count of non-premium seats in the run — only scored when preferPremium. */\n nonPremium: number;\n d2: number;\n}\n\n/**\n * Pick the `qty` best available seats. Returns `{ labels }` on success, or\n * `{ labels: [], reason }` when the request can't be satisfied at all.\n */\nexport function pickBestAvailable(\n seats: ExpandedSeat[],\n available: Set<string>,\n opts: BestAvailableOpts,\n): BestAvailableResult {\n const qty = Math.floor(opts.qty);\n if (!Number.isFinite(qty) || qty <= 0) return { labels: [], reason: 'sold_out' };\n const { categoryKey, zoneId, focal, preferPremium } = opts;\n\n // Group ALL seats by row (we need the non-eligible ones too, to detect gaps\n // and orphans), preserving original order for a stable fallback tie-break.\n const rows = new Map<string, Slot[]>();\n const eligibleAll: ExpandedSeat[] = [];\n seats.forEach((seat, i) => {\n const elig = available.has(seat.label)\n && (!categoryKey || seat.categoryKey === categoryKey)\n && (!zoneId || seat.zoneId === zoneId);\n const rowId = seat.logicalRowId ?? seat.rowId;\n let arr = rows.get(rowId);\n if (!arr) {\n arr = [];\n rows.set(rowId, arr);\n }\n arr.push({ seat, index: seatIndex(seat, i), elig });\n if (elig) eligibleAll.push(seat);\n });\n\n if (eligibleAll.length === 0) return { labels: [], reason: 'sold_out' };\n\n // --- 1) single-row contiguous runs of `qty` adjacent-available seats ---\n let best: Candidate | null = null;\n const better = (c: Candidate): boolean => {\n if (!best) return true;\n // Premium bias (opt-in) outranks everything else so the buyer lands the\n // best PREMIUM block; inert when preferPremium is off (nonPremium === 0).\n if (preferPremium && c.nonPremium !== best.nonPremium) return c.nonPremium < best.nonPremium;\n if (c.orphan !== best.orphan) return c.orphan < best.orphan;\n if (c.d2 !== best.d2) return c.d2 < best.d2;\n const r = c.rowId.localeCompare(best.rowId);\n if (r !== 0) return r < 0;\n return c.startIndex < best.startIndex;\n };\n\n for (const [rowId, slotsUnsorted] of rows) {\n const slots = [...slotsUnsorted].sort((a, b) => a.index - b.index);\n // Walk maximal eligible segments. A non-eligible slot (taken / wrong\n // category / missing) breaks contiguity.\n let i = 0;\n while (i < slots.length) {\n if (!slots[i].elig) {\n i++;\n continue;\n }\n let j = i;\n while (\n j < slots.length\n && slots[j].elig\n && (j === i || slots[j].index === slots[j - 1].index + 1)\n ) j++;\n const segLen = j - i; // eligible run [i, j)\n // Every window of `qty` within this segment is a candidate.\n for (let p = 0; p + qty <= segLen; p++) {\n const leftRem = p; // eligible seats stranded to the left of the window\n const rightRem = segLen - (p + qty); // …and to the right\n const orphan = leftRem === 1 || rightRem === 1 ? 1 : 0;\n const runSeats = slots.slice(i + p, i + p + qty).map((s) => s.seat);\n const c: Candidate = {\n labels: runSeats.map((s) => s.label),\n seats: runSeats,\n rowId,\n startIndex: slots[i + p].index,\n orphan,\n nonPremium: preferPremium ? runSeats.reduce((n, s) => n + (isPremium(s) ? 0 : 1), 0) : 0,\n d2: dist2(centroid(runSeats), candidateFocal(runSeats, focal)),\n };\n if (better(c)) best = c;\n }\n i = j;\n }\n }\n\n if (best) return { labels: best.labels };\n\n // --- 2) fallback: the `qty` closest-to-focal seats overall (may span rows) ---\n if (eligibleAll.length < qty) return { labels: [], reason: 'not_enough_together' };\n\n const ranked = eligibleAll\n .map((seat, i) => ({ seat, i, d2: dist2(seat, seat.focalPoint ?? focal) }))\n .sort((a, b) => {\n // Premium-first when biased (inert otherwise — both sides score 0).\n if (preferPremium) {\n const pa = isPremium(a.seat) ? 0 : 1;\n const pb = isPremium(b.seat) ? 0 : 1;\n if (pa !== pb) return pa - pb;\n }\n if (a.d2 !== b.d2) return a.d2 - b.d2;\n const r = (a.seat.logicalRowId ?? a.seat.rowId).localeCompare(b.seat.logicalRowId ?? b.seat.rowId);\n if (r !== 0) return r;\n return seatIndex(a.seat, a.i) - seatIndex(b.seat, b.i);\n });\n\n return { labels: ranked.slice(0, qty).map((r) => r.seat.label) };\n}\n","import { allObjects, expandTable } from './layout';\nimport type { ChartDoc, ExpandedSeat, TableObject } from './types';\n\nexport type ClientInventoryModelVersion = 1 | 2;\nexport type GroupedTableBookingMode = 'whole' | 'variable';\n\n/**\n * Buyer-side projection of one atomic table inventory unit. The physical\n * chairs remain renderer geometry, but `label` is the only booking identity.\n */\nexport interface GroupedTableInventoryUnit {\n objectId: string;\n label: string;\n displayLabel?: string;\n displayType?: string;\n categoryKey: string;\n mode: GroupedTableBookingMode;\n capacity: number;\n minOccupancy: number;\n maxOccupancy: number;\n chairs: ExpandedSeat[];\n}\n\nexport class GroupedTableProjectionError extends Error {\n constructor(\n readonly objectId: string,\n message: string,\n ) {\n super(message);\n this.name = 'GroupedTableProjectionError';\n }\n}\n\nfunction bounds(table: TableObject): { min: number; max: number } {\n const min = table.minOccupancy;\n const max = table.maxOccupancy;\n if (\n !Number.isInteger(min)\n || !Number.isInteger(max)\n || min! < 1\n || max! < min!\n || max! > table.seatCount\n ) {\n throw new GroupedTableProjectionError(\n table.id,\n `Table \"${table.label}\" has invalid variable-occupancy bounds`,\n );\n }\n return { min: min!, max: max! };\n}\n\n/**\n * Project grouped tables only for the event's explicit model-2 contract.\n * Model 1 deliberately returns no groups even if a legacy snapshot happens to\n * carry a grouping flag, preserving per-chair selection byte-for-byte.\n */\nexport function groupedTableInventory(\n doc: ChartDoc,\n modelVersion: ClientInventoryModelVersion,\n): GroupedTableInventoryUnit[] {\n if (modelVersion !== 2) return [];\n const units: GroupedTableInventoryUnit[] = [];\n for (const object of allObjects(doc)) {\n if (object.type !== 'table' || (!object.bookAsWhole && !object.variableOccupancy)) continue;\n if (object.bookAsWhole && object.variableOccupancy) {\n throw new GroupedTableProjectionError(\n object.id,\n `Table \"${object.label}\" cannot be whole-table and variable-occupancy inventory`,\n );\n }\n if (!Number.isInteger(object.seatCount) || object.seatCount < 1 || !object.label.trim()) {\n throw new GroupedTableProjectionError(object.id, 'Grouped tables require a label and at least one chair');\n }\n const mode: GroupedTableBookingMode = object.variableOccupancy ? 'variable' : 'whole';\n const occupancy = mode === 'variable'\n ? bounds(object)\n : { min: object.seatCount, max: object.seatCount };\n units.push({\n objectId: object.id,\n label: object.label,\n ...(object.displayLabel ? { displayLabel: object.displayLabel } : {}),\n ...(object.displayType ? { displayType: object.displayType } : {}),\n categoryKey: object.categoryKey,\n mode,\n capacity: object.seatCount,\n minOccupancy: occupancy.min,\n maxOccupancy: occupancy.max,\n chairs: expandTable(object),\n });\n }\n return units;\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 { pickBestAvailable } from '../core/bestAvailable';\nimport { t } from '../i18n';\nimport type {\n AccessibilityType,\n CategoryTier,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n RendererCallbacks,\n RendererViewMode,\n SeatCommercialAttributes,\n SeatStatus,\n SectionObject,\n} from '../core/types';\nimport { gaAreasOf, gaUnitLabels } from '../core/ga';\nimport {\n groupedTableInventory,\n type GroupedTableInventoryUnit,\n} from '../core/tableInventory';\n\nconst DEFAULT_MAX_SELECTION = 10;\nconst MAX_BACKOFF_MS = 15_000;\n\nexport interface PickerSeat {\n id: string;\n label: string;\n /** Buyer-facing label (row `displayLabel` applied). Falls back to `label`;\n * never use for booking — `label` is the inventory/booking identity. */\n displayLabel?: string;\n /** Buyer-facing object type word authored in Designer. Pure presentation. */\n displayType?: string;\n /** @deprecated Use `displayType`; retained for source compatibility. */\n rowType?: string;\n /** Stable parent chart-object id (row/table/booth), separate from seat id. */\n objectId?: string;\n /** Buyer-facing spatial context shared by selection, hold, and hover callbacks. */\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: 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 /** Accessibility semantics exposed to SDK callbacks and buyer summaries. */\n accessibility?: AccessibilityType[];\n /** Explicit physical wheelchair chair/bay distinction. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n /** Physical/bookable source kind; booking identity remains `label`. */\n objectType?: 'seat' | 'booth' | 'table';\n /** Grouped-table booking contract; absent for normal chair inventory. */\n bookingMode?: 'whole' | 'variable';\n /** Guest quantity represented by this one atomic table line. */\n quantity?: number;\n capacity?: number;\n minOccupancy?: number;\n maxOccupancy?: number;\n}\n\n/** Accessible quantity/confirmation payload for one model-2 table selection. */\nexport interface TableSelectionDetails extends PickerSeat {\n objectType: 'table';\n bookingMode: 'whole' | 'variable';\n quantity: number;\n capacity: number;\n minOccupancy: number;\n maxOccupancy: number;\n physicalSeatIds: 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}\n\nexport interface PickerGAArea {\n id: string;\n /** Stable technical/inventory prefix. */\n label: string;\n /** Buyer-facing area name and type; absent fields use UI defaults. */\n displayLabel?: string;\n displayType?: string;\n capacity: number;\n available: number;\n categoryKey: string;\n price: number;\n currency: string;\n tiers?: CategoryTier[];\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 /** Buyer-facing section name (`displayLabel` when set, else the inventory label). */\n label: string;\n /** Zone label (from ChartDoc.zones); '' when the section has no zone. */\n zoneLabel: string;\n /** Buyer-facing entrance/door hint (\"Entrance X\"); absent when unset. */\n entrance?: 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' | 'table';\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; quantity?: number }\ninterface BestAvailableResponse extends HoldResponse {\n labels: string[];\n}\n\n/** One unit's status as the realtime wire words it (`free`/`held`/`booked`/`blocked`/…). */\nexport interface PickerStatusChange {\n label: string;\n status: string;\n}\n\n/**\n * Where a transport-owned realtime client pushes reconstructed inventory.\n *\n * Structurally identical to the SDK's `RealtimeSink` on purpose: this file is\n * mirrored byte-for-byte into `@seatlayer/core`, which the SDK's `@seatlayer/js`\n * depends on — so it can never import BuyerRealtimeClient without inverting that\n * dependency. Structural typing lets the SDK hand its client this object with no\n * import in either direction.\n */\nexport interface PickerRealtimeSink {\n /** Apply a batch of label→status changes as ONE paint pass, not one per label. */\n applyStatuses(changes: PickerStatusChange[]): void;\n /** Re-pull authoritative state over HTTP (a frame that cannot be diffed). */\n resync(): void | Promise<void>;\n /** Section availability changed (hidden = stripped, closed = greyed). */\n onSections?(hidden: string[], closed: string[]): void;\n /** Scope-projected presence counters. Unused by the picker today. */\n onPresence?(counts: { shoppingSessions: number; activeHolds: number }): void;\n}\n\n/** The live feed itself, owned by the transport. */\nexport interface PickerRealtimeConnection {\n start(): void;\n stop(): void;\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; inventoryModelVersion?: 1 | 2 };\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, zoneId?: string, ttlMs?: number): 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 /** Optional — WebSocket subprotocols for the live feed (e.g. a one-use\n * subscribe ticket via `Sec-WebSocket-Protocol`, realtime-protocol v1).\n * Absent or empty means today's plain connection. */\n socketProtocols?(key: string): string[];\n /**\n * Optional — the transport owns the live feed and hands back a client that\n * speaks the compact `seatlayer.v1` protocol (snapshot diffing, `sv.<n>`\n * resume, ping/pong liveness, jittered reconnect).\n *\n * When this returns a connection the controller does NOT open its own socket:\n * one socket client, one reconnect/backoff/resume implementation. Returning\n * null (or omitting the method) keeps the plain-WebSocket path below, which is\n * what a transport with no realtime client of its own still gets.\n */\n createRealtime?(key: string, sink: PickerRealtimeSink): PickerRealtimeConnection | null;\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 grouped table was selected and needs buyer confirmation/guest quantity. */\n onTableSelectionRequest?: (table: TableSelectionDetails) => 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, {\n objectId: string;\n objectType: 'seat' | 'booth' | 'table';\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: string;\n displayType?: string;\n /** @deprecated compatibility alias for older tooltip consumers. */\n rowType?: string;\n }>();\n private allIds: string[] = [];\n /** Model-2 tables are one booking unit whose chairs remain renderer geometry. */\n private groupedTablesByObject = new Map<string, GroupedTableInventoryUnit>();\n private groupedTablesByLabel = new Map<string, GroupedTableInventoryUnit>();\n private groupedTableBySeatId = new Map<string, GroupedTableInventoryUnit>();\n private tableQuantities = new Map<string, number>();\n /** Variable quantity is a buyer contract, never an inferred default. */\n private confirmedVariableTables = new Set<string>();\n private groupedSelectionOverhead = 0;\n\n // realtime socket\n private ws: WebSocket | null = null;\n /** Transport-owned v1 client; mutually exclusive with `ws`. */\n private realtime: PickerRealtimeConnection | 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 private idsForLabel(label: string): string[] {\n const table = this.groupedTablesByLabel.get(label);\n if (table) return table.chairs.map((chair) => chair.id);\n const id = this.labelToId.get(label);\n return id ? [id] : [];\n }\n\n private idsForLabels(labels: Iterable<string>): string[] {\n return [...new Set([...labels].flatMap((label) => this.idsForLabel(label)))];\n }\n\n /** Resolve a physical chair id (or table inventory label) to its table unit. */\n tableSelection(seatIdOrLabel: string): TableSelectionDetails | null {\n const group = this.groupedTableBySeatId.get(seatIdOrLabel)\n ?? this.groupedTablesByLabel.get(seatIdOrLabel);\n return group ? this.toTableSeat(group) : null;\n }\n\n /**\n * Buyer-facing name + type word for a checkout line item, resolved from the\n * SAME author overrides the tray/tooltip already render. `label` stays the\n * booking identity; a host builds its own order summary from `displayLabel`/\n * `displayType` so the buyer sees the designer's copy, not the internal label.\n * Absent fields = no override (host falls back to `label`).\n */\n lineItemDisplay(\n item: { label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga' | 'table' },\n ): { displayLabel?: string; displayType?: string } {\n if (item.objectType === 'ga') {\n const doc = this.visibleDoc();\n const area = gaAreasOf(doc).find((candidate) => candidate.id === item.objectId);\n return {\n ...(area?.displayLabel ? { displayLabel: area.displayLabel } : {}),\n ...(area?.displayType ? { displayType: area.displayType } : {}),\n };\n }\n if (item.objectType === 'table') {\n const group = this.groupedTablesByLabel.get(item.label);\n return {\n ...(group?.displayLabel && group.displayLabel !== group.label ? { displayLabel: group.displayLabel } : {}),\n ...(group?.displayType ? { displayType: group.displayType } : {}),\n };\n }\n const seat = this.labelToSeat.get(item.label);\n const context = seat ? this.seatContext.get(seat.id) : undefined;\n return {\n ...(seat?.displayLabel ? { displayLabel: seat.displayLabel } : {}),\n ...(context?.displayType ? { displayType: context.displayType } : {}),\n };\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 try {\n const groups = groupedTableInventory(\n res.doc,\n res.event.inventoryModelVersion === 2 ? 2 : 1,\n );\n this.groupedTablesByObject = new Map(groups.map((group) => [group.objectId, group]));\n this.groupedTablesByLabel = new Map(groups.map((group) => [group.label, group]));\n this.groupedTableBySeatId = new Map(\n groups.flatMap((group) => group.chairs.map((chair) => [chair.id, group] as const)),\n );\n this.tableQuantities = new Map(groups.map((group) => [\n group.label,\n group.mode === 'whole' ? group.capacity : group.minOccupancy,\n ]));\n this.confirmedVariableTables = new Set();\n this.groupedSelectionOverhead = groups.reduce(\n (sum, group) => sum + Math.max(0, group.chairs.length - 1),\n 0,\n );\n } catch (err) {\n // A model-2 event with an invalid grouping contract is not safe to sell.\n // Fail before mounting the interactive renderer instead of falling back\n // to per-chair labels that the server does not own.\n this.emitError(err);\n return null;\n }\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 logicalRow = source?.type === 'row' ? source.segmentedRow : undefined;\n // Buyer-facing row name honours the designer's row `displayLabel`; inventory\n // `label` stays the booking identity used everywhere seats are held/booked.\n const sourceDisplayLabel = logicalRow?.displayLabel\n ?? (source && 'displayLabel' in source && typeof source.displayLabel === 'string' && source.displayLabel\n ? source.displayLabel\n : sourceLabel);\n const groupedTable = this.groupedTablesByObject.get(s.rowId);\n const objectType = source?.type === 'table' ? 'table' : source?.type === 'booth' ? 'booth' : 'seat';\n const rowLabel = sourceDisplayLabel;\n // Buyer-facing type word override (seats.io \"Displayed type\") — replaces the\n // default \"Row\" in tooltip/confirm/cart for rows and tables when set.\n const rowType = logicalRow?.displayType?.trim()\n || (source && 'displayType' in source && typeof source.displayType === 'string' && source.displayType.trim()\n ? source.displayType.trim()\n : undefined);\n // Seat number is read off the buyer-facing seat label so a renamed row shows\n // the buyer copy; both labels share the same `${prefix}-${number}` suffix.\n const visibleSeatLabel = s.displayLabel ?? s.label;\n const labelParts = visibleSeatLabel.split('-');\n const seatNumber = groupedTable\n ? undefined\n : s.kind === 'booth'\n ? undefined\n : sourceDisplayLabel && visibleSeatLabel.startsWith(`${sourceDisplayLabel}-`)\n ? visibleSeatLabel.slice(sourceDisplayLabel.length + 1)\n : labelParts[labelParts.length - 1] ?? visibleSeatLabel;\n this.seatContext.set(s.id, {\n objectId: s.rowId,\n objectType,\n sectionLabel: sectionLabels.get(membership.objectToSection.get(s.rowId) ?? ''),\n rowLabel,\n seatNumber,\n ...(rowType ? { displayType: rowType, rowType } : {}),\n });\n }\n // The backend speaks the table label, while the renderer still speaks chair\n // ids. Point the atomic label at a stable representative chair; every\n // status/selection mutation expands through idsForLabel() below.\n for (const group of this.groupedTablesByLabel.values()) {\n const representative = group.chairs[0];\n if (!representative) continue;\n this.labelToId.set(group.label, representative.id);\n this.labelToSeat.set(group.label, representative);\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 // Group chairs are selected together for paint, but count as one logical\n // inventory line. The controller enforces the guest-weighted cap.\n maxSelection: this.rendererSelectionCap(),\n confirmSelection: this.opts.confirmSelection,\n currency,\n onSelect: (seat) => {\n this.handleRendererSelect(seat);\n },\n onDeselect: (seat) => {\n this.handleRendererDeselect(seat);\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 const out: PickerSeat[] = [];\n const grouped = new Set<string>();\n for (const seat of this.renderer.getSelection()) {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n if (!grouped.has(table.label)) {\n grouped.add(table.label);\n out.push(this.toTableSeat(table));\n }\n } else {\n out.push(this.toSeat(seat));\n }\n }\n return out;\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.resetUnheldTableQuantities();\n this.emitSelectionChange();\n }\n deselect(ids: string[]): void {\n const expanded = new Set<string>();\n for (const id of ids) {\n const table = this.groupedTableBySeatId.get(id) ?? this.groupedTablesByLabel.get(id);\n if (table) {\n table.chairs.forEach((chair) => expanded.add(chair.id));\n if (!this.hold_?.labels.includes(table.label)) {\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n } else expanded.add(id);\n }\n this.renderer?.deselect([...expanded]);\n this.emitSelectionChange();\n }\n setMaxSelection(maxSelection: number): void {\n this.maxSelection = Math.max(0, Math.floor(maxSelection));\n this.renderer?.setMaxSelection?.(this.rendererSelectionCap());\n }\n select(ids: string[]): PickerSeat[] {\n const before = new Set(this.getSelection().map((seat) => seat.label));\n const expanded = new Set<string>();\n for (const id of ids) {\n const table = this.groupedTableBySeatId.get(id) ?? this.groupedTablesByLabel.get(id);\n if (table) table.chairs.forEach((chair) => expanded.add(chair.id));\n else expanded.add(id);\n }\n this.renderer?.select?.([...expanded]);\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect([...expanded]);\n this.opts.onSelectionLimit?.(this.maxSelection);\n return [];\n }\n const added = this.getSelection().filter((seat) => !before.has(seat.label));\n if (added.length) this.emitSelectionChange();\n return added;\n }\n\n /** Confirm/update the guest quantity for a selected variable table. */\n setTableQuantity(label: string, quantity: number): boolean {\n const table = this.groupedTablesByLabel.get(label);\n if (!table) return false;\n const q = table.mode === 'whole' ? table.capacity : Math.floor(quantity);\n if (!Number.isInteger(q) || q < table.minOccupancy || q > table.maxOccupancy) return false;\n const previous = this.tableQuantities.get(label) ?? table.minOccupancy;\n this.tableQuantities.set(label, q);\n if (this.selectionGuestCount() > this.maxSelection) {\n this.tableQuantities.set(label, previous);\n this.opts.onSelectionLimit?.(this.maxSelection);\n return false;\n }\n if (table.mode === 'variable') this.confirmedVariableTables.add(label);\n this.emitSelectionChange();\n return true;\n }\n\n /**\n * Atomically replace an active variable-table hold with a new guest count.\n * `ttlMs` keeps the host's checkout window across the replacement — without it\n * a guest-count change silently re-based the countdown on the server default.\n */\n async replaceTableQuantity(label: string, quantity: number, ttlMs?: number): Promise<HoldInfo | null> {\n const table = this.groupedTablesByLabel.get(label);\n const hold = this.hold_;\n if (!table || table.mode !== 'variable' || !hold?.labels.includes(label)) return null;\n const q = Math.floor(quantity);\n if (!Number.isInteger(q) || q < table.minOccupancy || q > table.maxOccupancy) return null;\n const otherGuests = (hold.items ?? [])\n .filter((item) => item.label !== label)\n .reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n if (otherGuests + q > this.maxSelection) {\n this.opts.onSelectionLimit?.(this.maxSelection);\n return null;\n }\n const selections: HoldSelectionRequest[] = (hold.items ?? []).map((item) => ({\n label: item.label,\n tierId: item.tierId,\n quantity: item.label === label ? q : item.quantity,\n }));\n if (!selections.some((item) => item.label === label)) return null;\n const result = await this.api.hold(this.key, selections, ttlMs, hold.holdId);\n this.tableQuantities.set(label, q);\n this.setHold({\n holdId: result.holdId,\n labels: selections.map((item) => item.label),\n expiresAt: result.expiresAt,\n items: result.items,\n });\n return this.hold_;\n }\n\n private rendererSelectionCap(): number {\n return this.maxSelection + this.groupedSelectionOverhead;\n }\n\n private selectionGuestCount(): number {\n return this.getSelection().reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n }\n\n private handleRendererSelect(seat: ExpandedSeat): void {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect(table.chairs.map((chair) => chair.id));\n this.opts.onSelectionLimit?.(this.maxSelection);\n this.emitSelectionChange();\n return;\n }\n // One click paints every chair as selected; the public selection remains\n // one table line through getSelection(). Programmatic select is silent.\n this.renderer?.select?.(table.chairs.map((chair) => chair.id));\n this.opts.onSelect?.(table.chairs[0] ?? seat);\n this.opts.onTableSelectionRequest?.(this.toTableSeat(table));\n this.emitSelectionChange();\n return;\n }\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect([seat.id]);\n this.opts.onSelectionLimit?.(this.maxSelection);\n this.emitSelectionChange();\n return;\n }\n this.opts.onSelect?.(seat);\n this.emitSelectionChange();\n }\n\n private handleRendererDeselect(seat: ExpandedSeat): void {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n this.renderer?.deselect(table.chairs.map((chair) => chair.id));\n if (!this.hold_?.labels.includes(table.label)) {\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n this.opts.onDeselect?.(table.chairs[0] ?? seat);\n } else {\n this.opts.onDeselect?.(seat);\n }\n this.emitSelectionChange();\n }\n\n private resetUnheldTableQuantities(): void {\n for (const table of this.groupedTablesByLabel.values()) {\n if (this.hold_?.labels.includes(table.label)) continue;\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n }\n\n private resetTableQuantitiesForLabels(labels: Iterable<string>): void {\n for (const label of labels) {\n const table = this.groupedTablesByLabel.get(label);\n if (!table) continue;\n this.tableQuantities.set(\n label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(label);\n }\n }\n\n private tableQuantityRequest(seat: PickerSeat | null): { quantity?: number } {\n if (seat?.objectType !== 'table') return {};\n if (seat.bookingMode === 'variable' && !this.confirmedVariableTables.has(seat.label)) {\n throw new Error('picker: confirm a variable table guest quantity before holding');\n }\n return { quantity: seat.quantity };\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 ?? this.getSelection().map((seat) => seat.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, quantity: ga.quantity };\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return {\n label,\n ...(resolved?.tierId ? { tierId: resolved.tierId } : {}),\n ...this.tableQuantityRequest(resolved),\n };\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 (this.groupedTableBySeatId.has(id)) continue;\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 for (const table of this.groupedTablesByLabel.values()) {\n if (table.chairs.some((chair) => closedMembers.has(chair.id))) continue;\n const representative = table.chairs[0];\n if (representative && (this.getStatus(representative.id) ?? 'free') === 'free') {\n // Availability is guest capacity, while atomic ownership remains one row.\n out[table.categoryKey] = (out[table.categoryKey] ?? 0) + table.maxOccupancy;\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(): PickerGAArea[] {\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 ...(area.displayLabel ? { displayLabel: area.displayLabel } : {}),\n ...(area.displayType ? { displayType: area.displayType } : {}),\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, HoldSelectionRequest>();\n for (const item of this.hold_?.items ?? []) selections.set(item.label, {\n label: item.label,\n tierId: item.tierId,\n quantity: item.quantity,\n });\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.getSelection()) {\n selections.set(seat.label, {\n label: seat.label,\n ...(seat.tierId ? { tierId: seat.tierId } : {}),\n ...this.tableQuantityRequest(seat),\n });\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 /** True when any seat on the visible chart carries the `premium` commercial\n * flag — gates the buyer widget's \"★ Best seats\" premium quick-pick (chip is\n * present-only, exactly like the accessibility filter chips). */\n hasPremiumSeats(): boolean {\n for (const seat of this.labelToSeat.values()) {\n if (seat.commercial?.premium) return true;\n }\n return false;\n }\n\n /** Zones which still own visible buyer inventory, in authored order. */\n getBestAvailableZones(): Array<{ id: string; label: string }> {\n const doc = this.visibleDoc();\n if (!doc?.zones?.length) return [];\n const used = new Set(\n computeSections(doc).sections\n .filter((section) => section.seatCount > 0 && !!section.zone)\n .map((section) => section.zone!),\n );\n return doc.zones.filter((zone) => used.has(zone.id)).map((zone) => ({ id: zone.id, label: zone.label }));\n }\n\n /**\n * Client-side premium pre-pass: find the best contiguous block of `qty`\n * PREMIUM-flagged free seats (orphan-avoiding, closest to the focal point)\n * using the local seat geometry + live availability, mirroring the server's\n * held-back exclusion via the visible (hidden-stripped) chart and current\n * seat status. Returns a FULL premium block of `qty`, or null when none\n * exists (the caller then falls back to the normal server pick).\n */\n private pickPremiumBlock(qty: number, categoryKey?: string, zoneId?: string): string[] | null {\n const doc = this.visibleDoc();\n if (!doc?.objects?.length) return null;\n const focal = doc.focalPoint ?? { x: 0, y: 0 };\n const groupedObjectIds = new Set(this.groupedTablesByObject.keys());\n // Group chairs are geometry, never adjacency inventory. Excluding their\n // rowIds prevents premium fallback from bridging/splitting a table.\n const seats = expandChart(doc).filter((seat) => !groupedObjectIds.has(seat.rowId));\n const held = new Set(this.hold_?.labels ?? []);\n const available = new Set<string>();\n for (const seat of seats) {\n if (held.has(seat.label)) continue;\n const id = this.labelToId.get(seat.label);\n const status = id ? this.getStatus(id) : undefined;\n if ((status ?? 'free') === 'free') available.add(seat.label);\n }\n const pick = pickBestAvailable(seats, available, { qty, categoryKey, zoneId, focal, preferPremium: true });\n if (pick.labels.length !== qty) return null;\n // Only treat it as a premium block when EVERY picked seat is premium — a\n // partial run means there's no true premium block of `qty` to offer.\n const allPremium = pick.labels.every((l) => this.labelToSeat.get(l)?.commercial?.premium);\n return allPremium ? [...pick.labels] : null;\n }\n\n /**\n * Server-picks `qty` best free seats and holds them atomically. Throws on\n * failure. With `preferPremium`, first tries to hold the best PREMIUM block\n * locally; when none matches the requested quantity it falls back to the\n * normal server pick (the widget surfaces a subtle note on that fallback).\n *\n * `ttlMs` is the host's checkout window and MUST reach both branches: a hold\n * born here is the same buyer commitment as one made by clicking seats, so\n * omitting it silently handed the buyer the server default instead.\n */\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: { preferPremium?: boolean; zoneId?: string; ttlMs?: number } = {},\n ): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n if (opts.preferPremium) {\n const block = this.pickPremiumBlock(qty, categoryKey, opts.zoneId);\n if (block) {\n // Drop any prior auto-hold before claiming the premium block.\n if (this.hold_ && !(await this.release())) return null;\n try {\n const selection = block.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 const result = await this.api.hold(this.key, selection, opts.ttlMs);\n r.clearSelection();\n const ids = this.idsForLabels(block);\n if (ids.length) r.setStatus(ids, 'held');\n this.setHold({ holdId: result.holdId, labels: [...block], expiresAt: result.expiresAt, items: result.items });\n const seats = block\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') {\n this.opts.onSalesClosed?.();\n throw err;\n }\n // Lost a race for the premium block (a seat was taken) — fall through\n // to the atomic server pick below rather than failing the buyer.\n }\n }\n // No premium block available — fall through to the normal server pick.\n }\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, opts.zoneId, opts.ttlMs);\n r.clearSelection();\n const ids = this.idsForLabels(result.labels);\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 * `ttlMs` only matters on the hold-first path: if the book call then fails, the\n * seats sit held for the host's window rather than the longer server default.\n */\n async book(bookingRef: string, labelsArg?: string[], ttlMs?: number): 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 ?? this.getSelection().map((seat) => seat.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 {\n label,\n ...(resolved?.tierId ? { tierId: resolved.tierId } : {}),\n ...this.tableQuantityRequest(resolved),\n };\n }),\n ttlMs,\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 = this.idsForLabels(takenLabels);\n if (takenIds.length) {\n r.setStatus(takenIds, 'booked');\n r.deselect(takenIds);\n this.resetTableQuantitiesForLabels(takenLabels);\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 = this.idsForLabels(labels);\n if (ids.length) {\n r.setStatus(ids, 'booked');\n r.deselect(ids);\n }\n this.clearHold();\n this.resetTableQuantitiesForLabels(labels);\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 this.resetTableQuantitiesForLabels(hold.labels);\n const ids = this.idsForLabels(hold.labels);\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 this.resetTableQuantitiesForLabels(drop);\n const ids = this.idsForLabels(drop);\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. No-op on a flat-only renderer. */\n setViewMode(mode: RendererViewMode): void {\n this.renderer?.setViewMode?.(mode);\n }\n getViewMode(): RendererViewMode {\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 const seenTables = new Set<string>();\n let seatsLeft = 0;\n for (const sid of memberIds) {\n const seat = this.seatById.get(sid);\n if (!seat) continue;\n const table = this.groupedTableBySeatId.get(sid);\n if (table) {\n if (seenTables.has(table.label)) continue;\n seenTables.add(table.label);\n byCat.set(table.categoryKey, (byCat.get(table.categoryKey) ?? 0) + table.maxOccupancy);\n if (r.getStatus(table.chairs[0]?.id ?? sid) === 'free') seatsLeft += table.maxOccupancy;\n } else {\n byCat.set(seat.categoryKey, (byCat.get(seat.categoryKey) ?? 0) + 1);\n if (r.getStatus(sid) === 'free') seatsLeft++;\n }\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.displayLabel ?? sec.label,\n zoneLabel: zone?.label ?? '',\n ...(sec.entrance && sec.entrance.trim() ? { entrance: sec.entrance.trim() } : {}),\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.realtime) {\n try {\n this.realtime.stop();\n } catch {\n /* ignore */\n }\n this.realtime = 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 table = this.groupedTableBySeatId.get(s.id);\n if (table) return this.toTableSeat(table);\n const commercial = s.commercial ? { commercial: s.commercial } : undefined;\n const display = s.displayLabel ? { displayLabel: s.displayLabel } : undefined;\n const accessibility = s.accessibility?.length ? { accessibility: s.accessibility } : undefined;\n const wheelchair = s.wheelchairSpaceType ? { wheelchairSpaceType: s.wheelchairSpaceType } : undefined;\n const context = this.seatContext.get(s.id);\n const tiers = this.tiersFor(s.categoryKey);\n if (!tiers) {\n return { id: s.id, label: s.label, ...display, ...context, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), ...commercial, ...accessibility, ...wheelchair };\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 ...display,\n ...context,\n categoryKey: s.categoryKey,\n price: chosen.price,\n tiers,\n tierId: chosen.id,\n ...commercial,\n ...accessibility,\n ...wheelchair,\n };\n }\n\n private toTableSeat(table: GroupedTableInventoryUnit): TableSelectionDetails {\n const representative = table.chairs[0];\n const tiers = this.tiersFor(table.categoryKey);\n const chosen = tiers?.find((tier) => tier.id === this.seatTiers.get(representative?.id ?? '')) ?? tiers?.[0];\n return {\n id: representative?.id ?? table.objectId,\n label: table.label,\n displayLabel: table.displayLabel ?? table.label,\n ...(table.displayType ? { displayType: table.displayType, rowType: table.displayType } : {}),\n objectId: table.objectId,\n sectionLabel: representative ? this.seatContext.get(representative.id)?.sectionLabel : undefined,\n rowLabel: table.displayLabel ?? table.label,\n categoryKey: table.categoryKey,\n price: chosen?.price ?? this.priceFor(table.categoryKey),\n ...(tiers ? { tiers, tierId: chosen?.id } : {}),\n objectType: 'table',\n bookingMode: table.mode,\n quantity: this.tableQuantities.get(table.label)\n ?? (table.mode === 'whole' ? table.capacity : table.minOccupancy),\n capacity: table.capacity,\n minOccupancy: table.minOccupancy,\n maxOccupancy: table.maxOccupancy,\n physicalSeatIds: table.chairs.map((chair) => chair.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 const quantities = new Map((h.items ?? []).map((item) => [item.label, item.quantity ?? 1]));\n return labels.every((label) => {\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n const currentTier = resolved?.tierId ?? null;\n const quantityMatches = resolved?.objectType !== 'table'\n || (resolved.bookingMode !== 'variable' || this.confirmedVariableTables.has(label))\n && (!quantities.has(label) || quantities.get(label) === resolved.quantity);\n return quantityMatches && (!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 = this.idsForLabels(conflicts.map((conflict) => conflict.label));\n if (takenIds.length) {\n r.deselect(takenIds);\n r.setStatus(takenIds, 'held');\n this.resetTableQuantitiesForLabels(conflicts.map((conflict) => conflict.label));\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 for (const item of hold.items ?? []) {\n if (this.groupedTablesByLabel.has(item.label) && item.quantity != null) {\n this.tableQuantities.set(item.label, item.quantity);\n if (this.groupedTablesByLabel.get(item.label)?.mode === 'variable') {\n this.confirmedVariableTables.add(item.label);\n }\n }\n }\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 this.idsForLabels(full.labels),\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.idsForLabels(this.hold_?.labels ?? []),\n );\n const byStatus: Record<SeatStatus, string[]> = { free: [], held: [], booked: [], not_for_sale: [] };\n for (const [label, st] of Object.entries(seats)) {\n byStatus[mapStatus(st)].push(...this.idsForLabel(label));\n }\n (['held', 'booked', 'not_for_sale'] as SeatStatus[]).forEach((st) => {\n if (byStatus[st].length) r.setStatus(byStatus[st], st);\n });\n // Clear a completed checkout hold before notifying the widget. `onStatusChange`\n // is where SeatPicker detects a booking; notifying first left the hosted\n // buyer stranded on \"Continue to checkout\" even though the API had booked\n // the seats successfully.\n this.clearBookedHoldIfSettled();\n this.opts.onStatusChange?.();\n }\n\n private clearBookedHoldIfSettled(): void {\n const hold = this.hold_;\n if (hold?.labels.every((label) => this.liveStatuses.get(label) === 'booked')) {\n this.clearHold();\n this.resetTableQuantitiesForLabels(hold.labels);\n }\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 /**\n * The sink a transport-owned v1 client pushes into.\n *\n * Deliberately byte-compatible with the inline socket handler below: the same\n * liveStatuses bookkeeping (which the hold-expiry verification reads), the\n * same one-call-per-status paint, the same free→taken flash rule that skips\n * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the\n * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same\n * callbacks in the same order whichever path is live.\n */\n private realtimeSink(): PickerRealtimeSink {\n return {\n applyStatuses: (changes) => this.applyStatusChanges(changes),\n resync: () => this.resnapshot(),\n onSections: (hidden, closed) => {\n // Hidden sections STRIP seats, so the chart is rebuilt and repainted\n // from an authoritative snapshot; closed sections are a cheap grey\n // restyle. Same reconciliation the inline handler does — an\n // access-scoped picker only repaints statuses here, this one restructures.\n const rebuilt = this.syncHidden(hidden);\n const restyled = this.syncClosed(closed);\n if (rebuilt) void this.resnapshot();\n if (rebuilt || restyled) this.opts.onStatusChange?.();\n },\n };\n }\n\n /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */\n private applyStatusChanges(changes: PickerStatusChange[]): void {\n const r = this.renderer;\n if (!r) return;\n for (const ch of changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const ids = this.idsForLabel(ch.label);\n if (!ids.length) 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 ids.some((id) => 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 ids.forEach((id) => r.flashSeat(id, next === 'held' ? '#f4b740' : '#f43f5e'));\n }\n r.setStatus(ids, 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 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\n // Preferred path: the transport owns a `seatlayer.v1` client. An anonymous\n // buyer gets exactly what a private-channel one gets — a compact snapshot\n // instead of every unit of the event, and a resume on reconnect instead of\n // a fresh full snapshot. The client also owns the reconnect, so nothing\n // below runs and there is no second backoff to keep in step.\n if (!this.realtime && this.api.createRealtime) {\n let connection: PickerRealtimeConnection | null = null;\n try {\n connection = this.api.createRealtime(this.key, this.realtimeSink());\n } catch {\n connection = null; // fall through to the plain socket\n }\n if (connection) {\n this.realtime = connection;\n connection.start();\n return;\n }\n }\n if (this.realtime) return;\n\n let ws: WebSocket;\n try {\n const protocols = this.api.socketProtocols?.(this.key);\n ws = protocols && protocols.length ? new WebSocket(url, protocols) : 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 this.applyStatusChanges(m.changes);\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 /**\n * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its\n * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a\n * deterministic `2**attempt` schedule brings every browser that lost the same\n * socket back in the same millisecond, and an on-sale crowd reconnecting in\n * lockstep turns one blip into a thundering herd. The ceiling still doubles,\n * so a sustained outage still backs off.\n */\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.random() * 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 * Pure sightline math for the auto-360° generator — no DOM, no canvas — so it can\n * be unit-tested and reused headless. Kept out of `generatePanorama.ts` (which\n * touches `document`/`canvas`) on purpose.\n */\nimport { SEATED_EYE_HEIGHT_M } from '../core/units';\n\n// Stage extents in metres, relative to the flat-ground seated eye baseline — the\n// heights the legacy formulas implicitly baked into `atan2(5,…)` / `atan2(1.1,…)`.\nexport const STAGE_TOP_M = 5;\nexport const STAGE_BASE_M = -1.1;\n/** Plausibility cap: a raised seat never looks further DOWN than this at the stage. */\nexport const MAX_LOOKDOWN_DEG = 35;\n\n/**\n * Pitch (deg) to the top and base of the stage for a seat whose eye sits\n * `eyeHeightM` above the focal/stage datum, `distM` metres away horizontally.\n *\n * A flat, ground-level seat (`eyeHeightM = SEATED_EYE_HEIGHT_M`) reproduces the\n * legacy `atan2(5,distM)` / `-atan2(1.1,distM)` byte-for-byte. A raised/raked seat\n * (larger `eyeHeightM`) looks DOWN at the stage: both pitches drop and go negative,\n * capped at `MAX_LOOKDOWN_DEG` of depression so a top-balcony view stays plausible.\n */\nexport function stageSightlinePitch(eyeHeightM: number, distM: number): { topPitch: number; basePitch: number } {\n const extraEyeM = eyeHeightM - SEATED_EYE_HEIGHT_M; // 0 for a flat ground-level seat\n let topPitch = (Math.atan2(STAGE_TOP_M - extraEyeM, distM) * 180) / Math.PI;\n let basePitch = (Math.atan2(STAGE_BASE_M - extraEyeM, distM) * 180) / Math.PI;\n if (basePitch < -MAX_LOOKDOWN_DEG) {\n // Shift the whole stage up so the base rests at the depression cap, preserving\n // its angular height (top stays above base).\n topPitch += -MAX_LOOKDOWN_DEG - basePitch;\n basePitch = -MAX_LOOKDOWN_DEG;\n }\n return { topPitch, basePitch };\n}\n","/**\n * Synthetic view-from-seat panorama, generated from chart geometry alone.\n *\n * Draws a 2048×1024 equirectangular texture of the hall as seen from THIS seat.\n * Everything is placed from geometry the viewer already carries — the seat's\n * position, its per-seat eye height (which already bakes in its section's\n * height + rake + row rise), and every other seat's position + eye height:\n *\n * • the SCENE at the correct bearing/angular size, chosen from the chart's own\n * geometry — a proscenium theatre stage, an in-the-round centre-stage deck,\n * or a flat sports playing surface (see {@link classifyScene});\n * • the SURROUNDING STANDS — other sections drawn as darker raked banks\n * rising to the pitch of their highest seat at their true bearing (upper\n * tiers loom higher, a pit sits below the horizon), so the buyer senses the\n * bowl wrapping around them;\n * • a BALCONY-OVERHANG ceiling lip where a high, near section sits overhead;\n * • the AUDIENCE — nearby people drawn as stylised head/neck/shoulder\n * silhouettes at their true bearing, rising behind and dropping in front\n * with the rake, near rows occluding far ones (painter's order).\n *\n * Used whenever the organizer hasn't uploaded a real photo/360 for the seat;\n * both go through the same viewer, and the designer preview reuses this exact\n * generator so authors see what buyers will.\n *\n * Height data drives the extra depth: a FLAT chart (no eye-height spread) draws\n * only the plain dark hall + scene + audience it always has — no raked masses,\n * no overhang, nothing invented from absent data.\n *\n * SCENE + PER-VENUE VARIATION. The picker hands this generator only seats — never\n * the stage object — so scene TYPE is inferred from the audience geometry around\n * the focal point (a bowl that wraps ~360° with a small central void is a\n * centre-stage arena; a large elongated void is a sports surface; a one-sided\n * audience is a proscenium theatre), and a stable per-chart seed (hashed from the\n * seat count + section ids + focal) drives backdrop hue, lighting tint and rig\n * layout so every venue looks like its own place. All deterministic: same\n * chart + seat ⇒ byte-identical texture (no Date, no Math.random).\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';\nimport { METRES_PER_CHART_UNIT, SEATED_EYE_HEIGHT_M } from '../core/units';\nimport { stageSightlinePitch } from './sightline';\n\nconst W = 2048;\nconst H = 1024;\n/** Chart units → meters, for plausible eye-level proportions (seatSpacing 24 ≈ 0.55m). */\nconst UNIT = METRES_PER_CHART_UNIT;\nconst TAU = Math.PI * 2;\n/** Equirectangular vertical resolution: pixels per degree of pitch. */\nconst PX_PER_DEG = H / 180;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\n// --- deterministic helpers ---------------------------------------------------\n\n/** FNV-1a → uint32, for a stable seed from a string descriptor. */\nfunction fnv1a(str: string): number {\n let h = 2166136261;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 16777619);\n }\n return h >>> 0;\n}\n\n/** mulberry32 PRNG — seeded, deterministic, for per-venue dressing choices. */\nfunction rng(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n// --- surrounding-stands model ------------------------------------------------\n// The buyer picker (SDK-owned, unmodifiable) hands us the full expanded seat\n// list, not raw section outlines — so we reconstruct each OTHER section as a\n// ring of yaw bins from its member seats. Each seat's `eyeHeightM` already\n// encodes its section's height + rake + drawn row rise (see layout.assignEye-\n// Heights), so the bank rises to exactly the pitch a real spectator would see.\n// Deriving from seats (not outlines) is also what keeps the buyer and the\n// designer preview pixel-identical: both feed the same expanded list in.\n\nconst NBINS = 96;\nconst BIN_DEG = 360 / NBINS;\n/** Below this eye-height spread (m) the venue reads as flat: no raked banks, no\n * overhang — the plain dark hall is the honest floor for a flat chart. */\nconst FLAT_DELTA_M = 0.6;\n/** Mid sky tone the distance haze blends banks toward (matches the shell). */\nconst HAZE_SKY: [number, number, number] = [17, 23, 42];\n\ntype RGB = [number, number, number];\n\nfunction blendToSky(base: RGB, t: number, a = 1): string {\n // Distance haze: blend toward the sky, but keep more of the band's own colour\n // at distance than before (cap 0.58, was 0.72) so far stands stay legible\n // architecture rather than dissolving into flat silhouettes.\n const k = Math.max(0, Math.min(0.58, t));\n const r = Math.round(base[0] + (HAZE_SKY[0] - base[0]) * k);\n const g = Math.round(base[1] + (HAZE_SKY[1] - base[1]) * k);\n const b = Math.round(base[2] + (HAZE_SKY[2] - base[2]) * k);\n return `rgba(${r},${g},${b},${a})`;\n}\n\nfunction mixRgb(a: RGB, b: RGB, t: number): RGB {\n return [\n Math.round(a[0] + (b[0] - a[0]) * t),\n Math.round(a[1] + (b[1] - a[1]) * t),\n Math.round(a[2] + (b[2] - a[2]) * t),\n ];\n}\n\nfunction hslToRgb(h: number, s: number, l: number): RGB {\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const hp = (((h % 360) + 360) % 360) / 60;\n const x = c * (1 - Math.abs((hp % 2) - 1));\n let r = 0, g = 0, b = 0;\n if (hp < 1) [r, g, b] = [c, x, 0];\n else if (hp < 2) [r, g, b] = [x, c, 0];\n else if (hp < 3) [r, g, b] = [0, c, x];\n else if (hp < 4) [r, g, b] = [0, x, c];\n else if (hp < 5) [r, g, b] = [x, 0, c];\n else [r, g, b] = [c, 0, x];\n const m = l - c / 2;\n return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];\n}\n\n/**\n * A stable, DESATURATED tint for a section from its category key. The panorama\n * has no access to the doc's category→colour map (its signature takes only\n * seats), so it derives a deterministic hue per category and mutes it hard —\n * same spirit as the 3D tier tinting in sceneModel.tintTop: enough to tell\n * adjacent sections apart as coloured architecture, never a saturated poster.\n */\nconst tintCache = new Map<string, RGB>();\nfunction tintFromKey(key: string | undefined): RGB | null {\n if (!key) return null;\n const cached = tintCache.get(key);\n if (cached) return cached;\n let h = 2166136261;\n for (let i = 0; i < key.length; i++) { h ^= key.charCodeAt(i); h = Math.imul(h, 16777619); }\n const hue = (h >>> 0) % 360;\n const rgb = hslToRgb(hue, 0.3, 0.42);\n tintCache.set(key, rgb);\n return rgb;\n}\n\ninterface StandBin {\n /** Pitch (deg) to the highest seat's head in this bin — the bank crest. */\n top: number;\n /** Pitch (deg) to the section's seat surface — its front-edge base. */\n base: number;\n /** Nearest member distance (m) in this bin, for the distance haze. */\n nearM: number;\n /** A high, near mass overhead → hint a balcony ceiling lip. */\n overhead: boolean;\n /** Desaturated section-colour hint (from the nearest member's category). */\n tint: RGB | null;\n}\n\n/**\n * Bin the OTHER sections' member seats by bearing into a surrounding ring.\n * Returns `maxDelta` (the largest eye-height difference seen) so the caller can\n * fall back to the flat hall when there is no real relief to draw.\n */\nfunction buildStands(\n seat: ExpandedSeat,\n neighborSeats: ExpandedSeat[],\n stageBearing: number,\n myEyeM: number,\n): { bins: (StandBin | null)[]; maxDelta: number } {\n const bins: (StandBin | null)[] = new Array(NBINS).fill(null);\n let maxDelta = 0;\n const own = seat.sectionId;\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const os = other.sectionId;\n // Own section is the foreground crowd (drawn as heads + a seat-back rail);\n // seats with no section can't be attributed to a bank, so skip them.\n if (!os || (own && os === own)) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const dM = Math.hypot(ox, oy) * UNIT;\n if (dM < 1.5 || dM > 95) continue;\n const otherEye = other.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const dTop = otherEye - myEyeM;\n if (Math.abs(dTop) > maxDelta) maxDelta = Math.abs(dTop);\n const top = (Math.atan2(dTop, dM) * 180) / Math.PI;\n const base = (Math.atan2(otherEye - SEATED_EYE_HEIGHT_M - myEyeM, dM) * 180) / Math.PI;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = (((bearing * 180) / Math.PI + 540) % 360) - 180;\n const idx = Math.min(NBINS - 1, Math.max(0, Math.floor((yaw + 180) / BIN_DEG)));\n const overhead = top > 34 && dM < 16;\n const cur = bins[idx];\n if (!cur) bins[idx] = { top, base, nearM: dM, overhead, tint: tintFromKey(other.categoryKey) };\n else {\n if (top > cur.top) cur.top = top;\n if (base < cur.base) cur.base = base;\n // The nearest member drives the visible tint (it fills most of the bank).\n if (dM < cur.nearM) { cur.nearM = dM; cur.tint = tintFromKey(other.categoryKey); }\n cur.overhead = cur.overhead || overhead;\n }\n }\n return { bins, maxDelta };\n}\n\n/**\n * Paint the binned banks: each is a dark raked mass from its crest down past the\n * horizon (so it reads solid, never floating), hazed by distance, with faint row\n * banding and — where a high near mass sits overhead — a balcony ceiling lip.\n */\nfunction drawStands(\n ctx: CanvasRenderingContext2D,\n bins: (StandBin | null)[],\n toX: (yawDeg: number) => number,\n toY: (pitchDeg: number) => number,\n): void {\n for (let i = 0; i < NBINS; i++) {\n const b = bins[i];\n if (!b) continue;\n const yaw0 = -180 + i * BIN_DEG;\n const x0 = toX(yaw0);\n const x1 = toX(yaw0 + BIN_DEG);\n if (!(x1 > x0)) continue; // equirect seam inside this bin → skip the sliver\n const top = Math.min(72, b.top);\n const bottom = Math.min(b.base, -4); // always reach just past the horizon\n const yTop = toY(top);\n const yBot = toY(bottom);\n if (yBot <= yTop) continue;\n const haze = b.nearM / 95;\n // Fold the section's desaturated colour hint into the bank so the panorama\n // and the 3D view read as the same venue. Kept subtle (~0.34) and only on\n // the lit upper stops so the shadowed facade stays neutral.\n const tint = b.tint;\n const crest: RGB = tint ? mixRgb([44, 54, 80], tint, 0.34) : [44, 54, 80];\n const seating: RGB = tint ? mixRgb([24, 30, 48], tint, 0.28) : [24, 30, 48];\n const grad = ctx.createLinearGradient(0, yTop, 0, yBot);\n grad.addColorStop(0, blendToSky(crest, haze)); // lit seat-row crest\n grad.addColorStop(0.24, blendToSky(seating, haze)); // seating\n grad.addColorStop(1, blendToSky([10, 13, 22], haze)); // facade into shadow\n ctx.fillStyle = grad;\n ctx.fillRect(x0, yTop, x1 - x0 + 1, yBot - yTop);\n // crest edge: a faint lit rim so the bank top reads as a hard architectural\n // line even far away (distance no longer melts it into the sky).\n ctx.fillStyle = `rgba(150,165,205,${0.35 * (1 - haze * 0.55)})`;\n ctx.fillRect(x0, yTop, x1 - x0 + 1, 1.5);\n // tier-band striping on the seated portion (crest down to the horizon):\n // alternating lit/shadow rows so distant stands read as populated tiers, not\n // a flat wash. More bands + higher contrast than before.\n const bandBottom = Math.min(yBot, toY(0));\n const bandSpan = bandBottom - yTop;\n if (bandSpan > 8) {\n const bands = 6;\n const contrast = 1 - haze * 0.4;\n for (let r = 1; r < bands; r++) {\n const y = yTop + (bandSpan * r) / bands;\n ctx.fillStyle = `rgba(0,0,0,${0.16 * contrast})`; // seat-row shadow gap\n ctx.fillRect(x0, y, x1 - x0 + 1, 1.5);\n ctx.fillStyle = `rgba(120,134,170,${0.1 * contrast})`; // lit seat-back band\n ctx.fillRect(x0, y + 1.5, x1 - x0 + 1, 1.2);\n }\n }\n // balcony overhang: a dark ceiling lip fading down onto the crest\n if (b.overhead) {\n const lipY = toY(Math.min(86, top + 12));\n const g2 = ctx.createLinearGradient(0, lipY, 0, yTop);\n g2.addColorStop(0, 'rgba(3,4,8,0.9)');\n g2.addColorStop(1, 'rgba(3,4,8,0)');\n ctx.fillStyle = g2;\n ctx.fillRect(x0, lipY, x1 - x0 + 1, yTop - lipY);\n ctx.fillStyle = 'rgba(120,130,160,0.14)'; // faint lit underside rim\n ctx.fillRect(x0, yTop - 1.5, x1 - x0 + 1, 1.5);\n }\n }\n}\n\n// --- scene classification ----------------------------------------------------\n// The generator never sees the stage object (its signature takes only seats), so\n// scene TYPE is inferred from where the audience sits around the focal point:\n// • a bowl wrapping ~360° with a SMALL central void → in-the-round centre-stage;\n// • a bowl wrapping ~360° with a LARGE, elongated void → a sports playing surface;\n// • a one-sided audience → a proscenium theatre.\n// A per-chart seed (seat count + section ids + focal) drives the dressing.\n\ntype SceneMode = 'proscenium' | 'arena' | 'sport';\ninterface Scene {\n mode: SceneMode;\n seed: number;\n /** Median radius (m) of the central void the audience rings — the performance area. */\n voidRadiusM: number;\n /** Elongation of the void (long axis / short axis); ~1 round, ~2 a rink. */\n aspect: number;\n}\n\nfunction classifyScene(_seat: ExpandedSeat, focal: Point, neighbors: ExpandedSeat[]): Scene {\n const NB = 72;\n const occ = new Array<boolean>(NB).fill(false);\n const innerM = new Array<number>(NB).fill(Infinity);\n const secSet = new Set<string>();\n let n = 0;\n for (const s of neighbors) {\n n++;\n if (s.sectionId) secSet.add(s.sectionId);\n const dx = s.x - focal.x;\n const dy = s.y - focal.y;\n const dM = Math.hypot(dx, dy) * UNIT;\n if (dM < 0.5) continue;\n const bearing = Math.atan2(dx, -dy); // −π..π, 0 = toward focal's −y\n let idx = Math.floor(((bearing + Math.PI) / TAU) * NB);\n if (idx < 0) idx = 0; else if (idx >= NB) idx = NB - 1;\n occ[idx] = true;\n if (dM < innerM[idx]) innerM[idx] = dM;\n }\n let occN = 0;\n const inner: number[] = [];\n for (let i = 0; i < NB; i++) if (occ[i]) { occN++; inner.push(innerM[i]); }\n const coverage = (occN / NB) * 360;\n inner.sort((a, b) => a - b);\n const median = inner.length ? inner[inner.length >> 1] : 0;\n const lo = inner.length ? (inner[Math.floor(inner.length * 0.15)] ?? median) : 0;\n const hi = inner.length ? (inner[Math.floor(inner.length * 0.85)] ?? median) : 0;\n const aspect = lo > 0.5 ? hi / lo : 1;\n const seed = fnv1a(`${n}|${[...secSet].sort().join(',')}|${Math.round(focal.x)},${Math.round(focal.y)}`);\n\n let mode: SceneMode;\n if (coverage >= 300 && median > 11 && aspect > 1.35) mode = 'sport';\n else if (coverage >= 285) mode = 'arena';\n else mode = 'proscenium';\n return { mode, seed, voidRadiusM: median, aspect };\n}\n\n// --- stylised human silhouettes ----------------------------------------------\n// Theatre-poster silhouettes, NOT photoreal: a slightly-oval head, a visible neck\n// gap, and shoulders that slope from the neck (a trapezius curve) into upper arms.\n// Deterministic per seat/performer index — head size/tilt, hair outline, shoulder\n// width and clothing tone all vary so no two neighbours are identical.\n\nconst HAIR_KINDS = 5; // 0 short · 1 full · 2 tied/bun · 3 cap · 4 long\n\n/** Hair as extra silhouette shapes on top of the base head oval (local head coords). */\nfunction drawHair(ctx: CanvasRenderingContext2D, r: number, kind: number): void {\n switch (kind) {\n case 1: // full / bushy — a larger rounded mass sitting over and around the head\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.14, r * 1.16, r * 1.16, 0, 0, TAU);\n ctx.fill();\n break;\n case 2: // tied back — a bun above the crown\n ctx.beginPath();\n ctx.ellipse(0, -r * 1.02, r * 0.42, r * 0.42, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.2, r * 0.98, r * 1.02, 0, 0, TAU);\n ctx.fill();\n break;\n case 3: // cap / hat — flattened crown with a small forward brim\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.36, r * 1.04, r * 0.6, 0, Math.PI, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.52, r * 1.22, r * 0.24, 0, 0, TAU); // brim\n ctx.fill();\n break;\n case 4: // long — hair falling past the neck on both sides\n ctx.beginPath();\n ctx.ellipse(-r * 0.66, r * 0.5, r * 0.5, r * 1.35, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(r * 0.66, r * 0.5, r * 0.5, r * 1.35, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.08, r * 1.06, r * 1.08, 0, 0, TAU);\n ctx.fill();\n break;\n default: // short — the clean head oval already reads as short hair\n break;\n }\n}\n\ninterface SeatedOpts {\n tone: RGB;\n clothing: RGB;\n alpha: number;\n tilt: number; // head tilt, radians\n shoulderK: number; // shoulder half-width in head-radii\n hair: number;\n rim: number; // 0..1 warm rim strength on head/shoulder crown\n turn: number; // head yaw offset in head-radii (−0.12..0.12) — neighbours chat\n lean: number; // shoulder asymmetry in head-radii (one side rides higher)\n}\n\n/**\n * A seated spectator seen from behind: sloping shoulders (drawn first) with a\n * trapezius curve into the upper arms, then a narrower neck + head on top so the\n * neck gap reads, then a hair-variant silhouette and an optional warm rim.\n */\nfunction drawSeated(ctx: CanvasRenderingContext2D, hx: number, hy: number, r: number, o: SeatedOpts): void {\n const neckHalf = r * 0.44;\n const shHalf = r * o.shoulderK;\n const neckTopY = r * 0.66;\n const shoulderY = r * 1.68;\n const botY = r * 5.4; // runs off below the crop / into the seat back\n const clo = `rgba(${o.clothing[0]},${o.clothing[1]},${o.clothing[2]},${o.alpha})`;\n const skin = `rgba(${o.tone[0]},${o.tone[1]},${o.tone[2]},${o.alpha})`;\n\n ctx.save();\n ctx.translate(hx, hy);\n\n // shoulders + torso (clothing tone) — trapezius slope from neck to shoulder,\n // then upper-arm drop. Lean lifts one shoulder and drops the other so close\n // figures don't sit in a perfectly level row.\n const leanPx = o.lean * r;\n ctx.fillStyle = clo;\n ctx.beginPath();\n ctx.moveTo(-neckHalf, neckTopY);\n ctx.quadraticCurveTo(-neckHalf * 1.18, shoulderY - leanPx - r * 0.6, -shHalf, shoulderY - leanPx);\n ctx.quadraticCurveTo(-shHalf * 1.05, shoulderY + r * 1.2, -shHalf * 0.94, botY);\n ctx.lineTo(shHalf * 0.94, botY);\n ctx.quadraticCurveTo(shHalf * 1.05, shoulderY + r * 1.2, shHalf, shoulderY + leanPx);\n ctx.quadraticCurveTo(neckHalf * 1.18, shoulderY + leanPx - r * 0.6, neckHalf, neckTopY);\n ctx.closePath();\n ctx.fill();\n\n // neck column (head tone), narrower than both head and shoulders → the gap.\n ctx.fillStyle = skin;\n ctx.fillRect(-neckHalf * 0.82, r * 0.5, neckHalf * 1.64, r * 0.9);\n\n // head + hair, with a small tilt and a seeded turn (heads angled toward a\n // neighbour, not all facing dead ahead).\n ctx.save();\n ctx.rotate(o.tilt);\n ctx.translate(o.turn * r, 0);\n ctx.fillStyle = skin;\n if (r >= 18) {\n // Close-up head: a cranium-to-jaw egg, not a balloon — full crown up top,\n // cheeks tapering through the jaw to a narrower chin.\n ctx.beginPath();\n ctx.moveTo(-r * 0.9, -r * 0.15);\n ctx.quadraticCurveTo(-r * 0.96, -r * 1.12, 0, -r * 1.06);\n ctx.quadraticCurveTo(r * 0.96, -r * 1.12, r * 0.9, -r * 0.15);\n ctx.quadraticCurveTo(r * 0.86, r * 0.55, r * 0.36, r * 0.98);\n ctx.quadraticCurveTo(0, r * 1.14, -r * 0.36, r * 0.98);\n ctx.quadraticCurveTo(-r * 0.86, r * 0.55, -r * 0.9, -r * 0.15);\n ctx.closePath();\n ctx.fill();\n // ear hints — small lobes just below the head's widest line.\n if (r >= 22) {\n ctx.beginPath();\n ctx.ellipse(-r * 0.9, r * 0.18, r * 0.13, r * 0.22, 0, 0, TAU);\n ctx.ellipse(r * 0.9, r * 0.18, r * 0.13, r * 0.22, 0, 0, TAU);\n ctx.fill();\n }\n } else {\n ctx.beginPath();\n ctx.ellipse(0, 0, r * 0.9, r * 1.06, 0, 0, TAU);\n ctx.fill();\n }\n drawHair(ctx, r, o.hair);\n // warm rim catching the stage light on the crown + a shoulder edge.\n if (o.rim > 0.01) {\n ctx.strokeStyle = `rgba(245,205,150,${(0.5 * o.rim).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, r * 0.14);\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.06, r * 0.86, r * 1.0, 0, Math.PI * 1.12, Math.PI * 1.9);\n ctx.stroke();\n }\n ctx.restore();\n\n if (o.rim > 0.01) {\n ctx.strokeStyle = `rgba(240,200,150,${(0.28 * o.rim).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, r * 0.12);\n ctx.beginPath();\n ctx.moveTo(-shHalf * 0.8, shoulderY - r * 0.05);\n ctx.quadraticCurveTo(-neckHalf, shoulderY - r * 0.75, 0, shoulderY - r * 0.82);\n ctx.quadraticCurveTo(neckHalf, shoulderY - r * 0.75, shHalf * 0.8, shoulderY - r * 0.05);\n ctx.stroke();\n }\n ctx.restore();\n}\n\n/** Cheap head+shoulders for the mid LOD band — a defined trapezius slope with a\n * visible neck notch (the near-LOD silhouette language, two curves cheaper). */\nfunction drawSeatedMid(ctx: CanvasRenderingContext2D, hx: number, hy: number, r: number, clothing: RGB, tone: RGB, alpha: number): void {\n ctx.fillStyle = `rgba(${clothing[0]},${clothing[1]},${clothing[2]},${alpha})`;\n ctx.beginPath();\n ctx.moveTo(hx - r * 1.72, hy + r * 4);\n ctx.quadraticCurveTo(hx - r * 1.78, hy + r * 1.55, hx - r * 0.46, hy + r * 1.02);\n ctx.lineTo(hx - r * 0.4, hy + r * 0.62); // neck notch, left\n ctx.lineTo(hx + r * 0.4, hy + r * 0.62); // neck notch, right\n ctx.lineTo(hx + r * 0.46, hy + r * 1.02);\n ctx.quadraticCurveTo(hx + r * 1.78, hy + r * 1.55, hx + r * 1.72, hy + r * 4);\n ctx.closePath();\n ctx.fill();\n ctx.fillStyle = `rgba(${tone[0]},${tone[1]},${tone[2]},${alpha})`;\n ctx.beginPath();\n ctx.ellipse(hx, hy, r * 0.9, r * 1.05, 0, 0, TAU);\n ctx.fill();\n}\n\ninterface PerformerOpts {\n tone: RGB;\n alpha: number;\n pose: number; // 0 neutral · 1 arms up · 2 instrument · 3 mic\n rim: RGB; // rim-light colour (from the scene lighting)\n rimStrength: number;\n}\n\n/**\n * A standing performer on the stage/deck: full body with varied poses, grounded\n * by a contact shadow on the deck. Same silhouette language as the audience.\n */\nfunction drawPerformer(ctx: CanvasRenderingContext2D, x: number, footY: number, h: number, o: PerformerOpts): void {\n const headR = h * 0.1;\n const headCy = footY - h * 0.9;\n const shoulderY = footY - h * 0.74;\n const hipY = footY - h * 0.46;\n const shHalf = h * 0.13;\n const hipHalf = h * 0.09;\n const skin = `rgba(${o.tone[0]},${o.tone[1]},${o.tone[2]},${o.alpha})`;\n\n // contact shadow — an elongated soft ellipse under the feet, on the deck.\n const sh = ctx.createRadialGradient(x, footY, 1, x, footY, h * 0.24);\n sh.addColorStop(0, 'rgba(0,0,0,0.4)');\n sh.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.save();\n ctx.scale(1, 0.28);\n ctx.fillStyle = sh;\n ctx.beginPath();\n ctx.ellipse(x, footY / 0.28, h * 0.24, h * 0.24, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n\n ctx.fillStyle = skin;\n // legs — two tapered columns to the feet.\n ctx.beginPath();\n ctx.moveTo(x - hipHalf, hipY);\n ctx.lineTo(x - hipHalf * 0.7, footY);\n ctx.lineTo(x - hipHalf * 0.1, footY);\n ctx.lineTo(x - hipHalf * 0.1, hipY + h * 0.02);\n ctx.lineTo(x + hipHalf * 0.1, hipY + h * 0.02);\n ctx.lineTo(x + hipHalf * 0.1, footY);\n ctx.lineTo(x + hipHalf * 0.7, footY);\n ctx.lineTo(x + hipHalf, hipY);\n ctx.closePath();\n ctx.fill();\n\n // torso — shoulders down to hips.\n ctx.beginPath();\n ctx.moveTo(x - shHalf, shoulderY);\n ctx.quadraticCurveTo(x - shHalf * 0.9, hipY - h * 0.12, x - hipHalf, hipY);\n ctx.lineTo(x + hipHalf, hipY);\n ctx.quadraticCurveTo(x + shHalf * 0.9, hipY - h * 0.12, x + shHalf, shoulderY);\n ctx.quadraticCurveTo(x, shoulderY - h * 0.05, x - shHalf, shoulderY);\n ctx.closePath();\n ctx.fill();\n\n // arms by pose.\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.strokeStyle = skin;\n ctx.lineWidth = h * 0.055;\n const armY = shoulderY + h * 0.02;\n if (o.pose === 1) {\n // arms up in a V.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x - shHalf * 1.5, footY - h * 1.02);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x + shHalf * 1.5, footY - h * 1.02);\n ctx.stroke();\n } else if (o.pose === 2) {\n // instrument: one arm across the body, a guitar body hint at the hip.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x + hipHalf * 1.4, hipY - h * 0.02);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x - hipHalf * 0.4, hipY - h * 0.06);\n ctx.stroke();\n ctx.fillStyle = skin;\n ctx.beginPath();\n ctx.ellipse(x + hipHalf * 1.5, hipY - h * 0.04, h * 0.07, h * 0.09, -0.5, 0, TAU);\n ctx.fill();\n } else if (o.pose === 3) {\n // mic stance: one arm up toward the head, a thin mic stand in front.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x - shHalf * 0.2, headCy + headR * 0.6);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x + shHalf * 1.1, hipY);\n ctx.stroke();\n ctx.lineWidth = h * 0.02;\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.2, headCy + headR * 0.9);\n ctx.lineTo(x - shHalf * 0.2, footY - h * 0.02);\n ctx.stroke();\n } else {\n // neutral — arms at the sides.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.85, armY);\n ctx.lineTo(x - shHalf * 0.95, hipY + h * 0.02);\n ctx.moveTo(x + shHalf * 0.85, armY);\n ctx.lineTo(x + shHalf * 0.95, hipY + h * 0.02);\n ctx.stroke();\n }\n\n // neck + head.\n ctx.fillStyle = skin;\n ctx.fillRect(x - headR * 0.34, headCy + headR * 0.6, headR * 0.68, headR * 0.9);\n ctx.beginPath();\n ctx.ellipse(x, headCy, headR * 0.86, headR * 1.05, 0, 0, TAU);\n ctx.fill();\n\n // rim light on the figure's lit edge.\n if (o.rimStrength > 0.01) {\n ctx.strokeStyle = `rgba(${o.rim[0]},${o.rim[1]},${o.rim[2]},${(0.6 * o.rimStrength).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, h * 0.02);\n ctx.beginPath();\n ctx.moveTo(x - shHalf, shoulderY);\n ctx.lineTo(x - headR * 0.6, headCy + headR * 0.4);\n ctx.moveTo(x - headR * 0.7, headCy);\n ctx.ellipse(x, headCy, headR * 0.84, headR * 1.02, 0, Math.PI * 1.05, Math.PI * 1.55);\n ctx.stroke();\n }\n}\n\n/** A tapered light-beam cone that ADDS light ('lighter' composite), strong at the\n * fixture and fading down. Narrow at the source (halfTop), wide at the target\n * pool (halfBot). */\nfunction drawBeam(\n ctx: CanvasRenderingContext2D,\n x0: number, y0: number, x1: number, y1: number,\n halfTop: number, halfBot: number, tint: string, strength: number,\n): void {\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n const g = ctx.createLinearGradient(0, y0, 0, y1);\n g.addColorStop(0, `rgba(${tint},${strength})`);\n g.addColorStop(0.5, `rgba(${tint},${(strength * 0.4).toFixed(3)})`);\n g.addColorStop(1, `rgba(${tint},0)`);\n ctx.fillStyle = g;\n ctx.beginPath();\n ctx.moveTo(x0 - halfTop, y0);\n ctx.lineTo(x1 - halfBot, y1);\n ctx.lineTo(x1 + halfBot, y1);\n ctx.lineTo(x0 + halfTop, y0);\n ctx.closePath();\n ctx.fill();\n ctx.restore();\n}\n\n/** A rig fixture: a bright dot with a soft halo where a beam originates. */\nfunction drawFixture(ctx: CanvasRenderingContext2D, x: number, y: number, r: number, tint: string): void {\n const g = ctx.createRadialGradient(x, y, 0, x, y, r * 3);\n g.addColorStop(0, `rgba(${tint},0.9)`);\n g.addColorStop(0.4, `rgba(${tint},0.35)`);\n g.addColorStop(1, `rgba(${tint},0)`);\n ctx.fillStyle = g;\n ctx.beginPath();\n ctx.arc(x, y, r * 3, 0, TAU);\n ctx.fill();\n ctx.fillStyle = `rgba(${tint},1)`;\n ctx.beginPath();\n ctx.arc(x, y, r, 0, TAU);\n ctx.fill();\n}\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 const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n\n const scene = classifyScene(seat, focalPoint, neighborSeats);\n const rand = rng(scene.seed);\n // Per-venue lighting identity: a base hue steers the backdrop, a cool rig tint\n // shifts a little off the default periwinkle, and a warm accent lights figures.\n const baseHue = 210 + rand() * 150; // violet → magenta → amber sweep\n const rigTint: RGB = hslToRgb(220 + (rand() - 0.5) * 60, 0.55, 0.82);\n const rigTintStr = `${rigTint[0]},${rigTint[1]},${rigTint[2]}`;\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#080b12');\n sky.addColorStop(0.42, '#12182c');\n sky.addColorStop(0.5, '#1c2440');\n sky.addColorStop(0.56, '#151b2c');\n sky.addColorStop(0.78, '#171e30');\n sky.addColorStop(1, '#131829');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // Ambient floor wash — a broad dim lift across the lower hall.\n const floorAmb = ctx.createLinearGradient(0, pitchToY(-6), 0, H);\n floorAmb.addColorStop(0, 'rgba(30, 37, 56, 0)');\n floorAmb.addColorStop(0.55, 'rgba(30, 37, 56, 0.22)');\n floorAmb.addColorStop(1, 'rgba(22, 28, 44, 0.12)');\n ctx.fillStyle = floorAmb;\n ctx.fillRect(0, pitchToY(-6), W, H - pitchToY(-6));\n\n // Bearing of the stage in screen coords (-y is \"up\" the hall).\n const stageBearing = Math.atan2(dx, -dy);\n\n // ---- surrounding stands: other sections as raked banks (all modes) ------\n const stands = buildStands(seat, neighborSeats, stageBearing, eyeM);\n const hasRelief = stands.maxDelta >= FLAT_DELTA_M;\n if (hasRelief) drawStands(ctx, stands.bins, yawToX, pitchToY);\n\n // Distance drama factor.\n const nearGlow = Math.max(0.3, Math.min(1, 1 - (distM - 6) / 60));\n\n // ---- the scene, centered at yaw 0 --------------------------------------\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(45, sightline.topPitch);\n const stageBasePitch = sightline.basePitch;\n\n if (scene.mode === 'sport') {\n drawSportScene(ctx, distM, eyeM, scene, nearGlow, baseHue, rigTintStr, rand);\n } else if (scene.mode === 'arena') {\n drawArenaScene(ctx, distM, eyeM, scene, nearGlow, rigTintStr, rand);\n } else {\n drawProsceniumScene(ctx, stageHalfYaw, stageTopPitch, stageBasePitch, nearGlow, baseHue, rigTintStr, rand);\n }\n\n // ---- rig lights along the ceiling all around ---------------------------\n // Sport gets even flood banks; performance venues get a warmer scattered rig.\n const rigCount = scene.mode === 'sport' ? 34 : 24 + Math.floor(rand() * 8);\n ctx.fillStyle = `rgba(${rigTintStr},0.8)`;\n for (let i = 0; i < rigCount; i++) {\n const x = ((i + 0.5) / rigCount) * W;\n const y = pitchToY(scene.mode === 'sport' ? 58 : 54 + ((i * 7) % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, scene.mode === 'sport' ? 2.6 : 3.2, 0, TAU);\n ctx.fill();\n }\n\n // ---- audience: stylised silhouettes of nearby seats --------------------\n drawAudience(ctx, seat, neighborSeats, focalPoint, stageBearing, eyeM, dx, dy, hasRelief, scene);\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.9, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.55)');\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// ---- scene drawers ----------------------------------------------------------\n\n/**\n * Proscenium theatre: a perspective arch (top valance + tapering legs) with dark\n * masking wings, a backdrop INSET in the opening that falls off softly at its\n * edges (never a hard rectangle floating in black), a lit stage-floor front edge\n * with footlights, tapered light-beam cones, and posed performer silhouettes.\n */\nfunction drawProsceniumScene(\n ctx: CanvasRenderingContext2D,\n stageHalfYaw: number,\n stageTopPitch: number,\n stageBasePitch: number,\n nearGlow: number,\n baseHue: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n const sw = sx1 - sx0;\n const sh = sy1 - sy0;\n const archTop = pitchToY(Math.min(50, stageTopPitch + 10));\n\n // Warm glow bloom behind the opening.\n const glowR = sw * (1.1 + (1 - nearGlow) * 0.5);\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 8, W / 2, (sy0 + sy1) / 2, glowR);\n glow.addColorStop(0, 'rgba(255, 214, 150, 0.34)');\n glow.addColorStop(0.28, 'rgba(150, 150, 230, 0.3)');\n glow.addColorStop(0.6, 'rgba(99, 102, 241, 0.12)');\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 // Backdrop inset — a seeded gradient painted only inside the opening, then a\n // soft edge falloff so it melts into the masking instead of a hard edge.\n const topCol = hslToRgb(baseHue, 0.62, 0.55);\n const midCol = hslToRgb(baseHue + 40, 0.7, 0.5);\n const botCol = hslToRgb(baseHue + 70, 0.78, 0.52);\n ctx.save();\n ctx.beginPath();\n ctx.rect(sx0, sy0, sw, sh);\n ctx.clip();\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, `rgb(${topCol[0]},${topCol[1]},${topCol[2]})`);\n backdrop.addColorStop(0.5, `rgb(${midCol[0]},${midCol[1]},${midCol[2]})`);\n backdrop.addColorStop(1, `rgb(${botCol[0]},${botCol[1]},${botCol[2]})`);\n ctx.globalAlpha = 0.8;\n ctx.fillStyle = backdrop;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.globalAlpha = 1;\n // Edge falloff: transparent centre → dark at the opening's borders.\n const fall = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, sw * 0.12, W / 2, (sy0 + sy1) / 2, sw * 0.62);\n fall.addColorStop(0, 'rgba(6,8,14,0)');\n fall.addColorStop(0.7, 'rgba(6,8,14,0.15)');\n fall.addColorStop(1, 'rgba(5,6,11,0.92)');\n ctx.fillStyle = fall;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.restore();\n\n // Performers on the stage floor.\n const perfCount = 3 + Math.floor(rand() * 3);\n const perfH = sh * 0.46;\n const floorY = sy1 - sh * 0.08;\n for (let i = 0; i < perfCount; i++) {\n const t = (i + 1) / (perfCount + 1);\n const px = sx0 + sw * (0.22 + t * 0.56 + (rand() - 0.5) * 0.06);\n drawPerformer(ctx, px, floorY, perfH * (0.9 + rand() * 0.24), {\n tone: [8, 10, 16],\n alpha: 0.9,\n pose: Math.floor(rand() * 4),\n rim: hslToRgb(baseHue + 20, 0.5, 0.7),\n rimStrength: 0.7,\n });\n }\n\n // Masking wings — dark vertical legs beyond the opening.\n ctx.fillStyle = '#05070d';\n ctx.fillRect(sx0 - sw * 0.5, archTop, sw * 0.5, sy1 - archTop);\n ctx.fillRect(sx1, archTop, sw * 0.5, sy1 - archTop);\n\n // Perspective arch: legs lean inward slightly toward the top, a top beam/valance.\n const legBot = sw * 0.055 + 3; // leg thickness at the base\n const legTop = legBot * 1.35; // wider at the top (perspective)\n ctx.fillStyle = '#03050a';\n // left leg\n ctx.beginPath();\n ctx.moveTo(sx0, sy1);\n ctx.lineTo(sx0 - legBot, sy1);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.lineTo(sx0 + sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n // right leg\n ctx.beginPath();\n ctx.moveTo(sx1, sy1);\n ctx.lineTo(sx1 + legBot, sy1);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx1 - sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n // top beam.\n ctx.fillRect(sx0 - legTop, archTop, sw + legTop * 2, (sy1 - archTop) * 0.12);\n // valance: a soft draped border hanging below the beam.\n const valH = sh * 0.14;\n const valY = archTop + (sy1 - archTop) * 0.12;\n ctx.fillStyle = 'rgba(4,6,12,0.96)';\n const scallops = 7;\n ctx.beginPath();\n ctx.moveTo(sx0 - legTop, valY);\n for (let i = 0; i <= scallops; i++) {\n const xx = sx0 - legTop + ((sw + legTop * 2) * i) / scallops;\n ctx.quadraticCurveTo(xx - (sw + legTop * 2) / scallops / 2, valY + valH, xx, valY);\n }\n ctx.lineTo(sx1 + legTop, valY);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.closePath();\n ctx.fill();\n // faint lit inner rim on the arch legs.\n ctx.fillStyle = `rgba(${rigTintStr},0.12)`;\n ctx.fillRect(sx0 - 1.5, valY, 1.5, sy1 - valY);\n ctx.fillRect(sx1, valY, 1.5, sy1 - valY);\n\n // Stage floor front edge + footlight glow.\n ctx.fillStyle = '#0b0f18';\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.05 + 3);\n const foot = ctx.createLinearGradient(0, sy1 - sh * 0.05, 0, sy1 + sh * 0.12);\n foot.addColorStop(0, `rgba(255,206,140,${(0.5 * nearGlow).toFixed(3)})`);\n foot.addColorStop(1, 'rgba(255,206,140,0)');\n ctx.fillStyle = foot;\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.2);\n\n // Tapered light-beam cones from rig fixtures above the arch.\n const beams = 3 + Math.floor(rand() * 2);\n for (let i = 0; i < beams; i++) {\n const t = (i + 1) / (beams + 1);\n const fx = sx0 + sw * (t + (rand() - 0.5) * 0.08);\n const fy = pitchToY(Math.min(62, stageTopPitch + 26));\n const skew = (rand() - 0.5) * sw * 0.16;\n drawBeam(ctx, fx, fy, fx + skew, sy1, 4, sw * 0.09, rigTintStr, 0.16 * (0.7 + nearGlow * 0.5));\n drawFixture(ctx, fx, fy, 2.4, rigTintStr);\n }\n}\n\n/**\n * In-the-round centre-stage: an elevated elliptical deck with a lit rim and a\n * visible riser side, a truss ring above with hanging fixtures and tapered beam\n * cones onto the deck, a warm floor-spill pool, and performers standing ON the\n * deck. No proscenium — the opposite stands stay visible behind it.\n */\nfunction drawArenaScene(\n ctx: CanvasRenderingContext2D,\n distM: number,\n eyeM: number,\n scene: Scene,\n nearGlow: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n // Bound the deck radius so a seat AT the stage edge (distM ≈ void radius) can't\n // blow the near-edge pitch up to the pole — the deck never exceeds the viewer's\n // own distance, and the near edge stays a safe fraction of the way in.\n const stageR = Math.min(distM * 0.6, Math.max(3, scene.voidRadiusM));\n const halfYaw = Math.min(55, (Math.atan2(stageR, distM) * 180) / Math.PI);\n const cx = W / 2;\n const deckRiserM = 1.2;\n const nearDist = Math.max(distM * 0.45, distM - stageR);\n const farDist = distM + stageR;\n // Near/far edges of the deck top, in pitch.\n const nearTopPitch = (Math.atan2(deckRiserM - eyeM, nearDist) * 180) / Math.PI;\n const farTopPitch = (Math.atan2(deckRiserM - eyeM, farDist) * 180) / Math.PI;\n const nearBasePitch = (Math.atan2(-eyeM, nearDist) * 180) / Math.PI; // floor at the near edge\n const yNearTop = pitchToY(nearTopPitch);\n const yFarTop = pitchToY(farTopPitch);\n const yBase = pitchToY(nearBasePitch);\n const halfW = yawToX(halfYaw) - cx;\n const topRy = Math.max(6, (yNearTop - yFarTop) / 2); // ellipse vertical radius (foreshortened)\n const topCy = (yNearTop + yFarTop) / 2;\n\n // Floor-spill pool around the deck base.\n const pool = ctx.createRadialGradient(cx, yBase, 4, cx, yBase, halfW * 2.6);\n pool.addColorStop(0, `rgba(255,206,150,${(0.2 * nearGlow).toFixed(3)})`);\n pool.addColorStop(0.5, 'rgba(150,140,190,0.08)');\n pool.addColorStop(1, 'rgba(40,44,60,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = pool;\n ctx.fillRect(cx - halfW * 2.6, yFarTop - topRy, halfW * 5.2, yBase - yFarTop + topRy + 40);\n ctx.restore();\n\n // Riser side (the deck wall) — dark, from the near-top ellipse down to the floor.\n ctx.fillStyle = '#0c1019';\n ctx.beginPath();\n ctx.moveTo(cx - halfW, topCy);\n ctx.ellipse(cx, topCy, halfW, topRy, 0, Math.PI, 0, false);\n ctx.lineTo(cx + halfW, yBase);\n ctx.ellipse(cx, yBase, halfW, topRy, 0, 0, Math.PI, false);\n ctx.closePath();\n ctx.fill();\n // lit vertical seam on the riser front.\n const riser = ctx.createLinearGradient(0, topCy, 0, yBase);\n riser.addColorStop(0, `rgba(${rigTintStr},0.14)`);\n riser.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.fillStyle = riser;\n ctx.fillRect(cx - halfW, topCy, halfW * 2, yBase - topCy);\n\n // Compose the ensemble BEFORE painting the deck so the lighting can key onto\n // the lead performer instead of blooming dead-centre. Deck-local coords:\n // u across (−1..1, screen x), v depth (−1 far edge .. +1 near edge). The old\n // even line-up at exact centre read static — a real in-the-round act stands\n // in an asymmetric cluster with the frontman worked toward one side.\n interface PerfSpot { u: number; v: number; lead?: boolean; pose: number }\n const FORMATIONS: PerfSpot[][] = [\n // frontman + guitarist + one at the back\n [{ u: -0.24, v: 0.4, lead: true, pose: 3 }, { u: 0.34, v: -0.04, pose: 2 }, { u: -0.52, v: -0.38, pose: 0 }],\n // duo — singer forward, instrument behind the shoulder\n [{ u: 0.2, v: 0.34, lead: true, pose: 3 }, { u: -0.3, v: -0.08, pose: 2 }],\n // 4-piece — lead just off-centre, band staggered around the far half\n [{ u: -0.1, v: 0.28, lead: true, pose: 1 }, { u: 0.44, v: -0.2, pose: 2 }, { u: -0.46, v: -0.14, pose: 2 }, { u: 0.08, v: -0.46, pose: 0 }],\n ];\n const form = FORMATIONS[Math.floor(rand() * FORMATIONS.length)];\n const mirror = rand() < 0.5 ? -1 : 1; // seeded side, so venues differ\n const spotX = (p: PerfSpot) => cx + p.u * mirror * halfW * 0.84;\n const spotY = (p: PerfSpot) => topCy + p.v * topRy * 0.8;\n const lead = form.find((p) => p.lead) ?? form[0];\n const leadX = spotX(lead);\n\n // Deck top face — a lit elliptical platform.\n const deckTop = ctx.createLinearGradient(0, topCy - topRy, 0, topCy + topRy);\n deckTop.addColorStop(0, '#3d4a72');\n deckTop.addColorStop(1, '#232b47');\n ctx.fillStyle = deckTop;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.fill();\n // warm bloom on the deck, centred under the LEAD, not the geometric middle.\n const deckGlow = ctx.createRadialGradient(leadX, topCy, 2, leadX, topCy, halfW);\n deckGlow.addColorStop(0, `rgba(255,214,160,${(0.5 * nearGlow).toFixed(3)})`);\n deckGlow.addColorStop(1, 'rgba(255,214,160,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = deckGlow;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n // lit rim around the deck edge.\n ctx.strokeStyle = `rgba(${rigTintStr},0.7)`;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.stroke();\n\n // Backline gear on the far half of the deck (amps/risers + a drum hint for\n // bigger acts) — silhouette furniture so the disc doesn't float empty.\n const perfH = Math.max(24, (yBase - yFarTop) * 1.3);\n const gearN = form.length >= 3 ? 3 : 2;\n for (let i = 0; i < gearN; i++) {\n const gu = (-0.62 + i * 0.52 + (rand() - 0.5) * 0.12) * -mirror;\n const gx = cx + gu * halfW * 0.7;\n const gy = topCy - topRy * (0.45 + rand() * 0.18);\n const gw = halfW * (0.07 + rand() * 0.04);\n const gh = perfH * (0.26 + rand() * 0.12);\n ctx.fillStyle = '#0a0e18';\n ctx.fillRect(gx - gw / 2, gy - gh, gw, gh);\n ctx.fillStyle = `rgba(${rigTintStr},0.3)`;\n ctx.fillRect(gx - gw / 2, gy - gh, gw, 1.5);\n }\n if (form.length >= 3) {\n // drum-kit hint: a low wide disc behind the ensemble's empty quarter.\n const drumX = cx - lead.u * mirror * halfW * 0.4;\n ctx.fillStyle = '#0b0f1a';\n ctx.beginPath();\n ctx.ellipse(drumX, topCy - topRy * 0.34, halfW * 0.08, topRy * 0.1, 0, 0, TAU);\n ctx.fill();\n ctx.strokeStyle = `rgba(${rigTintStr},0.35)`;\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n\n // Performers, far → near so the near ones occlude; height foreshortens with\n // deck depth (far-side figures smaller, higher on the ellipse).\n for (const p of [...form].sort((a, b) => a.v - b.v)) {\n const depthScale = 0.82 + (p.v + 1) * 0.14; // −1..1 → 0.82..1.1\n drawPerformer(ctx, spotX(p), spotY(p), perfH * depthScale * (p.lead ? 1.06 : 0.92), {\n tone: [18, 21, 34],\n alpha: 0.95,\n pose: p.pose,\n rim: hslToRgb(40, 0.72, 0.8),\n rimStrength: p.lead ? 1.4 : 0.9,\n });\n }\n\n // Truss ring above the deck with hanging fixtures + tapered beams onto the deck.\n const trussY = pitchToY(Math.min(60, farTopPitch + 34));\n const trussRy = topRy * 1.1 + 6;\n ctx.strokeStyle = 'rgba(60,68,92,0.85)';\n ctx.lineWidth = 3;\n ctx.beginPath();\n ctx.ellipse(cx, trussY, halfW * 1.15, trussRy, 0, 0, TAU);\n ctx.stroke();\n const fixtures = 4 + Math.floor(rand() * 3);\n for (let i = 0; i < fixtures; i++) {\n const a = (i / fixtures) * TAU;\n const fxX = cx + Math.cos(a) * halfW * 1.15;\n const fxY = trussY + Math.sin(a) * trussRy;\n if (Math.sin(a) > -0.2) {\n // front-facing fixtures cast visible beams down onto the deck.\n const tx = cx + (rand() - 0.5) * halfW * 0.8;\n drawBeam(ctx, fxX, fxY, tx, topCy, 3, halfW * 0.32, rigTintStr, 0.2 * (0.7 + nearGlow * 0.4));\n }\n drawFixture(ctx, fxX, fxY, 3, rigTintStr);\n }\n\n // Centre-hung scoreboard over the deck — the iconic in-the-round silhouette.\n // Without it the upper hemisphere is a black void at close range; with it the\n // eye gets an anchor above the show and the room reads unmistakably \"arena\".\n const scoreY = pitchToY(Math.min(52, farTopPitch + 24));\n const scoreW = Math.max(60, halfW * 0.4);\n const scoreH = Math.max(24, scoreW * 0.34);\n // cables up toward the roof\n ctx.strokeStyle = 'rgba(70,78,102,0.6)';\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n ctx.moveTo(cx - scoreW * 0.3, scoreY - scoreH / 2);\n ctx.lineTo(cx - scoreW * 0.16, scoreY - scoreH * 2.2);\n ctx.moveTo(cx + scoreW * 0.3, scoreY - scoreH / 2);\n ctx.lineTo(cx + scoreW * 0.16, scoreY - scoreH * 2.2);\n ctx.stroke();\n // body\n ctx.fillStyle = '#0d1220';\n ctx.fillRect(cx - scoreW / 2, scoreY - scoreH / 2, scoreW, scoreH);\n // glowing screen face with a soft video wash\n const screen = ctx.createLinearGradient(0, scoreY - scoreH * 0.3, 0, scoreY + scoreH * 0.42);\n screen.addColorStop(0, `rgba(${rigTintStr},0.5)`);\n screen.addColorStop(1, 'rgba(255,214,160,0.32)');\n ctx.fillStyle = screen;\n ctx.fillRect(cx - scoreW * 0.42, scoreY - scoreH * 0.3, scoreW * 0.84, scoreH * 0.72);\n // lit underside rim — reads as the ribbon board\n ctx.fillStyle = 'rgba(255,214,160,0.55)';\n ctx.fillRect(cx - scoreW / 2, scoreY + scoreH / 2 - 2, scoreW, 2);\n // soft glow bleeding off the screens into the air\n const scoreGlow = ctx.createRadialGradient(cx, scoreY, 4, cx, scoreY, scoreW * 1.1);\n scoreGlow.addColorStop(0, `rgba(${rigTintStr},0.2)`);\n scoreGlow.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = scoreGlow;\n ctx.fillRect(cx - scoreW * 1.1, scoreY - scoreW * 0.8, scoreW * 2.2, scoreW * 1.6);\n // haze of light in the air between the rig and the deck — show-light spill.\n const airGlow = ctx.createRadialGradient(cx, (trussY + topCy) / 2, 6, cx, (trussY + topCy) / 2, halfW * 1.5);\n airGlow.addColorStop(0, `rgba(${rigTintStr},${(0.1 * (0.6 + nearGlow * 0.5)).toFixed(3)})`);\n airGlow.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.fillStyle = airGlow;\n ctx.fillRect(cx - halfW * 1.5, trussY - 40, halfW * 3, topCy - trussY + 80);\n ctx.restore();\n // Key light: one stronger, tighter beam pinned on the lead — the eye lands\n // where the show is, which is what was missing from the dead-centre wash.\n const keyX = cx + Math.sign(leadX - cx || 1) * halfW * 0.5;\n drawBeam(ctx, keyX, trussY - trussRy * 0.4, leadX, spotY(lead), 2.5, halfW * 0.16, '255,224,178', 0.42 * (0.7 + nearGlow * 0.4));\n // hot pool where the key lands — grounds the lead in light.\n const pool2 = ctx.createRadialGradient(leadX, spotY(lead), 1, leadX, spotY(lead), halfW * 0.2);\n pool2.addColorStop(0, `rgba(255,228,185,${(0.4 * nearGlow).toFixed(3)})`);\n pool2.addColorStop(1, 'rgba(255,228,185,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = pool2;\n ctx.beginPath();\n ctx.ellipse(leadX, spotY(lead), halfW * 0.2, topRy * 0.24, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n}\n\n/**\n * A flat sports playing surface (rink/court) in the middle of the bowl: a bright\n * lit ellipse with faint markings, a scoreboard glow overhead instead of a stage\n * screen, and even arena flood lighting. No proscenium, no performers.\n */\nfunction drawSportScene(\n ctx: CanvasRenderingContext2D,\n distM: number,\n eyeM: number,\n scene: Scene,\n _nearGlow: number,\n baseHue: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n const cx = W / 2;\n const surfR = Math.max(10, scene.voidRadiusM);\n // The surface spans a wide arc; near edge close, far edge across the bowl.\n const nearEdge = Math.max(2, distM - surfR);\n const farEdge = distM + surfR;\n const halfYaw = Math.min(78, (Math.atan2(surfR * 1.15, distM) * 180) / Math.PI);\n const nearPitch = (Math.atan2(-eyeM, nearEdge) * 180) / Math.PI;\n const farPitch = (Math.atan2(-eyeM, farEdge) * 180) / Math.PI;\n const yNear = pitchToY(nearPitch);\n const yFar = pitchToY(farPitch);\n const halfW = yawToX(halfYaw) - cx;\n const cy = (yNear + yFar) / 2;\n const ry = Math.max(10, (yNear - yFar) / 2);\n\n // Cool bright playing surface (ice/court), a soft blue-white.\n const surfCol = ctx.createRadialGradient(cx, cy, 4, cx, cy, halfW);\n surfCol.addColorStop(0, '#e8f0fb');\n surfCol.addColorStop(0.7, '#b9c9e2');\n surfCol.addColorStop(1, '#8fa3c4');\n ctx.save();\n ctx.beginPath();\n ctx.ellipse(cx, cy, halfW, ry, 0, 0, TAU);\n ctx.clip();\n ctx.fillStyle = surfCol;\n ctx.fillRect(cx - halfW, cy - ry, halfW * 2, ry * 2);\n // faint markings: centre line + centre circle + two zone lines.\n ctx.strokeStyle = 'rgba(90,120,170,0.5)';\n ctx.lineWidth = 3;\n ctx.beginPath();\n ctx.moveTo(cx, cy - ry);\n ctx.lineTo(cx, cy + ry);\n ctx.moveTo(cx - halfW * 0.5, cy - ry);\n ctx.lineTo(cx - halfW * 0.5, cy + ry);\n ctx.moveTo(cx + halfW * 0.5, cy - ry);\n ctx.lineTo(cx + halfW * 0.5, cy + ry);\n ctx.stroke();\n ctx.strokeStyle = 'rgba(180,90,110,0.45)';\n ctx.beginPath();\n ctx.ellipse(cx, cy, ry * 0.9, ry * 0.5, 0, 0, TAU);\n ctx.stroke();\n ctx.restore();\n // lit rim / board line around the surface.\n ctx.strokeStyle = 'rgba(210,225,245,0.6)';\n ctx.lineWidth = 2.5;\n ctx.beginPath();\n ctx.ellipse(cx, cy, halfW, ry, 0, 0, TAU);\n ctx.stroke();\n\n // A couple of tiny player marks for life (small, not performers).\n ctx.fillStyle = 'rgba(20,26,40,0.8)';\n for (let i = 0; i < 5; i++) {\n const px = cx + (rand() - 0.5) * halfW * 1.4;\n const py = cy + (rand() - 0.5) * ry * 1.1;\n const s = Math.max(2, ry * 0.06);\n ctx.beginPath();\n ctx.ellipse(px, py, s * 0.6, s, 0, 0, TAU);\n ctx.fill();\n }\n\n // Cool even wash of light on the surface.\n const wash = ctx.createRadialGradient(cx, cy, 4, cx, cy, halfW * 1.4);\n wash.addColorStop(0, 'rgba(200,220,255,0.12)');\n wash.addColorStop(1, 'rgba(200,220,255,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = wash;\n ctx.fillRect(cx - halfW * 1.4, yFar - ry, halfW * 2.8, yNear - yFar + ry * 2);\n ctx.restore();\n\n // Scoreboard cluster overhead — a glowing hexagonal bank centred over the ice.\n const sbY = pitchToY(Math.min(66, farPitch + 60));\n const sbW = Math.max(80, halfW * 0.7);\n const sbH = sbW * 0.5;\n const sbGlow = ctx.createRadialGradient(cx, sbY, 4, cx, sbY, sbW * 1.6);\n sbGlow.addColorStop(0, `rgba(${rigTintStr},0.3)`);\n sbGlow.addColorStop(1, `rgba(${rigTintStr},0)`);\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = sbGlow;\n ctx.fillRect(cx - sbW * 1.6, sbY - sbW * 1.2, sbW * 3.2, sbW * 2.4);\n ctx.restore();\n // scoreboard body — four lit screens around a dark hexagon.\n ctx.fillStyle = '#080b12';\n ctx.beginPath();\n ctx.moveTo(cx - sbW / 2, sbY - sbH / 2);\n ctx.lineTo(cx + sbW / 2, sbY - sbH / 2);\n ctx.lineTo(cx + sbW * 0.6, sbY);\n ctx.lineTo(cx + sbW / 2, sbY + sbH / 2);\n ctx.lineTo(cx - sbW / 2, sbY + sbH / 2);\n ctx.lineTo(cx - sbW * 0.6, sbY);\n ctx.closePath();\n ctx.fill();\n const screenHue = baseHue;\n for (let i = 0; i < 3; i++) {\n const scol = hslToRgb(screenHue + i * 30, 0.5, 0.5);\n ctx.fillStyle = `rgba(${scol[0]},${scol[1]},${scol[2]},0.75)`;\n const swid = sbW * 0.26;\n ctx.fillRect(cx - sbW * 0.42 + i * (swid + sbW * 0.06), sbY - sbH * 0.32, swid, sbH * 0.64);\n }\n // hanging rig lights under the scoreboard.\n ctx.fillStyle = `rgba(${rigTintStr},0.9)`;\n for (let i = 0; i < 8; i++) {\n const lx = cx - sbW * 0.6 + (sbW * 1.2 * i) / 7;\n ctx.beginPath();\n ctx.arc(lx, sbY + sbH * 0.62, 2.4, 0, TAU);\n ctx.fill();\n }\n}\n\n// ---- audience ---------------------------------------------------------------\n\n/**\n * Nearby seats drawn as stylised silhouettes at their true bearing, sorted far→\n * near so front rows occlude the rows behind (painter's order). Three LOD bands:\n * near = full head/neck/shoulders + hair + rim; mid = simplified head+shoulders;\n * far = a dot + shoulder cap. A seat-back rail is drawn last when a seat sits\n * directly ahead (front-row seats face open floor and get none).\n */\nfunction drawAudience(\n ctx: CanvasRenderingContext2D,\n seat: ExpandedSeat,\n neighborSeats: ExpandedSeat[],\n _focalPoint: Point,\n stageBearing: number,\n eyeM: number,\n dx: number,\n dy: number,\n hasRelief: boolean,\n scene: Scene,\n): void {\n const own = seat.sectionId;\n let seatAhead = false;\n interface Fig { hx: number; hy: number; r: number; d: number; hash: number }\n const figs: Fig[] = [];\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 (own && other.sectionId === own && d < 3 && ox * dx + oy * dy > 0) seatAhead = true;\n if (d < 0.3 || d > 32) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const rise = hasRelief ? (other.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - eyeM : 0;\n // Head sits ~0.28m below the eye-line of its own seat, rake-shifted.\n const headPitch = (Math.atan2(rise - 0.28, d) * 180) / Math.PI;\n // Skip the far-and-high leak: same-section neighbours up the rake that the\n // fan curvature bends into the forward cone would otherwise read as a crowd\n // floating above the stage. A believable \"row in front\" sits at or below the\n // eye-line, so anything far AND well above it is culled.\n if (headPitch > 10 && d > 5) continue;\n let hh = 0;\n for (let k = 0; k < other.id.length; k++) hh = (hh * 31 + other.id.charCodeAt(k)) & 0xffff;\n // Physically-based head size: a ~0.16 m head half-width at distance d.\n const jitter = 0.9 + (hh & 15) / 40; // ~0.9..1.28\n const r = Math.min(78, (Math.atan2(0.16, d) * 180 / Math.PI) * PX_PER_DEG * jitter);\n if (r < 1.2) continue;\n figs.push({ hx: yawToX(yaw), hy: pitchToY(headPitch), r, d, hash: hh });\n }\n // Painter's order: far first so nearer figures overlap on top.\n figs.sort((a, b) => b.d - a.d);\n\n // Group figures into screen-space rows (similar head pitch → same physical\n // row) so each row can carry a seat-back strip behind its heads: the strip\n // fills the gaps BETWEEN figures, which is what makes a crowd read dense —\n // background showing between every head reads as a half-empty house.\n interface FigRow { figs: Fig[]; d: number; hy: number; r: number }\n const figRows: FigRow[] = [];\n {\n const byY = [...figs].sort((a, b) => a.hy - b.hy);\n let cur: Fig[] = [];\n const flush = () => {\n if (!cur.length) return;\n const d = cur.reduce((s, f) => s + f.d, 0) / cur.length;\n const hy = cur.reduce((s, f) => s + f.hy, 0) / cur.length;\n const r = cur.reduce((s, f) => s + f.r, 0) / cur.length;\n figRows.push({ figs: cur.sort((a, b) => b.d - a.d), d, hy, r });\n cur = [];\n };\n for (const f of byY) {\n const last = cur[cur.length - 1];\n if (last && Math.abs(f.hy - last.hy) > Math.max(5, ((last.r + f.r) / 2) * 1.7)) flush();\n cur.push(f);\n }\n flush();\n }\n figRows.sort((a, b) => b.d - a.d); // rows far → near: strip, then its figures\n\n const CLOTHES: RGB[] = [[22, 26, 40], [28, 27, 42], [24, 31, 46], [31, 30, 47], [20, 24, 36]];\n for (const row of figRows) {\n // Seat-back strip: contiguous runs of figures (split at real aisles) get a\n // soft dark band at shoulder height. Subtle — texture, not architecture.\n if (row.figs.length >= 3 && row.r >= 1.6 && row.r < 26) {\n const runs: Fig[][] = [];\n const byX = [...row.figs].sort((a, b) => a.hx - b.hx);\n let run: Fig[] = [];\n for (const f of byX) {\n const last = run[run.length - 1];\n if (last && f.hx - last.hx > Math.max(14, f.r * 7)) {\n if (run.length >= 3) runs.push(run);\n run = [];\n }\n run.push(f);\n }\n if (run.length >= 3) runs.push(run);\n const stripAlpha = Math.min(0.42, 0.5 * (1 - row.d / 42));\n if (stripAlpha > 0.05) {\n ctx.fillStyle = `rgba(15, 19, 31, ${stripAlpha.toFixed(3)})`;\n for (const seg of runs) {\n const x0 = seg[0].hx - row.r * 1.6;\n const x1 = seg[seg.length - 1].hx + row.r * 1.6;\n ctx.beginPath();\n ctx.roundRect(x0, row.hy + row.r * 0.8, x1 - x0, row.r * 2.4, row.r * 0.8);\n ctx.fill();\n }\n }\n }\n for (const f of row.figs) {\n // Near figures are near-solid so they occlude cleanly; the extended\n // mid-band tail fades out gently so the crowd dissolves into the stands\n // instead of stopping at a hard radius.\n const alpha = f.d < 12 ? 0.95 : f.d < 17 ? Math.max(0.66, 0.95 - (f.d - 12) / 18) : Math.max(0.3, 0.68 - (f.d - 17) / 34);\n const lift = Math.round((1 - Math.min(1, f.d / 16)) * 10);\n const headTone: RGB = [14 + ((f.hash >> 4) & 6) + lift, 17 + ((f.hash >> 4) & 6) + lift, 25 + ((f.hash >> 4) & 6) + lift];\n const clo0 = CLOTHES[f.hash % CLOTHES.length];\n const clothing: RGB = [clo0[0] + lift, clo0[1] + lift, clo0[2] + lift];\n if (f.r >= 13) {\n const rim = f.d < 9 ? 0.16 * (1 - f.d / 9) + (scene.mode === 'proscenium' ? 0.06 : 0) : 0;\n drawSeated(ctx, f.hx, f.hy, f.r, {\n tone: headTone,\n clothing,\n alpha,\n tilt: (((f.hash >> 2) & 7) - 3.5) * 0.018, // ±~7°\n shoulderK: 1.72 + ((f.hash >> 5) & 7) / 22, // ~1.72..2.04\n hair: f.hash % HAIR_KINDS,\n rim,\n turn: (((f.hash >> 8) & 7) - 3.5) * 0.034, // ±~0.12 head-radii sideways\n lean: (((f.hash >> 10) & 3) - 1.5) * 0.09, // one shoulder rides higher\n });\n } else if (f.r >= 5.5) {\n drawSeatedMid(ctx, f.hx, f.hy, f.r, clothing, headTone, alpha);\n } else {\n ctx.fillStyle = `rgba(${headTone[0]},${headTone[1]},${headTone[2]},${alpha.toFixed(3)})`;\n ctx.beginPath();\n ctx.arc(f.hx, f.hy, f.r, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(f.hx, f.hy + f.r * 1.4, f.r * 1.85, f.r * 0.95, 0, Math.PI, 0, true);\n ctx.fill();\n }\n }\n }\n\n // Foreground seat-back rail (only when a seat sits directly ahead).\n if (seatAhead) {\n const railTop = pitchToY(-34);\n ctx.fillStyle = 'rgba(6, 8, 14, 0.92)';\n ctx.fillRect(0, railTop, W, H - railTop);\n ctx.fillStyle = 'rgba(24, 30, 46, 0.9)';\n const humps = 16;\n for (let i = 0; i < humps; i++) {\n const cx = ((i + 0.5) / humps) * W;\n ctx.beginPath();\n ctx.ellipse(cx, railTop + 6, (W / humps) * 0.42, 22, 0, Math.PI, 0, true);\n ctx.fill();\n }\n }\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. It has no neighbour list, so it always\n// draws a compact upgraded proscenium (arch + inset backdrop + posed performers\n// + tapered beams), seeded off the seat id so venues still differ.\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 const rand = rng(fnv1a(`${seat.id}|${Math.round(focalPoint.x)},${Math.round(focalPoint.y)}`));\n const baseHue = 210 + rand() * 150;\n const rigTint = hslToRgb(220 + (rand() - 0.5) * 60, 0.55, 0.82);\n const rigTintStr = `${rigTint[0]},${rigTint[1]},${rigTint[2]}`;\n\n // hall shell (ceiling → wall → floor), horizon at mid-height.\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#080b12');\n sky.addColorStop(0.44, '#151c32');\n sky.addColorStop(0.5, '#1d2644');\n sky.addColorStop(0.58, '#161c2e');\n sky.addColorStop(1, '#131829');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageHalfYaw = Math.min(HALF_HFOV - 2, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(HALF_VFOV - 2, sightline.topPitch);\n const stageBasePitch = Math.max(-HALF_VFOV + 2, sightline.basePitch);\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 const nearGlow = Math.max(0.35, Math.min(1, 1 - (distM - 6) / 60));\n const archTop = pitchToTY(Math.min(HALF_VFOV - 1, stageTopPitch + 8));\n\n // glow bloom behind the opening.\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.15);\n glow.addColorStop(0, 'rgba(255,214,150,0.34)');\n glow.addColorStop(0.28, 'rgba(150,150,230,0.3)');\n glow.addColorStop(0.6, 'rgba(99,102,241,0.12)');\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 // backdrop inset with soft edge falloff.\n const topCol = hslToRgb(baseHue, 0.62, 0.55);\n const midCol = hslToRgb(baseHue + 40, 0.7, 0.5);\n const botCol = hslToRgb(baseHue + 70, 0.78, 0.52);\n ctx.save();\n ctx.beginPath();\n ctx.rect(sx0, sy0, sw, sh);\n ctx.clip();\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, `rgb(${topCol[0]},${topCol[1]},${topCol[2]})`);\n backdrop.addColorStop(0.5, `rgb(${midCol[0]},${midCol[1]},${midCol[2]})`);\n backdrop.addColorStop(1, `rgb(${botCol[0]},${botCol[1]},${botCol[2]})`);\n ctx.globalAlpha = 0.8;\n ctx.fillStyle = backdrop;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.globalAlpha = 1;\n const fall = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, sw * 0.12, TW / 2, (sy0 + sy1) / 2, sw * 0.6);\n fall.addColorStop(0, 'rgba(6,8,14,0)');\n fall.addColorStop(0.7, 'rgba(6,8,14,0.15)');\n fall.addColorStop(1, 'rgba(5,6,11,0.9)');\n ctx.fillStyle = fall;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.restore();\n\n // performers.\n const perfCount = 3;\n const floorY = sy1 - sh * 0.08;\n for (let i = 0; i < perfCount; i++) {\n const t = (i + 1) / (perfCount + 1);\n drawPerformer(ctx, sx0 + sw * (0.24 + t * 0.52), floorY, sh * 0.46 * (0.9 + rand() * 0.24), {\n tone: [8, 10, 16],\n alpha: 0.9,\n pose: Math.floor(rand() * 4),\n rim: hslToRgb(baseHue + 20, 0.5, 0.7),\n rimStrength: 0.7,\n });\n }\n\n // masking wings + arch.\n ctx.fillStyle = '#05070d';\n ctx.fillRect(sx0 - sw * 0.5, archTop, sw * 0.5, sy1 - archTop);\n ctx.fillRect(sx1, archTop, sw * 0.5, sy1 - archTop);\n const legBot = sw * 0.05 + 2;\n const legTop = legBot * 1.35;\n ctx.fillStyle = '#03050a';\n ctx.beginPath();\n ctx.moveTo(sx0, sy1);\n ctx.lineTo(sx0 - legBot, sy1);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.lineTo(sx0 + sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n ctx.beginPath();\n ctx.moveTo(sx1, sy1);\n ctx.lineTo(sx1 + legBot, sy1);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx1 - sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n ctx.fillRect(sx0 - legTop, archTop, sw + legTop * 2, (sy1 - archTop) * 0.13);\n ctx.fillStyle = `rgba(${rigTintStr},0.12)`;\n ctx.fillRect(sx0 - 1.2, archTop, 1.2, sy1 - archTop);\n ctx.fillRect(sx1, archTop, 1.2, sy1 - archTop);\n\n // stage floor front edge + footlights.\n ctx.fillStyle = '#0b0f18';\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.05 + 2);\n const foot = ctx.createLinearGradient(0, sy1 - sh * 0.05, 0, sy1 + sh * 0.14);\n foot.addColorStop(0, `rgba(255,206,140,${(0.5 * nearGlow).toFixed(3)})`);\n foot.addColorStop(1, 'rgba(255,206,140,0)');\n ctx.fillStyle = foot;\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.22);\n\n // tapered beams.\n for (let i = 0; i < 3; i++) {\n const t = (i + 1) / 4;\n const fx = sx0 + sw * t;\n const fy = pitchToTY(Math.min(HALF_VFOV - 1, stageTopPitch + 20));\n drawBeam(ctx, fx, fy, fx + (rand() - 0.5) * sw * 0.14, sy1, 3, sw * 0.09, rigTintStr, 0.17 * nearGlow);\n drawFixture(ctx, fx, fy, 1.8, rigTintStr);\n }\n\n // rig lights across the ceiling.\n ctx.fillStyle = `rgba(${rigTintStr},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, TAU);\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++) {\n const bx = i * (TW / 9) + TW / 18;\n ctx.beginPath();\n ctx.ellipse(bx, TH - 22, (TW / 9) * 0.4, 15, 0, Math.PI, 0, true);\n ctx.fill();\n }\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 — they are ~2.5 KB gzipped of the complete CDN artifact — and\n * code-splits each locale so a page/SDK only downloads the language it actually\n * uses. (The \"150 KB product contract\" this used to cite was never true of a\n * shipped bundle; see docs/hosted-checkout-programme-2026-08-03.md §W4.)\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":["objects","bounds","t","rgb","bounds","scale","stageX","stageY","centroid","seatIndex","active","t","t","rgb"]}
1
+ {"version":3,"sources":["../src/core/ga.ts","../src/core/sections.ts","../src/core/chartRenderRules.ts","../src/core/renderedQuality.ts","../src/engine/SeatmapRenderer.ts","../src/core/chartBackgrounds.ts","../src/core/icons.ts","../src/core/spatialIndex.ts","../src/core/perspectiveProjection.ts","../src/lib/money.ts","../src/i18n/locales/en.ts","../src/i18n/index.ts","../src/core/shapeLineStyle.ts","../src/core/orphans.ts","../src/core/bestAvailable.ts","../src/core/tableInventory.ts","../src/picker/PickerController.ts","../src/view/sightline.ts","../src/view/generatePanorama.ts","../src/i18n/bundles.ts"],"sourcesContent":["import type { ChartDoc, GAAreaObject, GAInventorySegment } 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\n/** Strict, bounded validation for durable Join Areas inventory provenance. */\nexport function validGAInventorySegments(area: GAAreaObject): boolean {\n const segments = area.inventorySegments;\n if (segments === undefined) return true;\n if (!Array.isArray(segments) || segments.length < 1 || segments.length > 256) return false;\n let total = 0;\n const ranges = new Map<string, Array<{ start: number; end: number }>>();\n for (const segment of segments) {\n if (!segment || typeof segment.sourceAreaId !== 'string'\n || !segment.sourceAreaId.trim() || segment.sourceAreaId.length > 160\n || !Number.isInteger(segment.startIndex) || segment.startIndex < 0\n || !Number.isInteger(segment.count) || segment.count < 1\n || segment.startIndex + segment.count > MAX_GA_CAPACITY) return false;\n total += segment.count;\n if (total > MAX_GA_CAPACITY) return false;\n const sourceRanges = ranges.get(segment.sourceAreaId) ?? [];\n const end = segment.startIndex + segment.count;\n if (sourceRanges.some((range) => segment.startIndex < range.end && end > range.start)) return false;\n sourceRanges.push({ start: segment.startIndex, end });\n ranges.set(segment.sourceAreaId, sourceRanges);\n }\n return total === area.capacity;\n}\n\n/** Canonical source ranges. Invalid explicit provenance intentionally yields no\n * labels: chart validation blocks publication instead of inventing identities. */\nexport function gaInventorySegments(area: GAAreaObject): GAInventorySegment[] {\n const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));\n if (area.inventorySegments === undefined) {\n return capacity ? [{ sourceAreaId: area.id, startIndex: 0, count: capacity }] : [];\n }\n if (!validGAInventorySegments(area)) return [];\n return area.inventorySegments.map((segment) => ({ ...segment }));\n}\n\nexport function gaUnitLabels(area: GAAreaObject): string[] {\n return gaInventorySegments(area).flatMap((segment) => Array.from(\n { length: segment.count },\n (_, offset) => gaUnitLabel(segment.sourceAreaId, segment.startIndex + offset),\n ));\n}\n\n/** Append-only capacity semantics for an already joined GA surface. */\nexport function growJoinedGAInventory(area: GAAreaObject, nextCapacity: number): GAInventorySegment[] | undefined {\n if (area.inventorySegments === undefined || nextCapacity === area.capacity) return area.inventorySegments;\n if (nextCapacity < area.capacity) return undefined;\n const segments = gaInventorySegments(area);\n if (!segments.length) return undefined;\n const extra = nextCapacity - area.capacity;\n if (!extra) return segments;\n const ownRanges = segments.filter((segment) => segment.sourceAreaId === area.id);\n const startIndex = ownRanges.reduce((max, segment) => Math.max(max, segment.startIndex + segment.count), 0);\n const last = segments[segments.length - 1];\n if (last?.sourceAreaId === area.id && last.startIndex + last.count === startIndex) {\n last.count += extra;\n } else {\n if (segments.length >= 256) return undefined;\n segments.push({ sourceAreaId: area.id, startIndex, count: extra });\n }\n return segments;\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, owningSectionForObject } from './layout';\nimport { gaUnitLabels } from './ga';\n\n/**\n * The section 3D-geometry resolver + tier fallback constant now live in the leaf\n * `units.ts` module (so `layout.ts` can consume them without an import cycle).\n * Re-exported here to keep the historical `from './sections'` import path working.\n */\nexport { sectionGeometry, TIER_HEIGHT_M } from './units';\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\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 const owner = owningSectionForObject(objs, obj);\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 * 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\nimport type { AccessibilityType } from './types';\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/** Square viewBox every accessibility glyph path's coordinates live in. */\nexport const ACCESS_GLYPH_VIEWBOX = 24;\n\n/**\n * Per-accommodation pictograms drawn centred on accessible seats. Each is a\n * SOLID filled silhouette in the 0 0 24 24 viewBox, designed to stay legible at\n * the ~13px it renders on a seat dot (bold shapes, no thin strokes). A vector\n * path renders crisply at small sizes on every platform, unlike a colour emoji\n * whose canvas metrics/alignment are inconsistent cross-browser.\n *\n * The owner directive (OV-89): every accessibility type must render ITS OWN\n * meaningful glyph so a buyer *sees* what the seat provides — the coloured ring\n * still encodes the type by colour, but the on-seat icon now matches the\n * filter's meaning instead of every non-wheelchair type showing a bare ring.\n *\n * Every path below is numerically validated (bbox centred within 12±1.5, longer\n * axis spans 14–22 units) — see scratchpad/validate-glyphs.mjs in the authoring\n * session. Keep any edit passing that check.\n */\nexport const ACCESS_TYPE_GLYPH_PATHS: Record<AccessibilityType, string> = {\n // ISO-style wheelchair: seated figure (head + L-shaped body) over a ring wheel.\n wheelchair:\n 'M7.8 4.5a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0z'\n + 'M8 7L10.5 7L10.5 15L8 15Z'\n + 'M8 12.5L18 12.5L18 15L8 15Z'\n + 'M16 15L18 15L18 18L16 18Z'\n + 'M5.5 16a5.5 5.5 0 1 0 11 0a5.5 5.5 0 1 0 -11 0z'\n + 'M8 16a3 3 0 1 1 6 0a3 3 0 1 1 -6 0z',\n // Companion: two overlapping head-and-shoulders figures (seat + a guest).\n companion:\n 'M5.5 6.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0z'\n + 'M4.5 18.5L6 11.5L11 11.5L12.5 18.5Z'\n + 'M12.5 7.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0z'\n + 'M11.5 19L13 12.5L18 12.5L19.5 19Z',\n // Semi-ambulatory: walking figure leaning on a cane at its right side.\n 'semi-ambulatory':\n 'M8.3 3.8a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0z'\n + 'M9 6.2L12 6.6L11 13.5L8.6 13L9 6.2Z'\n + 'M8.6 13L11 13L9.5 21L7 21Z'\n + 'M10.4 13L12.6 13L13.6 21L11.2 21Z'\n + 'M11.2 7.2L14 8L14.6 9.6L11.9 8.9Z'\n + 'M14.4 6.8L15.9 6.8L16.4 21L14.8 21Z',\n // Hearing: a bold ear silhouette (assistive listening).\n hearing:\n 'M15.5 3.5'\n + 'C9 2.2 5.5 6 5.5 11.5'\n + 'C5.5 16 8 19.5 10.5 21'\n + 'C13.2 22.6 16.4 20.8 15.4 18'\n + 'C14.8 16.4 12.9 16.1 13 14'\n + 'C13.1 11.9 15.8 11.4 15.8 8.5'\n + 'C15.8 5.4 13 4 15.5 3.5Z',\n // CART captions: a rounded caption bubble with two bold caption bars cut out.\n cart:\n 'M5.5 6L18.5 6a2.5 2.5 0 0 1 2.5 2.5L21 15.5a2.5 2.5 0 0 1 -2.5 2.5L11 18L7 20.5L7.5 18L5.5 18a2.5 2.5 0 0 1 -2.5 -2.5L3 8.5a2.5 2.5 0 0 1 2.5 -2.5z'\n + 'M6.5 11L17.5 11L17.5 12.6L6.5 12.6z'\n + 'M6.5 14L17.5 14L17.5 15.6L6.5 15.6z',\n // Sign language: a raised open hand (palm with four fingers and a thumb).\n 'sign-language':\n 'M7 11L17 11L17 18a2 2 0 0 1 -2 2L9 20a2 2 0 0 1 -2 -2z'\n + 'M7.6 5L9.4 5L9.4 12L7.6 12z'\n + 'M9.9 3.5L11.7 3.5L11.7 12L9.9 12z'\n + 'M12.3 3.5L14.1 3.5L14.1 12L12.3 12z'\n + 'M14.6 5L16.4 5L16.4 12L14.6 12z'\n + 'M7.2 12.5L5 10.2L6.4 8.9L8.6 11.2Z',\n // Plus-size: a broad-shouldered wide figure.\n 'plus-size':\n 'M9.4 4.3a2.6 2.6 0 1 0 5.2 0a2.6 2.6 0 1 0 -5.2 0z'\n + 'M5 20L4 13C4 10.5 7 9.5 12 9.5C17 9.5 20 10.5 20 13L19 20Z',\n // Lift-up armrest: a chair side-profile with an up arrow over the armrest.\n 'lift-armrest':\n 'M5 6L8 6L8 19L5 19z'\n + 'M5 16L18 16L18 19L5 19z'\n + 'M8 12L17 12L17 14.5L8 14.5z'\n + 'M14 7L16 7L16 12L14 12z'\n + 'M12 7L18 7L15 3Z',\n};\n\n/**\n * Legacy default access pictogram — now the ISO-style wheelchair symbol. Kept as\n * an alias of {@link ACCESS_TYPE_GLYPH_PATHS.wheelchair} for back-compat with\n * callers that drew a single wheelchair glyph.\n */\nexport const ACCESS_GLYPH_PATH = ACCESS_TYPE_GLYPH_PATHS.wheelchair;\n\n/**\n * The glyph to draw for a seat's PRIMARY accommodation. Wheelchair wins whenever\n * present (its physical provision is the headline fact); otherwise the first\n * listed accommodation is shown. Returns null for a seat with no accommodations,\n * so callers can skip drawing a glyph.\n */\nexport function accessGlyphPath(accessibility: AccessibilityType[]): string | null {\n if (!accessibility?.length) return null;\n const primary = accessibility.includes('wheelchair') ? 'wheelchair' : accessibility[0];\n return ACCESS_TYPE_GLYPH_PATHS[primary] ?? null;\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 */\n/**\n * Acceptance bar for AUTHORED seat-number / row-label colors (the theme\n * swatches). These are short bold marks whose information is duplicated in\n * tooltips/chips, so the WCAG non-text 3:1 bar applies — under the 4.5:1\n * small-text bar a normal mid-tone category palette rejects EVERY authored\n * color (each seat silently falls back to black/white and the control feels\n * broken; owner-found 07-23). Auto-swap still guards anything below 3:1.\n */\nexport const AUTHORED_LABEL_MIN_CONTRAST = 3;\n\nexport function stateAwareBookableLabelInk(fill: string, preferred: string, minContrast: number = SMALL_TEXT_CONTRAST): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= minContrast) 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\n/**\n * Ink for the accessibility seat glyphs. Unlike seat-number text, these are\n * bold solid silhouettes — graphical objects, so the WCAG non-text bar (3:1)\n * applies, not the 4.5:1 small-text bar. Preferring white at ≥3:1 keeps the\n * glyph crisp on every mid/dark category colour (where a 4.5:1 text rule was\n * falling back to near-invisible dark-on-mid ink); genuinely light seat fills\n * still get the dark ink.\n */\nconst GLYPH_CONTRAST = 3;\nexport function accessGlyphInk(fill: string): string {\n const white = renderedTextContrast('#ffffff', fill);\n if (white != null && white >= GLYPH_CONTRAST) return '#ffffff';\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 '#ffffff';\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 minContrast: number = SMALL_TEXT_CONTRAST,\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, minContrast);\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","import {\n MIN_VISIBLE_BOOKABLE_LABEL_PX,\n renderedTextContrast,\n} from './chartRenderRules';\nimport type {\n RenderedBookableLabelEvidence,\n RenderedFreeTextEvidence,\n RenderedHierarchyLabelEvidence,\n RendererQualityEvidence,\n} from './types';\n\nexport const RENDERED_QUALITY_REPORT_VERSION = 3;\nconst MIN_TEXT_CONTRAST = 4.5;\nconst MIN_GRAPHICAL_CONTRAST = 3;\nconst MIN_POINTER_TARGET_PX = 24;\nconst MAX_SAMPLES_PER_FINDING = 20;\n\nexport type RenderedEvidenceState = 'overview' | 'interaction';\n\ninterface ScreenBox { x: number; y: number; width: number; height: number }\n\nexport type RenderedQualityFindingCode =\n | 'bookable-label-undersized'\n | 'bookable-label-contrast-low'\n | 'bookable-label-collision'\n | 'hierarchy-label-undersized'\n | 'hierarchy-label-contrast-low'\n | 'hierarchy-label-outside-section'\n | 'hierarchy-label-collision'\n | 'hierarchy-bookable-collision'\n | 'overview-section-category-paint'\n | 'overview-category-detail-visible'\n | 'overview-row-hints-visible'\n | 'overview-availability-clutter'\n | 'overview-ga-detail-visible'\n | 'free-text-undersized'\n | 'free-text-contrast-low'\n | 'free-text-collision'\n | 'free-text-bookable-collision'\n | 'free-text-hierarchy-collision'\n | 'ga-contrast-low'\n | 'detail-rung-missing'\n | 'detail-inventory-not-visible'\n | 'pointer-target-undersized'\n | 'pointer-target-inactive'\n | 'selected-state-missing'\n | 'selected-state-contrast-low'\n | 'held-state-missing'\n | 'booked-state-missing'\n | 'status-state-indistinct'\n | 'section-focus-missing'\n | 'category-filter-missing'\n | 'category-filter-ineffective'\n | 'target-category-not-visible'\n | 'target-category-filter-mismatch';\n\nexport interface RenderedQualitySample {\n primaryId: string;\n primaryLabel: string;\n secondaryId?: string;\n secondaryLabel?: string;\n measured?: number;\n minimum?: number;\n}\n\nexport interface RenderedQualityFinding {\n code: RenderedQualityFindingCode;\n message: string;\n count: number;\n samples: RenderedQualitySample[];\n}\n\nexport interface RenderedQualityReport {\n version: typeof RENDERED_QUALITY_REPORT_VERSION;\n passed: boolean;\n state: RenderedEvidenceState;\n /** Server-selected category exercised by a category-specific detail scene. */\n targetCategoryKey: string | null;\n /** Exact overview checks discharged by this browser-rendered report. */\n resolvedRules: string[];\n viewport: { width: number; height: number };\n canvasBackground: string;\n effectiveScale: number;\n rung: RendererQualityEvidence['rung'];\n inventory: {\n totalBookableUnits: number;\n totalLabelledBookableUnits: number;\n visibleBookableLabels: number;\n hiddenBookableLabels: number;\n visibleHierarchyLabels: number;\n visibleFreeTextLabels: number;\n visibleGAAreas: number;\n };\n overviewStyle?: RendererQualityEvidence['overviewStyle'];\n /**\n * Coordinate-free identity evidence from the exact buyer scene. The Worker\n * uses this to compare persisted reference semantics with what Chromium\n * actually painted, without exposing screen boxes or accepting geometry.\n */\n composition: {\n hierarchy: Array<{\n id: string;\n kind: 'section' | 'zone';\n label: string;\n visible: boolean;\n }>;\n labelledObjects: Array<{\n objectId: string;\n kind: RenderedFreeTextEvidence['kind'];\n text: string;\n visible: boolean;\n }>;\n gaAreas: Array<{\n areaId: string;\n label: string;\n categoryKey: string;\n sectionId?: string;\n visible: boolean;\n }>;\n bookableSectionIds: string[];\n categoryKeys: string[];\n /** Categories whose non-dimmed bookable paint is visible in this scene. */\n activeCategoryKeys: string[];\n };\n metrics: {\n minimumRenderedBookableLabelPx: number | null;\n minimumBookableLabelContrast: number | null;\n minimumRenderedHierarchyLabelPx: number | null;\n minimumHierarchyLabelContrast: number | null;\n minimumRenderedFreeTextPx: number | null;\n minimumFreeTextContrast: number | null;\n minimumGAContrast: number | null;\n minimumEffectivePointerTargetPx: number | null;\n selectedRingContrast: number | null;\n };\n interaction: {\n applicable: {\n detail: boolean;\n pointer: boolean;\n held: boolean;\n booked: boolean;\n sectionFocus: boolean;\n categoryFilter: boolean;\n };\n selectedUnits: number;\n heldUnits: number;\n bookedUnits: number;\n activePointerTargets: number;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n };\n findings: RenderedQualityFinding[];\n}\n\ntype VisibleWithBox<T extends { visible: boolean; screenBox?: ScreenBox }> = T & { screenBox: ScreenBox };\n\nfunction visibleWithBox<T extends { visible: boolean; screenBox?: ScreenBox }>(\n items: T[],\n): Array<VisibleWithBox<T>> {\n return items.filter((item): item is VisibleWithBox<T> => item.visible && Boolean(item.screenBox));\n}\n\nfunction intersects(left: ScreenBox, right: ScreenBox): boolean {\n return left.x < right.x + right.width && left.x + left.width > right.x\n && left.y < right.y + right.height && left.y + left.height > right.y;\n}\n\nfunction minimum(values: number[]): number | null {\n return values.length ? Math.round(Math.min(...values) * 100) / 100 : null;\n}\n\nfunction finding(\n code: RenderedQualityFindingCode,\n message: string,\n samples: RenderedQualitySample[],\n): RenderedQualityFinding | null {\n if (!samples.length) return null;\n return {\n code,\n message,\n count: samples.length,\n samples: samples.slice(0, MAX_SAMPLES_PER_FINDING),\n };\n}\n\nfunction labelSample(label: RenderedBookableLabelEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.seatId,\n primaryLabel: label.label,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction hierarchySample(label: RenderedHierarchyLabelEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.id,\n primaryLabel: label.label,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction freeTextSample(label: RenderedFreeTextEvidence, measured?: number, minimumValue?: number): RenderedQualitySample {\n return {\n primaryId: label.objectId,\n primaryLabel: label.text,\n ...(measured == null ? {} : { measured: Math.round(measured * 100) / 100 }),\n ...(minimumValue == null ? {} : { minimum: minimumValue }),\n };\n}\n\nfunction collisionSample(\n primaryId: string,\n primaryLabel: string,\n secondaryId: string,\n secondaryLabel: string,\n): RenderedQualitySample {\n return { primaryId, primaryLabel, secondaryId, secondaryLabel };\n}\n\n/**\n * Inspect what the buyer renderer actually decided to paint at one exact\n * viewport. This is deliberately downstream of ChartDoc validation: screen\n * size, LOD visibility, fitted hierarchy text, transient paint, and label\n * collisions cannot be proven from stored geometry alone.\n */\nexport function inspectRenderedQualityEvidence(\n evidence: RendererQualityEvidence,\n state: RenderedEvidenceState = 'overview',\n targetCategoryKey: string | null = null,\n): RenderedQualityReport {\n const bookable = visibleWithBox(evidence.labels);\n const hierarchy = visibleWithBox(evidence.hierarchyLabels);\n const freeText = visibleWithBox(evidence.freeTextLabels);\n const visibleGA = evidence.gaAreas.filter((area) => area.visible);\n\n const bookableContrast = bookable.map((label) => renderedTextContrast(label.ink, label.fill) ?? 0);\n const hierarchyContrast = hierarchy.map((label) => renderedTextContrast(label.ink, label.fill) ?? 0);\n const freeTextContrast = freeText.map((label) => renderedTextContrast(label.ink, label.background) ?? 0);\n const gaContrast = visibleGA.map((area) => renderedTextContrast(area.effectiveBackground, evidence.canvasBackground) ?? 0);\n const targetLabels = targetCategoryKey\n ? evidence.labels.filter((label) => label.categoryKey === targetCategoryKey)\n : evidence.labels;\n const targetGAAreas = targetCategoryKey\n ? evidence.gaAreas.filter((area) => area.categoryKey === targetCategoryKey)\n : evidence.gaAreas;\n const selected = targetLabels.filter((label) => label.selected);\n const held = targetLabels.filter((label) => label.status === 'held');\n const booked = targetLabels.filter((label) => label.status === 'booked');\n const activePointerTargets = targetLabels.filter((label) => label.pointerTarget.active);\n const activeCategoryKeys = new Set([\n ...evidence.labels\n .filter((label) => label.visible && (label.opacity > 0.25 || label.selected || label.status !== 'free'))\n .map((label) => label.categoryKey),\n ...evidence.gaAreas\n .filter((area) => area.visible && area.opacity > 0.1)\n .map((area) => area.categoryKey),\n ]);\n const selectedRingContrast = selected.length\n ? minimum(selected.flatMap((label) => [\n renderedTextContrast(evidence.selectionRingColor, evidence.canvasBackground) ?? 0,\n renderedTextContrast(evidence.selectionRingColor, label.fill) ?? 0,\n ]))\n : null;\n\n const findings: Array<RenderedQualityFinding | null> = [];\n const overviewCountSamples = (count: number, label: string): RenderedQualitySample[] =>\n Array.from({ length: count }, (_, index) => ({\n primaryId: `overview:${index + 1}`,\n primaryLabel: label,\n }));\n if (state === 'overview' && evidence.rung === 'sections') {\n findings.push(finding(\n 'overview-section-category-paint',\n 'Section overview shells must use the neutral hierarchy palette, not category paint',\n overviewCountSamples(evidence.overviewStyle.categoryPaintedSectionShells, 'category-painted section shell'),\n ));\n findings.push(finding(\n 'overview-category-detail-visible',\n 'Category-tinted section detail must wait until section focus or seat zoom',\n overviewCountSamples(evidence.overviewStyle.visibleCategoryDetailOutlines, 'category detail outline'),\n ));\n findings.push(finding(\n 'overview-row-hints-visible',\n 'Row and seat patterns must not clutter the section overview',\n overviewCountSamples(evidence.overviewStyle.visibleSectionRowHints, 'section row hint'),\n ));\n findings.push(finding(\n 'overview-availability-clutter',\n 'Live availability counts belong in focused detail, not on section overview shells',\n overviewCountSamples(evidence.overviewStyle.visibleSectionAvailabilityLabels, 'section availability label'),\n ));\n findings.push(finding(\n 'overview-ga-detail-visible',\n 'Section-contained standing paint belongs in focused detail, not on section overview shells',\n overviewCountSamples(evidence.overviewStyle.visibleSectionGADetails, 'section-contained GA detail'),\n ));\n }\n findings.push(finding(\n 'bookable-label-undersized',\n 'Visible bookable labels must meet the rendered small-text size floor',\n bookable\n .filter((label) => label.renderedFontPx < evidence.minimumVisibleLabelPx)\n .map((label) => labelSample(label, label.renderedFontPx, evidence.minimumVisibleLabelPx)),\n ));\n\n if (state === 'interaction') {\n const labelledInventory = targetLabels.length > 0;\n const gaInventory = targetGAAreas.length > 0;\n const detailInventory = labelledInventory || gaInventory;\n const visibleTargetGA = targetGAAreas.filter((area) => area.visible);\n const sections = new Set([\n ...targetLabels.flatMap((label) => label.sectionId ? [label.sectionId] : []),\n ...targetGAAreas.flatMap((area) => area.sectionId ? [area.sectionId] : []),\n ]);\n const categories = new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ]);\n const inViewport = (label: RenderedBookableLabelEvidence) => (\n label.screenCenter.x >= 0 && label.screenCenter.x <= evidence.viewport.width\n && label.screenCenter.y >= 0 && label.screenCenter.y <= evidence.viewport.height\n );\n findings.push(finding(\n 'detail-rung-missing',\n 'Interaction evidence with bookable inventory must render the seat-detail rung',\n detailInventory && evidence.rung !== 'seats'\n ? [{ primaryId: 'renderer', primaryLabel: evidence.rung }]\n : [],\n ));\n findings.push(finding(\n 'detail-inventory-not-visible',\n 'Interaction evidence must frame at least one real bookable unit',\n detailInventory && !targetLabels.some(inViewport) && !visibleTargetGA.length\n ? [{ primaryId: 'renderer', primaryLabel: 'no target inventory in viewport' }]\n : [],\n ));\n findings.push(finding(\n 'pointer-target-inactive',\n 'Interaction evidence must expose a live production pointer target',\n (labelledInventory && !activePointerTargets.some(inViewport))\n || (!labelledInventory && gaInventory && !visibleTargetGA.some((area) => area.interactive))\n ? [{ primaryId: 'renderer', primaryLabel: 'no active pointer target in viewport' }]\n : [],\n ));\n findings.push(finding(\n 'pointer-target-undersized',\n 'Every active production pointer target must reach at least 24 CSS pixels',\n activePointerTargets\n .filter((label) => inViewport(label) && label.pointerTarget.effectiveMinimumPx < MIN_POINTER_TARGET_PX)\n .map((label) => labelSample(label, label.pointerTarget.effectiveMinimumPx, MIN_POINTER_TARGET_PX)),\n ));\n findings.push(finding(\n 'selected-state-missing',\n 'Interaction evidence must paint a selected unit and its renderer-owned ring',\n labelledInventory && (!selected.length || !selected.some((label) => evidence.selectionRingSeatIds.includes(label.seatId)))\n ? [{ primaryId: 'renderer', primaryLabel: 'selected state' }]\n : [],\n ));\n findings.push(finding(\n 'selected-state-contrast-low',\n 'The selected-state ring must maintain 3:1 graphical contrast with the canvas',\n selected.length && (selectedRingContrast ?? 0) < MIN_GRAPHICAL_CONTRAST\n ? [{\n primaryId: selected[0].seatId,\n primaryLabel: selected[0].label,\n measured: Math.round((selectedRingContrast ?? 0) * 100) / 100,\n minimum: MIN_GRAPHICAL_CONTRAST,\n }]\n : [],\n ));\n findings.push(finding(\n 'held-state-missing',\n 'Interaction evidence must paint a held state when the floor has at least two status-managed units',\n targetLabels.length >= 2 && !held.length\n ? [{ primaryId: 'renderer', primaryLabel: 'held state' }]\n : [],\n ));\n findings.push(finding(\n 'booked-state-missing',\n 'Interaction evidence must paint a taken state when the floor has at least three status-managed units',\n targetLabels.length >= 3 && !booked.length\n ? [{ primaryId: 'renderer', primaryLabel: 'booked state' }]\n : [],\n ));\n const heldSignatures = new Set(held.map((label) => `${label.fill.toLowerCase()}:${label.opacity}`));\n const bookedSignatures = new Set(booked.map((label) => `${label.fill.toLowerCase()}:${label.opacity}`));\n findings.push(finding(\n 'status-state-indistinct',\n 'Held and taken evidence must resolve to distinct renderer paint',\n held.length && booked.length && [...heldSignatures].some((signature) => bookedSignatures.has(signature))\n ? [{ primaryId: held[0].seatId, primaryLabel: held[0].label, secondaryId: booked[0].seatId, secondaryLabel: booked[0].label }]\n : [],\n ));\n findings.push(finding(\n 'section-focus-missing',\n 'Interaction evidence must exercise section focus and its backdrop when section membership exists',\n sections.size && (!evidence.focusedSectionId || !evidence.focusBackdropVisible)\n ? [{ primaryId: 'renderer', primaryLabel: 'section focus' }]\n : [],\n ));\n findings.push(finding(\n 'category-filter-missing',\n 'Interaction evidence must exercise a category filter when multiple categories exist',\n categories.size >= 2 && (!evidence.categoryFilterKeys || !evidence.categoryFilterKeys.length)\n ? [{ primaryId: 'renderer', primaryLabel: 'category filter' }]\n : [],\n ));\n const excludedFree = evidence.labels.filter((label) => (\n label.status === 'free'\n && !label.selected\n && evidence.categoryFilterKeys != null\n && !evidence.categoryFilterKeys.includes(label.categoryKey)\n ));\n const excludedGA = evidence.gaAreas.filter((area) => (\n evidence.categoryFilterKeys != null\n && !evidence.categoryFilterKeys.includes(area.categoryKey)\n ));\n findings.push(finding(\n 'category-filter-ineffective',\n 'The active category filter must visibly dim excluded free inventory',\n (excludedFree.length || excludedGA.length)\n && !excludedFree.some((label) => label.opacity <= 0.25)\n && !excludedGA.some((area) => area.opacity <= 0.1)\n ? [\n ...excludedFree.map((label) => labelSample(label, label.opacity)),\n ...excludedGA.map((area) => ({ primaryId: area.areaId, primaryLabel: area.label, measured: area.opacity })),\n ]\n : [],\n ));\n findings.push(finding(\n 'target-category-not-visible',\n 'A category-specific interaction scene must visibly paint its exact target category',\n targetCategoryKey && !activeCategoryKeys.has(targetCategoryKey)\n ? [{ primaryId: targetCategoryKey, primaryLabel: targetCategoryKey }]\n : [],\n ));\n findings.push(finding(\n 'target-category-filter-mismatch',\n 'A category-specific interaction scene must bind its filter to only the exact target category',\n targetCategoryKey && (\n evidence.categoryFilterKeys?.length !== 1\n || evidence.categoryFilterKeys[0] !== targetCategoryKey\n )\n ? [{ primaryId: targetCategoryKey, primaryLabel: targetCategoryKey }]\n : [],\n ));\n }\n findings.push(finding(\n 'bookable-label-contrast-low',\n 'Visible bookable labels must meet 4.5:1 contrast against their actual paint',\n bookable.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.fill) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [labelSample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n\n const bookableCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < bookable.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(bookable[index].screenBox, bookable[other].screenBox)) {\n bookableCollisions.push(collisionSample(\n bookable[other].seatId, bookable[other].label,\n bookable[index].seatId, bookable[index].label,\n ));\n }\n }\n }\n findings.push(finding(\n 'bookable-label-collision',\n 'Visible bookable labels must not overlap',\n bookableCollisions,\n ));\n\n findings.push(finding(\n 'hierarchy-label-undersized',\n 'Visible section and zone labels must meet the rendered small-text size floor',\n hierarchy\n .filter((label) => label.renderedFontPx < MIN_VISIBLE_BOOKABLE_LABEL_PX)\n .map((label) => hierarchySample(label, label.renderedFontPx, MIN_VISIBLE_BOOKABLE_LABEL_PX)),\n ));\n findings.push(finding(\n 'hierarchy-label-contrast-low',\n 'Visible section and zone labels must meet 4.5:1 contrast against their backing paint',\n hierarchy.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.fill) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [hierarchySample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n findings.push(finding(\n 'hierarchy-label-outside-section',\n 'Visible section labels must remain inside the filled section surface and outside holes',\n hierarchy\n .filter((label) => label.kind === 'section' && label.fitsContainer === false)\n .map((label) => hierarchySample(label)),\n ));\n\n const hierarchyCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < hierarchy.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(hierarchy[index].screenBox, hierarchy[other].screenBox)) {\n hierarchyCollisions.push(collisionSample(\n hierarchy[other].id, hierarchy[other].label,\n hierarchy[index].id, hierarchy[index].label,\n ));\n }\n }\n }\n findings.push(finding(\n 'hierarchy-label-collision',\n 'Visible hierarchy labels must not overlap each other',\n hierarchyCollisions,\n ));\n\n const hierarchyBookableCollisions: RenderedQualitySample[] = [];\n for (const upper of hierarchy) {\n for (const unit of bookable) {\n if (intersects(upper.screenBox, unit.screenBox)) {\n hierarchyBookableCollisions.push(collisionSample(upper.id, upper.label, unit.seatId, unit.label));\n }\n }\n }\n findings.push(finding(\n 'hierarchy-bookable-collision',\n 'Visible hierarchy labels must not overlap bookable labels',\n hierarchyBookableCollisions,\n ));\n\n findings.push(finding(\n 'free-text-undersized',\n 'Visible chart text must meet the rendered small-text size floor',\n freeText\n .filter((label) => label.renderedFontPx < evidence.minimumVisibleLabelPx)\n .map((label) => freeTextSample(label, label.renderedFontPx, evidence.minimumVisibleLabelPx)),\n ));\n findings.push(finding(\n 'free-text-contrast-low',\n 'Visible chart text must meet 4.5:1 contrast against its measured background',\n freeText.flatMap((label) => {\n const ratio = renderedTextContrast(label.ink, label.background) ?? 0;\n return ratio < MIN_TEXT_CONTRAST ? [freeTextSample(label, ratio, MIN_TEXT_CONTRAST)] : [];\n }),\n ));\n\n const freeTextCollisions: RenderedQualitySample[] = [];\n for (let index = 0; index < freeText.length; index += 1) {\n for (let other = 0; other < index; other += 1) {\n if (intersects(freeText[index].screenBox, freeText[other].screenBox)) {\n freeTextCollisions.push(collisionSample(\n freeText[other].objectId, freeText[other].text,\n freeText[index].objectId, freeText[index].text,\n ));\n }\n }\n }\n findings.push(finding(\n 'free-text-collision',\n 'Visible chart text labels must not overlap each other',\n freeTextCollisions,\n ));\n\n const freeTextBookableCollisions: RenderedQualitySample[] = [];\n for (const text of freeText) {\n for (const unit of bookable) {\n if (intersects(text.screenBox, unit.screenBox)) {\n freeTextBookableCollisions.push(collisionSample(text.objectId, text.text, unit.seatId, unit.label));\n }\n }\n }\n findings.push(finding(\n 'free-text-bookable-collision',\n 'Visible chart text must not overlap bookable labels',\n freeTextBookableCollisions,\n ));\n\n const freeTextHierarchyCollisions: RenderedQualitySample[] = [];\n for (const text of freeText) {\n for (const upper of hierarchy) {\n if (intersects(text.screenBox, upper.screenBox)) {\n freeTextHierarchyCollisions.push(collisionSample(text.objectId, text.text, upper.id, upper.label));\n }\n }\n }\n findings.push(finding(\n 'free-text-hierarchy-collision',\n 'Visible chart text must not overlap hierarchy labels',\n freeTextHierarchyCollisions,\n ));\n\n findings.push(finding(\n 'ga-contrast-low',\n 'Visible GA surfaces must maintain 3:1 graphical contrast with the canvas',\n visibleGA.flatMap((area) => {\n const ratio = renderedTextContrast(area.effectiveBackground, evidence.canvasBackground) ?? 0;\n return ratio < MIN_GRAPHICAL_CONTRAST ? [{\n primaryId: area.areaId,\n primaryLabel: area.label,\n measured: Math.round(ratio * 100) / 100,\n minimum: MIN_GRAPHICAL_CONTRAST,\n }] : [];\n }),\n ));\n\n const materialFindings = findings.filter((item): item is RenderedQualityFinding => Boolean(item));\n return {\n version: RENDERED_QUALITY_REPORT_VERSION,\n passed: materialFindings.length === 0,\n state,\n targetCategoryKey,\n resolvedRules: [\n 'rendered-overview-label-size',\n 'rendered-overview-label-contrast',\n 'rendered-overview-label-collision',\n 'rendered-overview-hierarchy-containment',\n 'rendered-overview-section-first-style',\n 'rendered-overview-ga-contrast',\n ...(state === 'interaction' ? [\n 'rendered-detail-inventory',\n 'rendered-pointer-target',\n 'rendered-selected-held-taken-states',\n 'rendered-section-focus',\n 'rendered-category-filter',\n ] : []),\n ],\n viewport: evidence.viewport,\n canvasBackground: evidence.canvasBackground,\n effectiveScale: evidence.effectiveScale,\n rung: evidence.rung,\n inventory: {\n totalBookableUnits: evidence.totalBookableUnits,\n totalLabelledBookableUnits: evidence.totalLabelledBookableUnits,\n visibleBookableLabels: bookable.length,\n hiddenBookableLabels: evidence.hiddenLabels,\n visibleHierarchyLabels: hierarchy.length,\n visibleFreeTextLabels: freeText.length,\n visibleGAAreas: visibleGA.length,\n },\n overviewStyle: evidence.overviewStyle,\n composition: {\n hierarchy: evidence.hierarchyLabels\n .filter((label) => label.role === 'name')\n .map((label) => ({\n id: label.id,\n kind: label.kind,\n label: label.label,\n visible: label.visible,\n }))\n .sort((left, right) => left.kind.localeCompare(right.kind) || left.id.localeCompare(right.id)),\n labelledObjects: evidence.freeTextLabels\n .map((label) => ({\n objectId: label.objectId,\n kind: label.kind,\n text: label.text,\n visible: label.visible,\n }))\n .sort((left, right) => left.objectId.localeCompare(right.objectId) || left.kind.localeCompare(right.kind)),\n gaAreas: evidence.gaAreas\n .map((area) => ({\n areaId: area.areaId,\n label: area.label,\n categoryKey: area.categoryKey,\n ...(area.sectionId ? { sectionId: area.sectionId } : {}),\n visible: area.visible,\n }))\n .sort((left, right) => left.areaId.localeCompare(right.areaId)),\n bookableSectionIds: [...new Set(evidence.labels.flatMap((label) => label.sectionId ? [label.sectionId] : []))].sort(),\n categoryKeys: [...new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ])].sort(),\n activeCategoryKeys: [...activeCategoryKeys].sort(),\n },\n metrics: {\n minimumRenderedBookableLabelPx: minimum(bookable.map((label) => label.renderedFontPx)),\n minimumBookableLabelContrast: minimum(bookableContrast),\n minimumRenderedHierarchyLabelPx: minimum(hierarchy.map((label) => label.renderedFontPx)),\n minimumHierarchyLabelContrast: minimum(hierarchyContrast),\n minimumRenderedFreeTextPx: minimum(freeText.map((label) => label.renderedFontPx)),\n minimumFreeTextContrast: minimum(freeTextContrast),\n minimumGAContrast: minimum(gaContrast),\n minimumEffectivePointerTargetPx: minimum(activePointerTargets.map((label) => label.pointerTarget.effectiveMinimumPx)),\n selectedRingContrast: selectedRingContrast == null ? null : Math.round(selectedRingContrast * 100) / 100,\n },\n interaction: {\n applicable: {\n detail: targetLabels.length > 0 || targetGAAreas.length > 0,\n pointer: targetLabels.length > 0 || targetGAAreas.length > 0,\n held: targetLabels.length >= 2,\n booked: targetLabels.length >= 3,\n sectionFocus: targetLabels.some((label) => Boolean(label.sectionId))\n || targetGAAreas.some((area) => Boolean(area.sectionId)),\n categoryFilter: new Set([\n ...evidence.labels.map((label) => label.categoryKey),\n ...evidence.gaAreas.map((area) => area.categoryKey),\n ]).size >= 2,\n },\n selectedUnits: selected.length,\n heldUnits: held.length,\n bookedUnits: booked.length,\n activePointerTargets: activePointerTargets.length,\n focusedSectionId: evidence.focusedSectionId,\n focusBackdropVisible: evidence.focusBackdropVisible,\n categoryFilterKeys: evidence.categoryFilterKeys,\n },\n findings: materialFindings,\n };\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 { Arrow } from 'konva/lib/shapes/Arrow';\nimport { Text } from 'konva/lib/shapes/Text';\nimport { Path } from 'konva/lib/shapes/Path';\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 RendererViewMode,\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 { distanceToRings, polygonNetArea } from '../core/polygonAnchor';\nimport { buyerBackgroundImage } from '../core/chartBackgrounds';\nimport { venueIconPath, VENUE_ICON_VIEWBOX, VENUE_ICON_STROKE } from '../core/icons';\nimport { sectionGeometry } from '../core/sections';\nimport { buildSeatIndex, queryRect, type SeatIndex } from '../core/spatialIndex';\nimport { CHART_UNITS_PER_METRE, SEATED_EYE_HEIGHT_M, sectionElevationTier } from '../core/units';\nimport {\n applyAffine,\n composeAffine,\n createPerspectiveCamera,\n decomposeAffineLinear,\n invertAffine,\n perspectiveTangentAffine,\n projectPerspectivePoint,\n type Affine2D,\n type PerspectiveCamera,\n} from '../core/perspectiveProjection';\nimport {\n ACCESS_GLYPH_VIEWBOX,\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 accessGlyphInk,\n accessGlyphPath,\n bookableMarkerLabel,\n compositeHexOver,\n isBookableLabelLegibleAtScale,\n AUTHORED_LABEL_MIN_CONTRAST,\n stateAwareBookableLabelInk,\n} from '../core/chartRenderRules';\nimport { t } from '../i18n';\nimport { formatMoney } from '../lib/money';\nimport { resolvedShapeLineStyle, shapeArrowMetrics } from '../core/shapeLineStyle';\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/** Wheelchair provision remains identifiable in the normal All-seats view. */\nconst WHEELCHAIR_GLYPH_MIN_PX = 10;\n/**\n * Minimum screen-space size of the wheelchair glyph while the buyer is\n * explicitly filtering for wheelchair provision. At venue-fit LOD a normal\n * seat can be only a couple of pixels wide; keeping the selected filter's\n * semantic marker at a stable size makes the result recognizable without\n * changing the seat's inventory silhouette or hit target.\n */\nconst FILTERED_WHEELCHAIR_GLYPH_MIN_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/** Window after a `tap` in which a `click` is the browser's ghost, not a real\n * mouse click. 700ms covers the legacy 300ms click delay with margin; mouse\n * and pen paths never set the timestamp, so they are unaffected. */\nconst GHOST_CLICK_MS = 700;\n/** World-space padding kept between an automatic row label and nearby ink. */\nconst ROW_LABEL_CLEARANCE = 2;\n/** Cell size for the tiny row/free-text collision index. Row labels are\n * normally 10–40 chart units wide, so 64 keeps each query to a few entries. */\nconst ROW_LABEL_COLLISION_CELL = 64;\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/** 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 shaded by four bounded availability\n * states (normal / nearly-gone / sold-out / closed) — never a continuous\n * price-or-demand heatmap ramp. See overviewStateFill / SectionAvailabilityState. */\nconst BLOCK_FILL_ALPHA = 1;\n/**\n * Section outlines are drawn TWICE — the colour-tinted outline underneath and\n * the neutral overview shell on top — so the border an author sees is the sum\n * of both. At 2px each that reads as a heavy double rule, and on a traced plan\n * whose sections now abut along a deliberate 2px gutter it swallows the gutter\n * entirely: neighbours look welded together rather than separated.\n *\n * One screen pixel per stroke keeps the boundary crisp at every zoom without\n * competing with the gap itself for the author's attention.\n */\nconst SECTION_STROKE_PX = 1;\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;\n/** Successive shrinks tried on a colliding section name before it is hidden. */\nconst SECTION_LABEL_SHRINK_STEPS = [0.85, 0.72, 0.62] as const;\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 bind to these by their stable KEY (sorted), never doc order, so\n * reordering categories never re-shuffles seat hues (OV-46). */\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';\n\n/** Konva `fontStyle` string from bold/italic flags (mirrors the designer). */\nfunction konvaFontStyle(bold?: boolean, italic?: boolean, defaultWeight = 'normal'): string {\n const weight = bold ? 'bold' : defaultWeight;\n return italic ? `italic ${weight}`.trim() : weight;\n}\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\ninterface WorldBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface RowLabelPlanEntry {\n text: string;\n x: number;\n y: number;\n rotation: number;\n fontSize: number;\n ink: string;\n opacity: number;\n /** Absent for a free-drag position, which must remain pixel-faithful. */\n automaticAway?: Point;\n}\n\nfunction worldBoxesOverlap(a: WorldBox, b: WorldBox): boolean {\n return a.x < b.x + b.width && b.x < a.x + a.width\n && a.y < b.y + b.height && b.y < a.y + a.height;\n}\n\n/** Small deterministic grid used only while rebuilding viewport labels. */\nclass WorldBoxIndex {\n private cells = new Map<string, WorldBox[]>();\n\n insert(box: WorldBox): void {\n for (const key of this.keys(box)) {\n const bucket = this.cells.get(key);\n if (bucket) bucket.push(box);\n else this.cells.set(key, [box]);\n }\n }\n\n collisionCount(box: WorldBox): number {\n const seen = new Set<WorldBox>();\n let count = 0;\n for (const key of this.keys(box)) {\n for (const existing of this.cells.get(key) ?? []) {\n if (seen.has(existing)) continue;\n seen.add(existing);\n if (worldBoxesOverlap(box, existing)) count++;\n }\n }\n return count;\n }\n\n private keys(box: WorldBox): string[] {\n const x0 = Math.floor(box.x / ROW_LABEL_COLLISION_CELL);\n const x1 = Math.floor((box.x + Math.max(0, box.width)) / ROW_LABEL_COLLISION_CELL);\n const y0 = Math.floor(box.y / ROW_LABEL_COLLISION_CELL);\n const y1 = Math.floor((box.y + Math.max(0, box.height)) / ROW_LABEL_COLLISION_CELL);\n const keys: string[] = [];\n for (let y = y0; y <= y1; y++) {\n for (let x = x0; x <= x1; x++) keys.push(`${x}:${y}`);\n }\n return keys;\n }\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\n/**\n * Bounded availability states an overview section shell can read (OV-69). This is\n * a four-bucket semantic ladder, deliberately NOT a continuous demand heatmap:\n * • normal — shown in the neutral shell fill.\n * • nearly-gone — >0 but ≤10% of the section's seats free: one desaturated step.\n * • sold-out — 0 seats free: a muted, flatter fill that reads unavailable.\n * • closed — operator turned the section off: its own darker slab (kept).\n * `closed` outranks the live-availability buckets — an operator close is authoritative.\n */\ntype SectionAvailabilityState = 'normal' | 'nearly-gone' | 'sold-out' | 'closed';\n\n/** Section is nearly gone once free seats drop to this fraction of its capacity. */\nconst SECTION_NEARLY_GONE_RATIO = 0.1;\n\n/** The one source of truth for a section shell's fill per availability state.\n * Both the live paint and the overview evidence set read from here, so the\n * \"clean shell never leaks category paint\" check treats these semantic fills as\n * legitimate (not category leakage). */\nfunction overviewStateFill(palette: OverviewPalette, state: SectionAvailabilityState): string {\n const base = palette.sectionFill;\n // Sold-out: drop lightness a notch then drain the cool cast so it reads as a\n // dead, muted block — distinct from the operator-closed darker-but-tinted slab.\n const soldOut = desaturate(darken(base, 0.2), 0.85);\n switch (state) {\n case 'closed':\n return darken(base, 0.12);\n case 'sold-out':\n return soldOut;\n case 'nearly-gone':\n // One measured step toward sold-out — never a smooth per-seat ramp.\n return lerpColor(base, soldOut, 0.4);\n case 'normal':\n default:\n return base;\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/** Mix a #rrggbb colour toward its own perceptual grey by `amt` (0..1) —\n * drains saturation without changing brightness, for the muted \"sold-out\" look. */\nfunction desaturate(hex: string, amt: number): string {\n const rgb = hexToRgb(hex);\n if (!rgb) return hex;\n const [r, g, b] = rgb;\n const grey = 0.299 * r + 0.587 * g + 0.114 * b;\n return toHex(r + (grey - r) * amt, g + (grey - g) * amt, b + (grey - b) * amt);\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/**\n * Interior anchors to try when fitting a section name, fattest first.\n *\n * `preferred` is the polygon's pole of inaccessibility, so it leads. The grid\n * fallbacks used to be ordered by distance to the bounding-box centre, which on\n * a concave shell ranks points by where the *box* middle is rather than by how\n * much room they have — the fitter then walked down font sizes at cramped\n * anchors before reaching a roomy one. Ordering by clearance from every ring\n * means the first anchor tried is always the one most likely to hold the label.\n */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\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 const rings = [outer, ...holes];\n return points\n .map((point) => ({ point, room: distanceToRings(point, rings) }))\n .sort((left, right) => right.room - left.room)\n .map((entry) => entry.point)\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\n/** Trace a closed polygon with rounded corners (radius clamped per corner to\n * half the shorter adjacent edge). Mirrors the designer's corner-smoothing so\n * the buyer map matches the authored GA shape (OV-66). */\nfunction roundedPolygonSubpath(\n context: { moveTo(x: number, y: number): void; arcTo(x1: number, y1: number, x2: number, y2: number, r: number): void; closePath(): void },\n points: Point[],\n radius: number,\n): void {\n const n = points.length;\n const start = { x: (points[n - 1].x + points[0].x) / 2, y: (points[n - 1].y + points[0].y) / 2 };\n context.moveTo(start.x, start.y);\n for (let i = 0; i < n; i += 1) {\n const curr = points[i];\n const next = points[(i + 1) % n];\n const prev = points[(i - 1 + n) % n];\n const rMax = Math.min(\n Math.hypot(curr.x - prev.x, curr.y - prev.y) / 2,\n Math.hypot(next.x - curr.x, next.y - curr.y) / 2,\n );\n context.arcTo(curr.x, curr.y, next.x, next.y, Math.max(0, Math.min(radius, rMax)));\n }\n context.closePath();\n}\n\nfunction polygonWithHolesShape(\n outer: Point[],\n holes: Point[][] | undefined,\n attrs: { fill?: string; stroke?: string; strokeWidth?: number; opacity?: number; listening?: boolean; cornerRadius?: number },\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 const cornerRadius = attrs.cornerRadius && attrs.cornerRadius > 0 ? attrs.cornerRadius : 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 if (cornerRadius > 0 && points.length >= 3) return roundedPolygonSubpath(context, points, cornerRadius);\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/** A section container that can be omitted from scene + hit paints without\n * toggling Konva's public `visible` attribute. `visible(false)` recursively\n * invalidates every descendant's absolute-visibility cache — exactly the O(N)\n * cliff viewport culling is meant to avoid on a 14k-seat chart. */\nclass ViewportGroup extends Group {\n private viewportCulled = false;\n\n setViewportCulled(culled: boolean): void {\n if (culled === this.viewportCulled) return;\n this.viewportCulled = culled;\n // Descendants may have cached absolute transforms from before an offscreen\n // camera move. Clear them once when the section re-enters, not on every\n // frame while it remains outside the viewport.\n if (!culled) super._clearSelfAndDescendantCache();\n }\n\n isViewportCulled(): boolean {\n return this.viewportCulled;\n }\n\n override drawScene(...args: Parameters<Group['drawScene']>): this {\n return this.viewportCulled ? this : super.drawScene(...args);\n }\n\n override drawHit(...args: Parameters<Group['drawHit']>): this {\n return this.viewportCulled ? this : super.drawHit(...args);\n }\n\n override _clearSelfAndDescendantCache(attr?: string): void {\n if (!this.viewportCulled) {\n super._clearSelfAndDescendantCache(attr);\n return;\n }\n // The group itself must follow its parent camera, but culled children are\n // neither drawn nor hit-tested. Their caches are refreshed on re-entry.\n this._clearCache(attr);\n }\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 roomiest-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n /** Net shell area — the de-collision tiebreak, so big stands keep their name. */\n labelArea: number;\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 * Resolved iso lift in world units = `sectionGeometry(section).height ×\n * CHART_UNITS_PER_METRE` (Phase B1). Uses the section's authored real height when\n * present, else the legacy `elevation × TIER_HEIGHT_M` fallback — which equals the\n * old `elevation × LIFT_PER_STEP`, so un-authored charts stay pixel-identical.\n * Computed once at build time; never per frame.\n */\n liftWorld: number;\n /** Authored section rake used by the Phase-C tangent surface. */\n rakeDeg: number;\n /** Focal point that defines front→back depth for this physical surface. */\n surfaceFocal: Point;\n /** Nearest member/outline distance to the focal point, in chart units. */\n frontDistanceWorld: number;\n /** Desired projected tangent plane, built only while perspective is active. */\n perspectiveAffine?: Affine2D;\n /** Child correction after the shared ground-plane affine. */\n perspectiveCorrection?: Affine2D;\n /** Camera depth used to order far sections before near sections. */\n perspectiveDepth?: number;\n /** Section-owned background root: side faces + top-surface child group. */\n rootGroupBg: Group;\n /** Original sibling order restored when leaving perspective. */\n bgZIndex: number;\n seatZIndex: number;\n /** Elevated background container; null for a flat section. */\n liftGroupBg: Group;\n /**\n * Every section owns one seat group. Besides making elevation one group\n * transform, this is the production viewport-culling boundary: offscreen\n * sections do not make Konva repaint thousands of invisible seats while a\n * buyer pans or zooms a focused part of a large venue.\n */\n liftGroupSeat: ViewportGroup;\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 private readonly exportMode: boolean;\n\n private stage: Stage;\n private bgLayer: Layer;\n private seatLayer: Layer;\n private overlayLayer: Layer;\n private labelGroup: Group;\n /** Per-elevated-section label containers. Keeping the labels grouped lets the\n * Phase-B lift move thousands of seat labels with one transform per section\n * instead of rewriting every label on every tween frame. */\n private labelLiftGroups = new Map<string, ViewportGroup>();\n /** Foreground decor images — drawn on the overlay layer, ABOVE the seats. */\n private fgDecorGroup: Group;\n\n private seats: ExpandedSeat[] = [];\n private seatById = new Map<string, ExpandedSeat>();\n /** One build per chart/floor; section membership queries only inspect seats in\n * the section bounds instead of rescanning the full 13k venue per section. */\n private seatIndex: SeatIndex | null = null;\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; points?: Point[] }>();\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 /** Coloured accommodation ring per accessible seat (few per chart). */\n private accessRingById = new Map<string, Circle>();\n /** Centred ♿ glyph per physical wheelchair provision. It keeps a small\n * screen-space floor at every LOD and grows when the Wheelchair filter is\n * active. Kept in a map so zoom updates touch only the handful of matching\n * seats, never all 13k nodes. */\n private accessGlyphById = new Map<string, Path>();\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 backdrop?: Rect;\n background: string;\n kind: RenderedFreeTextEvidence['kind'];\n categoryKey?: string;\n }>();\n /** Vector venue-icon Path nodes + authored size; obey the free-text size floor. */\n private iconNodeById = new Map<string, { node: Path; fontSize: number }>();\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 /** Stable per-category-KEY colorblind hue (OV-46) — order-independent. */\n private cbHueByKey = new Map<string, string>();\n /** OV-45(a): authored row-letter labels for the buyer/preview map, resolved in\n * world space (matching seat labels) and honouring each row's labelPresentation\n * (position/rotation/visibility/style). Painted at the seats LOD rung. */\n private rowLabelPlan: RowLabelPlanEntry[] = [];\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 /** Seat-contained 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 /** Seat currently owning the shared hover ring (null while not hovering). */\n private hoveredId: string | null = null;\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 /** Seats outside every authored section retain the legacy path in one group. */\n private unsectionedSeatGroup: Group | null = null;\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 /** Non-listening visual dim outside the focused section. One overlay replaces\n * descendant opacity mutations across every seat in the venue. */\n private focusDimOverlay: Shape | 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 /** Public view target; perspective is a separate non-affine Phase-C lane. */\n private viewMode: RendererViewMode = 'flat';\n private perspectiveCamera: PerspectiveCamera | null = null;\n /** Ground-plane tangent applied once to every renderer layer. */\n private perspectiveBaseAffine: Affine2D | null = null;\n private perspectiveBaseInverse: Affine2D | null = null;\n /** Exact pinhole anchor expressed in the overlay tangent-layer coordinates. */\n private perspectiveSeatLocal = new Map<string, Point>();\n /** Exact projected point (before Stage pan/zoom), keyed by seat. */\n private perspectiveSeatProjected = new Map<string, Point>();\n /** Positive camera depth, used for deterministic far→near paint order. */\n private perspectiveSeatDepth = new Map<string, number>();\n /** Exact pinhole size ratio at each seat anchor. */\n private perspectiveSeatScale = new Map<string, number>();\n /** Seats whose native Konva nodes currently carry the exact projected pose.\n * Large sectioned venues apply these lazily as a section enters the live-seat\n * viewport; the overview rung hides the seat layer completely. */\n private perspectiveAppliedSeats = new Set<string>();\n private perspectiveBounds: { x: number; y: number; width: number; height: number } | null = null;\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 /** While the camera tween is active, defer polygon label fitting/collision to\n * the settled frame. Geometry remains smoothly stage-scaled, while expensive\n * point-in-polygon text work no longer repeats at 120 Hz. */\n private glideInProgress = false;\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 /** Current chart's buyer-visible image work. Failures are retained until ready(). */\n private assetGeneration = 0;\n private assetPromises: Promise<void>[] = [];\n private assetErrors: string[] = [];\n private assetCancels = new Set<() => void>();\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 * Ghost-click guard. Konva binds `_pointerup` to mouseup, touchend AND\n * pointerup, so `on('click tap')` is two handlers for one finger tap unless\n * the browser's synthesized compatibility click is suppressed. Konva only\n * suppresses it when the touch lands on a LISTENING SHAPE (Stage.js returns\n * early before its preventDefault() when `!shape || !shape.isListening()`),\n * so a near-miss rescued by nearestSeatToScreen used to fire `tap` (select)\n * then `click` (deselect) 1-3ms apart and net to nothing. With\n * SEAT_TAP_SLOP_PX=14 against a ~12px seat radius, that broken annulus is\n * ~3.7x the area of the seat itself — i.e. most successful mobile taps.\n * `touch-action: none` does NOT suppress compatibility mouse events.\n */\n private lastTapAt = 0;\n\n /**\n * True when this is the browser's synthesized compatibility click following a\n * finger tap we already handled. Discriminates on `e.type` deliberately —\n * `PointerEvent extends MouseEvent`, so an `instanceof MouseEvent` test\n * matches genuine pointer taps too. One shared timestamp across the layer and\n * stage handlers: a tap consumed at the layer must also suppress the ghost at\n * the stage, and only `click` is ever rejected, so bubbling stays intact.\n */\n private isGhostClick(e: KonvaEventObject<Event>): boolean {\n if (e.type === 'tap') { this.lastTapAt = performance.now(); return false; }\n return this.lastTapAt > 0 && performance.now() - this.lastTapAt < GHOST_CLICK_MS;\n }\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.exportMode = options.exportMode === true;\n this.currency = options.currency;\n\n const previousPixelRatio = Konva.pixelRatio;\n if (this.exportMode) this.dpr = 1;\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 if (!this.exportMode) {\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\n this.bgLayer = new Layer({ listening: !this.exportMode });\n this.seatLayer = new Layer({ listening: !this.exportMode });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n // Foreground decor sits above seats but below the hover/focus rings.\n this.fgDecorGroup = new Group({ listening: false });\n this.overlayLayer.add(this.fgDecorGroup);\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 // Export canvases intentionally use one physical pixel per stage pixel.\n // Restore the shared Konva default immediately so a live renderer created\n // while this exporter exists still receives its ordinary device ratio.\n if (this.exportMode) Konva.pixelRatio = previousPixelRatio;\n\n if (!this.exportMode) {\n this.wireInteraction();\n this.startFpsLoop();\n }\n\n if (import.meta.env.DEV && !this.exportMode) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (!this.exportMode && 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.cancelAssetLoads();\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.focusDimOverlay?.destroy();\n this.focusDimOverlay = null;\n // A prior overview may have left the layer bitmap-cached and non-listening.\n // A floor/chart replacement is a fresh live scene: clear both pieces of\n // cache state before adding its seats so direct Konva picking is truthful.\n this.seatLayer.clearCache();\n this.seatLayer.listening(!this.exportMode);\n this.seatLayer.destroyChildren();\n this.unsectionedSeatGroup = null;\n this.labelGroup.destroyChildren();\n this.labelLiftGroups.clear();\n this.fgDecorGroup.destroyChildren();\n this.circleById.clear();\n this.boothDims.clear();\n this.boothLabelById.clear();\n this.seatLabelById.clear();\n this.accessRingById.clear();\n this.accessGlyphById.clear();\n this.freeTextById.clear();\n this.iconNodeById.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.seatIndex = null;\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.viewMode = 'flat';\n this.perspectiveCamera = null;\n this.perspectiveBaseAffine = null;\n this.perspectiveBaseInverse = null;\n this.perspectiveSeatLocal.clear();\n this.perspectiveSeatProjected.clear();\n this.perspectiveSeatDepth.clear();\n this.perspectiveSeatScale.clear();\n this.perspectiveAppliedSeats.clear();\n this.perspectiveBounds = null;\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 this.hoveredId = null;\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 // OV-46: colorblind-safe hues bind to a category's stable KEY (deterministic\n // sorted order), never its position. Reordering categories (buyer legend\n // priority) must never re-shuffle which seat shows which hue.\n this.cbHueByKey.clear();\n [...this.catOrder].sort().forEach((key, i) => {\n this.cbHueByKey.set(key, CB_PALETTE[i % CB_PALETTE.length]);\n });\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, {\n width: obj.width, height: obj.height, rotation: obj.rotation,\n ...(obj.points && obj.points.length >= 3 ? { points: obj.points.map((p) => ({ x: p.x, y: p.y })) } : {}),\n });\n }\n }\n\n this.seats = expandChart(view, {\n // A stacked overview is presentation-only and never opens a seat POV. The\n // per-section renderer below still resolves each object's real floor base.\n floorBaseHeightM: this.stacked ? 0 : this.floorBaseHeightMFor(),\n });\n for (const s of this.seats) {\n this.seatById.set(s.id, s);\n this.statusById.set(s.id, 'free');\n }\n this.seatIndex = buildSeatIndex(this.seats, { seatRadius: this.seatR });\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 // Phase C projection is precomputed once per chart/floor. Entering the view\n // only moves existing Konva hit shapes to these exact anchors; pan/zoom never\n // recomputes pinhole geometry.\n this.buildPerspectiveProjection(view);\n\n this.renderBackground(view);\n // Rows/booths outside an authored section retain one always-visible legacy\n // container. Every section has its own group (created by renderSection), so\n // large venues can omit only whole, safely offscreen sections from paints.\n this.unsectionedSeatGroup = new Group({ listening: !this.exportMode });\n this.seatLayer.add(this.unsectionedSeatGroup);\n this.renderSeats();\n this.buildRowLabelPlan(view);\n // re-add overlay furniture wiped by destroyChildren above (order sets z:\n // labels + foreground decor sit under the hover/focus rings).\n this.overlayLayer.add(this.labelGroup);\n this.overlayLayer.add(this.fgDecorGroup);\n this.overlayLayer.add(this.hoverRing);\n this.overlayLayer.add(this.focusRing);\n\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 {\n ...doc,\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(doc),\n };\n if (this.stacked && doc.floors.length >= 2) {\n return {\n ...stackFloors(doc),\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(doc),\n };\n }\n const floor = doc.floors.find((f) => f.id === this.activeFloorId) ?? doc.floors[0];\n return {\n ...doc,\n objects: floor.objects,\n focalPoint: floor.focalPoint,\n referenceImage: undefined,\n backgroundImage: buyerBackgroundImage(floor),\n floors: undefined,\n };\n }\n\n /** Physical floor height is authored data; the 900-unit stacked overview\n * spread is presentation-only and must never leak into real 3D geometry. */\n private floorBaseHeightMFor(objectId?: string): number {\n const floors = this.chartDoc?.floors;\n if (!floors?.length) return 0;\n const floorId = this.stacked && objectId\n ? this.objectFloor.get(objectId) ?? this.activeFloorId\n : this.activeFloorId;\n return floors.find((floor) => floor.id === floorId)?.baseHeightM ?? 0;\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 const rendered = this.renderedSeatPoint(seat);\n if (rendered.x < x0 || rendered.x > x1 || rendered.y < y0 || rendered.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 rendered = this.renderedSeatPoint(seat);\n const ring = new Circle({\n x: rendered.x,\n y: rendered.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 const projectionScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seatId) ?? 1\n : 1;\n ring.scale({ x: projectionScale, y: projectionScale });\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 outline = this.viewMode === 'perspective' && section.perspectiveAffine\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline.map((point) => {\n const lift = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n return { x: point.x + lift.x, y: point.y + lift.y };\n });\n const centre = outline.reduce(\n (sum, point) => ({ x: sum.x + point.x, y: sum.y + point.y }),\n { x: 0, y: 0 },\n );\n centre.x /= outline.length;\n centre.y /= outline.length;\n const halo = new Line({\n x: centre.x,\n y: centre.y,\n points: 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 const fromPoint = this.viewMode === 'perspective'\n ? this.perspectiveSeatProjected.get(from.id) ?? from\n : from;\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 candidatePoint = this.viewMode === 'perspective'\n ? this.perspectiveSeatProjected.get(s.id) ?? s\n : s;\n const dx = candidatePoint.x - fromPoint.x;\n const dy = candidatePoint.y - fromPoint.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(this.renderedSeatPoint(seat));\n const projectionScale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(id) ?? 1 : 1;\n this.focusRing.scale({ x: projectionScale, y: projectionScale });\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 rendered = this.renderedSeatPoint(seat);\n const ip = this.viewMode === 'perspective' && this.perspectiveBaseAffine\n ? applyAffine(this.perspectiveBaseAffine, rendered)\n : this.isoT === 0 ? rendered : this.isoForward(rendered);\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.viewMode === 'perspective' && this.perspectiveBounds\n ? this.perspectiveBounds\n : 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 // Picker hosts pass the ExpandedSeat object they received from callbacks.\n // Recognise that richer runtime shape so elevated-seat popovers anchor to\n // the painted seat rather than its pre-lift authoring coordinate. Plain\n // chart points retain the public Point contract and remain unchanged.\n const candidateId = (point as Partial<ExpandedSeat>).id;\n const seat = typeof candidateId === 'string' ? this.seatById.get(candidateId) : undefined;\n if (this.viewMode === 'perspective' && this.perspectiveBaseAffine) {\n const projected = seat\n ? this.perspectiveSeatProjected.get(seat.id) ?? applyAffine(this.perspectiveBaseAffine, point)\n : applyAffine(this.perspectiveBaseAffine, point);\n return { x: projected.x * s + this.stage.x(), y: projected.y * s + this.stage.y() };\n }\n const localPoint = seat ? this.renderedSeatPoint(seat) : point;\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 ? localPoint : this.isoForward(localPoint);\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 // A wheelchair filter can promote its matching glyphs above the normal\n // camera-size threshold, so recompute their visibility and screen-size\n // before repainting opacity for matching/nonmatching seats.\n this.updateAccessGlyphs(this.effScale());\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 // The overview is a bitmap; rebuild it so filter dimming and the promoted\n // wheelchair glyph are visible immediately instead of only after zoom.\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 = !this.exportMode\n && ga.sectionId != null\n && 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(!this.exportMode && !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 const point = this.renderedSeatPoint(seat);\n minX = Math.min(minX, point.x);\n maxX = Math.max(maxX, point.x);\n minY = Math.min(minY, point.y);\n maxY = Math.max(maxY, point.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: RendererViewMode): void {\n if (mode === 'perspective') {\n if (this.viewMode === mode) {\n this.afterViewChange();\n return;\n }\n const resetElevatedSeatGroups = this.viewMode === 'isometric' && this.isoT > 0;\n this.viewMode = mode;\n this.isoTarget = 1;\n this.isoT = 1;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n this.applyPerspective(resetElevatedSeatGroups);\n this.zoomToFit();\n return;\n }\n\n const target = mode === 'isometric' ? 1 : 0;\n const leavingPerspective = this.viewMode === 'perspective';\n this.viewMode = mode;\n this.isoTarget = target;\n if (this.isoRaf) { cancelAnimationFrame(this.isoRaf); this.isoRaf = 0; }\n if (leavingPerspective) {\n // A non-affine view cannot meaningfully tween through the old affine lean.\n // Snap to the requested endpoint (also the reduced-motion behaviour), then\n // let future flat⇄iso switches use the established 320-ms animation.\n this.isoT = target;\n this.applyIso();\n this.afterViewChange();\n return;\n }\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(): RendererViewMode {\n return this.viewMode;\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 if (this.viewMode === 'perspective' && this.perspectiveBaseAffine) {\n const xScale = Math.hypot(this.perspectiveBaseAffine.a, this.perspectiveBaseAffine.b);\n const yScale = Math.hypot(this.perspectiveBaseAffine.c, this.perspectiveBaseAffine.d);\n return this.stage.scaleX() * Math.min(xScale, yScale);\n }\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 /** Precompute the Phase-C pinhole camera and every exact seat anchor. */\n private buildPerspectiveProjection(view: ChartDoc): void {\n let maxSurfaceHeightWorld = 0;\n for (const seat of this.seats) {\n const surfaceM = Math.max(0, (seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - SEATED_EYE_HEIGHT_M);\n maxSurfaceHeightWorld = Math.max(maxSurfaceHeightWorld, surfaceM * CHART_UNITS_PER_METRE);\n }\n for (const object of view.objects) {\n if (object.type !== 'section') continue;\n maxSurfaceHeightWorld = Math.max(\n maxSurfaceHeightWorld,\n sectionGeometry(object, { floorBaseHeightM: this.floorBaseHeightMFor(object.id) }).height\n * CHART_UNITS_PER_METRE,\n );\n }\n const camera = createPerspectiveCamera(this.bounds, maxSurfaceHeightWorld);\n const base = perspectiveTangentAffine(camera, camera.target);\n const inverse = invertAffine(base);\n this.perspectiveCamera = camera;\n this.perspectiveBaseAffine = base;\n this.perspectiveBaseInverse = inverse;\n this.perspectiveSeatLocal.clear();\n this.perspectiveSeatProjected.clear();\n this.perspectiveSeatDepth.clear();\n this.perspectiveSeatScale.clear();\n this.perspectiveBounds = null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const seat of this.seats) {\n const surfaceM = Math.max(0, (seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - SEATED_EYE_HEIGHT_M);\n const projected = projectPerspectivePoint(camera, seat, surfaceM * CHART_UNITS_PER_METRE);\n const point = { x: projected.x, y: projected.y };\n this.perspectiveSeatProjected.set(seat.id, point);\n this.perspectiveSeatLocal.set(seat.id, applyAffine(inverse, point));\n this.perspectiveSeatDepth.set(seat.id, projected.depth);\n this.perspectiveSeatScale.set(seat.id, projected.scale);\n minX = Math.min(minX, projected.x);\n minY = Math.min(minY, projected.y);\n maxX = Math.max(maxX, projected.x);\n maxY = Math.max(maxY, projected.y);\n }\n for (const point of [\n { x: this.bounds.x, y: this.bounds.y },\n { x: this.bounds.x + this.bounds.width, y: this.bounds.y },\n { x: this.bounds.x + this.bounds.width, y: this.bounds.y + this.bounds.height },\n { x: this.bounds.x, y: this.bounds.y + this.bounds.height },\n ]) {\n const projected = projectPerspectivePoint(camera, point, 0);\n minX = Math.min(minX, projected.x);\n minY = Math.min(minY, projected.y);\n maxX = Math.max(maxX, projected.x);\n maxY = Math.max(maxY, projected.y);\n }\n const pad = Math.max(24, this.seatR * 3);\n this.perspectiveBounds = Number.isFinite(minX)\n ? { x: minX - pad, y: minY - pad, width: Math.max(1, maxX - minX + pad * 2), height: Math.max(1, maxY - minY + pad * 2) }\n : null;\n }\n\n /** Apply an affine to a Konva container while keeping `pivot` fixed logically. */\n private setContainerAffine(node: Group | Layer, affine: Affine2D, pivot: Point): void {\n const decomposed = decomposeAffineLinear(affine);\n node.offset(pivot);\n node.position(applyAffine(affine, pivot));\n node.rotation(decomposed.rotationDeg);\n node.scale({ x: decomposed.scaleX, y: decomposed.scaleY });\n node.skewX(decomposed.skewX);\n node.skewY(0);\n }\n\n private resetContainerTransform(node: Group | Layer): void {\n node.position({ x: 0, y: 0 });\n node.offset({ x: 0, y: 0 });\n node.scale({ x: 1, y: 1 });\n node.rotation(0);\n node.skewX(0);\n node.skewY(0);\n }\n\n /** Exact raked surface height used for the bounded section tangent plane. */\n private sectionSurfaceHeight(section: SectionRender, point: Point): number {\n const radial = Math.hypot(point.x - section.surfaceFocal.x, point.y - section.surfaceFocal.y);\n const depth = Math.max(0, radial - section.frontDistanceWorld);\n return section.liftWorld + depth * Math.tan((section.rakeDeg * Math.PI) / 180);\n }\n\n /** Desired perspective-space point for a section surface, before Stage pan/zoom. */\n private projectedSectionPoint(section: SectionRender, point: Point): Point {\n return section.perspectiveAffine\n ? applyAffine(section.perspectiveAffine, point)\n : applyAffine(this.perspectiveBaseAffine!, point);\n }\n\n /** Shared-layer local point which the ground affine paints at `projected`. */\n private perspectiveLocalPoint(projected: Point): Point {\n return this.perspectiveBaseInverse ? applyAffine(this.perspectiveBaseInverse, projected) : projected;\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 `liftWorld × isoT` world units\n * (= inverse-linear of the pure vertical lift). Zero at isoT=0. `liftWorld` is\n * the section's resolved real height in world units (Phase B1).\n */\n private isoLiftLocal(liftWorld: number): { x: number; y: number } {\n const { th, sg } = this.isoParams();\n const delta = liftWorld * this.isoT;\n return { x: -(delta / sg) * Math.sin(th), y: -(delta / sg) * Math.cos(th) };\n }\n\n /** Restore projection layers to identity (flat) — byte-for-byte the original.\n * `seatLayer` can be skipped when entering perspective from flat: assigning a\n * top-level transform invalidates all 14k descendant absolute transforms even\n * while the semantic overview keeps that layer fully transparent. */\n private resetLayerTransforms(includeSeatLayer = true): void {\n const layers = includeSeatLayer\n ? [this.bgLayer, this.seatLayer, this.overlayLayer]\n : [this.bgLayer, this.overlayLayer];\n for (const layer of layers) {\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 /** Restore section-owned containers before applying another projection. */\n private resetSectionProjection(resetSeatGroups = true): void {\n for (const section of this.sections) {\n this.resetContainerTransform(section.rootGroupBg);\n this.resetContainerTransform(section.liftGroupBg);\n if (resetSeatGroups) this.resetContainerTransform(section.liftGroupSeat);\n section.rootGroupBg.zIndex(section.bgZIndex);\n if (resetSeatGroups) section.liftGroupSeat.zIndex(section.seatZIndex);\n const labelGroup = this.labelLiftGroups.get(section.id);\n if (labelGroup && resetSeatGroups) this.resetContainerTransform(labelGroup);\n section.perspectiveAffine = undefined;\n section.perspectiveCorrection = undefined;\n section.perspectiveDepth = undefined;\n }\n }\n\n /** Move native seat/booth hit shapes to or from their exact pinhole anchors. */\n private applyExactSeatAnchors(perspective: boolean, seatIds?: Iterable<string>): void {\n const seats = seatIds\n ? [...seatIds].map((id) => this.seatById.get(id)).filter((seat): seat is ExpandedSeat => !!seat)\n : perspective\n ? this.seats\n : [...this.perspectiveAppliedSeats]\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat);\n for (const seat of seats) {\n if (perspective && this.perspectiveAppliedSeats.has(seat.id)) continue;\n // Seat-layer nodes use absolute projected coordinates instead of a\n // transformed 14k-descendant Layer. Overlay nodes continue to use the\n // inverse-base local point and are projected by overlayLayer itself.\n const point = perspective ? this.perspectiveSeatProjected.get(seat.id) ?? seat : seat;\n const scale = perspective ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n const shape = this.circleById.get(seat.id);\n shape?.position(point);\n shape?.scale({ x: scale, y: scale });\n const ring = this.accessRingById.get(seat.id);\n ring?.position(point);\n ring?.scale({ x: scale, y: scale });\n const glyph = this.accessGlyphById.get(seat.id);\n if (glyph) {\n const baseGlyphScale = (this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX;\n glyph.position(point);\n glyph.scale({ x: baseGlyphScale * scale, y: baseGlyphScale * scale });\n }\n const boothLabel = this.boothLabelById.get(seat.id);\n boothLabel?.position(point);\n boothLabel?.scale({ x: scale, y: scale });\n if (perspective) this.perspectiveAppliedSeats.add(seat.id);\n }\n if (!perspective) this.perspectiveAppliedSeats.clear();\n }\n\n /**\n * Phase C projected 2.5D. Seat/booth anchors are exact pinhole projections;\n * section top surfaces use one explicitly bounded tangent plane per authored\n * section. Native Konva shapes move with the anchors, so direct hit testing is\n * the same graph that paints the buyer-visible unit.\n */\n private applyPerspective(resetElevatedSeatGroups = true): void {\n const camera = this.perspectiveCamera;\n const base = this.perspectiveBaseAffine;\n const inverse = this.perspectiveBaseInverse;\n if (!camera || !base || !inverse) return;\n\n const lazySectionSeats = this.seats.length > 2_500 && this.sections.length > 0;\n // A large sectioned overview already owns a flat cached seat bitmap, but\n // the section LOD makes seatLayer fully transparent. Keep that dormant\n // bitmap until the camera reaches live seats: rebuilding 14k invisible\n // descendants during this mode switch costs ~95 ms and paints no pixels.\n if (this.cached && !lazySectionSeats) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n }\n this.resetLayerTransforms(resetElevatedSeatGroups);\n // Flat groups are already identity. Re-setting an identity transform on a\n // group with hundreds of children invalidates every descendant transform;\n // across 14k seats that alone blows the two-frame gate. Only an isometric\n // source view needs its elevated seat-group offsets explicitly cleared.\n this.resetSectionProjection(resetElevatedSeatGroups);\n // Background/overlay geometry benefits from one bounded tangent affine.\n // Exact native seat and booth nodes are placed directly at their pinhole\n // anchors, keeping hit testing exact without invalidating the full seat\n // graph through a top-level Layer transform.\n for (const layer of [this.bgLayer, this.overlayLayer]) {\n this.setContainerAffine(layer, base, camera.target);\n }\n this.perspectiveAppliedSeats.clear();\n // The semantic overview paints section shells and sets seatLayer opacity to\n // zero, so touching 14k invisible nodes here would create a ~200 ms toggle\n // stall for no pixels. Small charts stay eager; large sectioned charts move\n // each native hit shape exactly when its section reaches the live-seat rung.\n if (!lazySectionSeats) this.applyExactSeatAnchors(true);\n\n for (const section of this.sections) {\n const heightAt = (point: Point): number => this.sectionSurfaceHeight(section, point);\n const desired = perspectiveTangentAffine(camera, section.centroid, heightAt);\n const correction = composeAffine(inverse, desired);\n section.perspectiveAffine = desired;\n section.perspectiveCorrection = correction;\n section.perspectiveDepth = projectPerspectivePoint(\n camera,\n section.centroid,\n heightAt(section.centroid),\n ).depth;\n // Only the top shell uses the tangent plane. Seats remain in the root\n // section group at their exact precomputed anchors.\n this.setContainerAffine(section.liftGroupBg, correction, section.centroid);\n\n for (let index = 0; index < section.sideFaces.length; index++) {\n const p0 = section.outline[index];\n const p1 = section.outline[(index + 1) % section.outline.length];\n const base0 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p0, 0));\n const base1 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p1, 0));\n const top1 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p1, heightAt(p1)));\n const top0 = this.perspectiveLocalPoint(projectPerspectivePoint(camera, p0, heightAt(p0)));\n section.sideFaces[index].points([\n base0.x, base0.y,\n base1.x, base1.y,\n top1.x, top1.y,\n top0.x, top0.y,\n ]);\n section.sideFaces[index].opacity(0.9);\n }\n }\n\n // Far sections paint first; near sections and their exact hit shapes win an\n // overlap. Sorting O(section count), never O(seat count), on view entry only.\n const farToNear = [...this.sections].sort(\n (left, right) => (right.perspectiveDepth ?? 0) - (left.perspectiveDepth ?? 0),\n );\n for (const section of farToNear) {\n section.rootGroupBg.moveToTop();\n section.liftGroupSeat.moveToTop();\n }\n this.unsectionedSeatGroup?.moveToTop();\n\n this.syncSeatOverlayPositions();\n // setViewMode() fits the projected bounds immediately after this method.\n // Running viewport culling against the *old flat camera* would eagerly move\n // most 14k native seats even though the fitted overview hides seatLayer.\n if (!lazySectionSeats) this.updateSeatGroupVisibility();\n this.bgLayer.batchDraw();\n this.seatLayer.batchDraw();\n this.overlayLayer.batchDraw();\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 this.resetSectionProjection();\n this.applyExactSeatAnchors(false);\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 this.updateSeatGroupVisibility();\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.liftWorld <= 0) continue;\n const off = this.isoLiftLocal(sec.liftWorld);\n sec.liftGroupBg?.position(off);\n sec.liftGroupSeat.position(off);\n this.labelLiftGroups.get(sec.id)?.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 this.syncSeatOverlayPositions();\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cancelAssetLoads();\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 if (this.exportMode) {\n return this.theme.fontFamily?.toLowerCase().includes('jetbrains')\n ? 'JetBrains Mono, monospace'\n : 'Inter, sans-serif';\n }\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.unsectionedSeatGroup ?? this.seatLayer;\n }\n\n /** True when a section belongs to the active logical section/zone focus. */\n private sectionMatchesFocus(section: SectionRender): boolean {\n const focus = this.focusedSectionId;\n return focus == null\n || section.id === focus\n || section.logicalId === focus\n || section.zone === focus;\n }\n\n /** Visual opacity after the section-focus overlay is composed. */\n private focusedSeatOpacity(id: string, localOpacity: number): number {\n if (!this.focusedSectionId) return localOpacity;\n const section = this.seatSection.get(id);\n return localOpacity * (section && this.sectionMatchesFocus(section) ? 1 : FOCUS_DIM_OPACITY);\n }\n\n /** Project a section outline through elevation + the active affine view and\n * then into viewport pixels. The result is conservative (AABB), so a visible\n * section is never clipped even for rotated or isometric outlines. */\n private sectionScreenBounds(section: SectionRender): { x: number; y: number; width: number; height: number } {\n if (this.viewMode === 'perspective' && section.perspectiveAffine) {\n const scale = this.stage.scaleX();\n const stageX = this.stage.x();\n const stageY = this.stage.y();\n return polyBounds(section.outline.map((point) => {\n const projected = this.projectedSectionPoint(section, point);\n return { x: projected.x * scale + stageX, y: projected.y * scale + stageY };\n }));\n }\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n const scale = this.stage.scaleX();\n const stageX = this.stage.x();\n const stageY = this.stage.y();\n return polyBounds(section.outline.map((point) => {\n const local = { x: point.x + offset.x, y: point.y + offset.y };\n const projected = this.isoT === 0 ? local : this.isoForward(local);\n return { x: projected.x * scale + stageX, y: projected.y * scale + stageY };\n }));\n }\n\n /** Hide only section groups wholly outside a padded viewport at the live-seat\n * rung. Overview caching always restores all groups first, so panning a\n * cached whole-venue bitmap can never reveal missing inventory. */\n private updateSeatGroupVisibility(): void {\n const liveSeats = this.exportMode || this.effScale() >= CACHE_THRESHOLD;\n // During a large-venue focus glide, transient camera rectangles can sweep\n // across thousands of seats that will be offscreen at the endpoint. Keep\n // the semantic shells visible through the motion and project native seats\n // once, for the settled viewport, rather than generating several expensive\n // intermediate scene paints that buyers never interact with.\n const deferPerspectiveSeatReveal = this.viewMode === 'perspective'\n && this.glideInProgress\n && this.seats.length > 2_500;\n const padding = 96;\n const width = this.stage.width();\n const height = this.stage.height();\n for (const section of this.sections) {\n let visible = true;\n if (liveSeats) {\n const bounds = this.sectionScreenBounds(section);\n visible = bounds.x + bounds.width >= -padding\n && bounds.y + bounds.height >= -padding\n && bounds.x <= width + padding\n && bounds.y <= height + padding;\n if (visible && this.viewMode === 'perspective' && !deferPerspectiveSeatReveal) {\n this.applyExactSeatAnchors(true, section.memberIds);\n }\n }\n section.liftGroupSeat.setViewportCulled(!visible);\n const labelGroup = this.labelLiftGroups.get(section.id);\n labelGroup?.setViewportCulled(!visible);\n }\n if (this.unsectionedSeatGroup && !this.unsectionedSeatGroup.visible()) {\n this.unsectionedSeatGroup.visible(true);\n }\n if (liveSeats && this.viewMode === 'perspective' && !deferPerspectiveSeatReveal) {\n this.applyExactSeatAnchors(true, this.seats\n .filter((seat) => !this.seatSection.has(seat.id))\n .map((seat) => seat.id));\n }\n }\n\n /** Seats worth considering for viewport labels. Section culling is a safe\n * coarse index; the later screen test remains the exact filter. */\n private visibleSeatCandidates(): ExpandedSeat[] {\n if (!this.sections.length) return this.seats;\n const candidates: ExpandedSeat[] = [];\n for (const section of this.sections) {\n if (section.liftGroupSeat.isViewportCulled()) continue;\n for (const id of section.memberIds) {\n const seat = this.seatById.get(id);\n if (seat) candidates.push(seat);\n }\n }\n for (const seat of this.seats) {\n if (!this.seatSection.has(seat.id)) candidates.push(seat);\n }\n return candidates;\n }\n\n private seatViewportCulled(id: string): boolean {\n return this.seatSection.get(id)?.liftGroupSeat.isViewportCulled() ?? false;\n }\n\n /** Local world coordinate at which an elevated seat is actually painted for\n * the current iso tween. Flat seats and the 2D endpoint are unchanged. */\n private renderedSeatPoint(seat: ExpandedSeat): Point {\n if (this.viewMode === 'perspective') return this.perspectiveSeatLocal.get(seat.id) ?? seat;\n const section = this.seatSection.get(seat.id);\n if (!section || section.liftWorld <= 0 || this.isoT === 0) return seat;\n const offset = this.isoLiftLocal(section.liftWorld);\n return { x: seat.x + offset.x, y: seat.y + offset.y };\n }\n\n /** Overlay labels mirror the seat-layer lift without an O(seats) per-frame\n * rewrite. The groups are rebuilt with the zoom-dependent label set. */\n private seatLabelContainer(id: string): Group {\n const section = this.seatSection.get(id);\n if (!section) return this.labelGroup;\n let group = this.labelLiftGroups.get(section.id);\n if (!group) {\n group = new ViewportGroup({\n listening: false,\n });\n group.setViewportCulled(section.liftGroupSeat.isViewportCulled());\n group.position(this.viewMode === 'perspective'\n ? { x: 0, y: 0 }\n : this.isoLiftLocal(section.liftWorld));\n this.labelGroup.add(group);\n this.labelLiftGroups.set(section.id, group);\n }\n return group;\n }\n\n /** Shared overlay furniture is not parented to section lift groups, so keep\n * the small transient set aligned explicitly. Selection is capped in buyer\n * mode, making this constant-sized work during the iso tween. */\n private syncSeatOverlayPositions(): void {\n if (this.hoveredId) {\n const seat = this.seatById.get(this.hoveredId);\n if (seat) {\n this.hoverRing.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n this.hoverRing.scale({ x: scale, y: scale });\n }\n }\n if (this.focusedId) {\n const seat = this.seatById.get(this.focusedId);\n if (seat) {\n this.focusRing.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n this.focusRing.scale({ x: scale, y: scale });\n }\n }\n for (const [id, marker] of this.selectionMarkers) {\n const seat = this.seatById.get(id);\n if (seat) {\n marker.position(this.renderedSeatPoint(seat));\n const scale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(seat.id) ?? 1 : 1;\n marker.scale({ x: scale, y: scale });\n }\n }\n }\n\n private renderSeats(): void {\n // Stable far→near insertion makes exact perspective anchors occlude in the\n // camera-correct order without an O(seats) reorder when the buyer toggles\n // the view. Flat charts rarely overlap units; id is the deterministic tie.\n const paintOrder = [...this.seats].sort((left, right) =>\n (this.perspectiveSeatDepth.get(right.id) ?? 0) - (this.perspectiveSeatDepth.get(left.id) ?? 0));\n for (const seat of paintOrder) {\n if (seat.kind === 'booth') {\n this.renderBoothUnit(seat);\n continue;\n }\n const target = this.seatContainer(seat.id);\n // An empty wheelchair bay is still one sellable inventory unit, but its\n // square footprint must never masquerade as a fixed chair. `skip` seats\n // never reach this loop at all, preserving the three distinct states.\n const c: Shape = seat.wheelchairSpaceType === 'no-seat'\n ? new Rect({\n x: seat.x,\n y: seat.y,\n width: this.seatR * 2,\n height: this.seatR * 2,\n offsetX: this.seatR,\n offsetY: this.seatR,\n cornerRadius: 2,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n })\n : 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 // Every accommodation gets its colour-coded ring. The centred ♿ path is\n // reserved for actual wheelchair provision; CART, hearing and other\n // accommodations must never masquerade as wheelchair places.\n if (seat.accessible) {\n if (seat.wheelchairSpaceType !== 'no-seat') {\n const ring = new Circle({\n x: seat.x,\n y: seat.y,\n radius: this.seatR + 1.5,\n stroke: accessibilityRingColor(seat.accessibility),\n strokeWidth: 2.5,\n listening: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n this.accessRingById.set(seat.id, ring);\n target.add(ring);\n }\n if (seat.accessibility?.includes('wheelchair') && accessGlyphPath(seat.accessibility)) {\n const glyph = this.buildAccessGlyph(seat, typeof c.fill() === 'string' ? (c.fill() as string) : '');\n this.accessGlyphById.set(seat.id, glyph);\n target.add(glyph);\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 let labelX = seat.x;\n let labelY = seat.y;\n let node: Shape;\n if (dims.points && dims.points.length >= 3) {\n // Custom outline: local points relative to the booth centre (seat.x/y),\n // drawn as one closed unit. Label sits at the polygon centroid.\n node = new Line({\n x: seat.x,\n y: seat.y,\n points: dims.points.flatMap((p) => [p.x, p.y]),\n closed: true,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n hitStrokeWidth: 0,\n });\n labelX = seat.x + dims.points.reduce((a, p) => a + p.x, 0) / dims.points.length;\n labelY = seat.y + dims.points.reduce((a, p) => a + p.y, 0) / dims.points.length;\n } else {\n node = 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 }\n node.setAttr('seatId', seat.id);\n this.circleById.set(seat.id, node);\n target.add(node);\n\n const t = new Text({\n x: labelX,\n y: labelY,\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.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(node, seat.id);\n }\n\n /**\n * Build the centred accessibility glyph for a seat. Sized relative to the seat\n * radius (so it always fills the marker at any zoom) and given a contrast-aware\n * fill against the seat's paint — recomputed per state in {@link paintSeat}.\n */\n private buildAccessGlyph(seat: ExpandedSeat, seatFill: string): Path {\n const k = (this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX;\n return new Path({\n x: seat.x,\n y: seat.y,\n // Non-null: buildAccessGlyph is only called for seats the gate confirmed\n // resolve to a primary-accommodation glyph.\n data: accessGlyphPath(seat.accessibility ?? []) ?? '',\n offsetX: ACCESS_GLYPH_VIEWBOX / 2,\n offsetY: ACCESS_GLYPH_VIEWBOX / 2,\n scaleX: k,\n scaleY: k,\n fill: accessGlyphInk(seatFill),\n listening: false,\n visible: false,\n perfectDrawEnabled: false,\n shadowForStrokeEnabled: false,\n });\n }\n\n /**\n * Keep physical wheelchair provision readable in screen space at every map\n * LOD. The active Wheelchair filter promotes it further. Iterates the small\n * wheelchair-seat set, never the full node graph.\n */\n private updateAccessGlyphs(scale: number): void {\n if (!this.accessGlyphById.size) return;\n for (const [id, glyph] of this.accessGlyphById) {\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(id) ?? 1\n : 1;\n const baseScale = ((this.seatR * 1.5) / ACCESS_GLYPH_VIEWBOX) * perspectiveScale;\n const emphasized = this.accessGlyphFilterEmphasized(id);\n const minimumScreenPx = emphasized\n ? FILTERED_WHEELCHAIR_GLYPH_MIN_PX\n : WHEELCHAIR_GLYPH_MIN_PX;\n const glyphScale = Math.max(\n baseScale,\n minimumScreenPx / (ACCESS_GLYPH_VIEWBOX * Math.max(scale, 0.001)),\n );\n glyph.scale({ x: glyphScale, y: glyphScale });\n glyph.visible(this.accessGlyphShouldShow(id));\n }\n }\n\n /** True only for a physical wheelchair provision matching an active buyer filter. */\n private accessGlyphFilterEmphasized(id: string): boolean {\n const seat = this.seatById.get(id);\n const filter = this.accessFilter;\n return !!seat\n && filter !== null\n && !!seat.accessibility?.includes('wheelchair')\n && (filter.length === 0 || filter.includes('wheelchair'))\n && seatMatchesAccess(seat, filter);\n }\n\n private accessGlyphShouldShow(id: string): boolean {\n return this.accessGlyphById.has(id) && this.accessGlyphEligible(id);\n }\n\n /**\n * Whether an accessible seat's glyph should show for its current status. It is\n * hidden on seats a buyer cannot take (sold, or another buyer's hold) where the\n * overlay status cue (diagonal mark / lock) carries the state instead — mirrors\n * the `unavailable` test in {@link updateLabels} so the two never collide.\n */\n private accessGlyphEligible(id: string): boolean {\n const status = this.statusById.get(id) ?? 'free';\n if (status === 'booked') return false;\n if (status === 'held' && !this.ownedHold.has(id) && !this.opts.manageMode) return false;\n return true;\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 // Key-based (OV-46): the hue follows the category's identity, not its order.\n return this.cbHueByKey.get(categoryKey) ?? CB_PALETTE[0];\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), AUTHORED_LABEL_MIN_CONTRAST);\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 // The empty bay keeps normal status/category paint for booking truth, while\n // its dashed square boundary supplies a non-colour cue that it is space for\n // a wheelchair rather than a physical chair.\n if (seat.wheelchairSpaceType === 'no-seat' && status === 'free') {\n c.stroke(accessibilityRingColor(seat.accessibility));\n c.strokeWidth(selected ? 3 : 2);\n c.dash([3, 2]);\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 // Section-focus dimming belongs to the section's parent Group. Keeping it\n // out of this per-seat paint path avoids 14k node mutations on focus.\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 // Keep the accessibility markers composed with the seat's final paint: the\n // glyph re-contrasts against the current fill (legible on any state incl.\n // colorblind hues), and both markers inherit the seat's opacity so filter/\n // focus dimming carries through instead of leaving a bright ring behind.\n const accessGlyph = this.accessGlyphById.get(id);\n if (accessGlyph) {\n const fill = c.fill();\n accessGlyph.fill(accessGlyphInk(typeof fill === 'string' ? fill : ''));\n accessGlyph.opacity(c.opacity());\n accessGlyph.visible(this.accessGlyphShouldShow(id));\n }\n this.accessRingById.get(id)?.opacity(c.opacity());\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.bgLayer.batchDraw();\n this.overlayLayer.batchDraw();\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.focusDimOverlay?.destroy();\n this.focusDimOverlay = null;\n this.bgLayer.batchDraw();\n this.overlayLayer.batchDraw();\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 const perspective = this.viewMode === 'perspective' && section.perspectiveAffine;\n const outline = perspective\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline;\n const holes = perspective\n ? section.holes.map((hole) => hole.map((point) =>\n this.perspectiveLocalPoint(this.projectedSectionPoint(section, point))))\n : section.holes;\n backdrop.add(polygonWithHolesShape(outline, holes, {\n fill: FOCUS_BACKDROP_FILL,\n stroke: rgba('#ffffff', 0.1),\n strokeWidth: 1,\n listening: false,\n }, perspective ? undefined : 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 this.drawFocusDimOverlay(sections);\n }\n\n /** Dim everything outside the active section with one paint-only shape. Group\n * opacity would make Konva recursively invalidate absolute-opacity caches on\n * all 14k descendants. The cut-out follows the live elevation offset and is\n * non-listening, so direct seat hit-testing is unchanged. */\n private drawFocusDimOverlay(sections: SectionRender[]): void {\n this.focusDimOverlay?.destroy();\n const span = Math.max(this.bounds.width, this.bounds.height, 1);\n const padding = span * 4 + 1_000;\n const outer: Point[] = [\n { x: this.bounds.x - padding, y: this.bounds.y - padding },\n { x: this.bounds.x + this.bounds.width + padding, y: this.bounds.y - padding },\n { x: this.bounds.x + this.bounds.width + padding, y: this.bounds.y + this.bounds.height + padding },\n { x: this.bounds.x - padding, y: this.bounds.y + this.bounds.height + padding },\n ];\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 overlay = new Shape({\n fill: this.canvasBackground,\n opacity: 1 - FOCUS_DIM_OPACITY,\n listening: false,\n perfectDrawEnabled: false,\n sceneFunc: (context, shape) => {\n const polygonPath = (points: Point[]): void => {\n if (!points.length) return;\n context.moveTo(points[0].x, points[0].y);\n for (let index = 1; index < points.length; index++) context.lineTo(points[index].x, points[index].y);\n context.closePath();\n };\n context.beginPath();\n polygonPath(outer);\n for (const section of sections) {\n const hole = this.viewMode === 'perspective' && section.perspectiveAffine\n ? section.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(section, point)))\n : section.outline.map((point) => {\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n return { x: point.x + offset.x, y: point.y + offset.y };\n });\n // Outer is clockwise in canvas coordinates; reverse same-winding holes\n // so the default non-zero fill rule cuts a transparent focus window.\n polygonPath(signedArea(hole) > 0 ? [...hole].reverse() : hole);\n }\n context.fillStrokeShape(shape);\n },\n });\n this.overlayLayer.add(overlay);\n overlay.moveToTop();\n for (const marker of this.selectionMarkers.values()) marker.moveToTop();\n this.hoverRing.moveToTop();\n this.focusRing.moveToTop();\n this.focusDimOverlay = overlay;\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 const buyerBackground = buyerBackgroundImage(doc);\n if (buyerBackground) this.renderBackgroundImage(buyerBackground);\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 /**\n * Track an image through decode without ever leaving a rejected promise\n * unobserved. Ordinary picker rendering remains best-effort; export ready()\n * turns the retained failures into one actionable error.\n */\n private trackAssetImage(\n image: HTMLImageElement,\n source: string,\n label: string,\n onReady: () => void,\n ): void {\n const generation = this.assetGeneration;\n if (/^https?:\\/\\//i.test(source)) image.crossOrigin = 'anonymous';\n const work = new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n this.assetCancels.delete(cancel);\n resolve();\n };\n const cancel = () => {\n image.onload = null;\n image.onerror = null;\n try {\n image.removeAttribute('src');\n image.src = '';\n } catch {\n // Releasing the renderer must not be blocked by an Image implementation.\n }\n finish();\n };\n this.assetCancels.add(cancel);\n image.onload = () => {\n if (!this.exportMode) {\n if (generation === this.assetGeneration) onReady();\n finish();\n return;\n }\n const decoded = typeof image.decode === 'function' ? image.decode() : Promise.resolve();\n void decoded\n .then(() => {\n if (generation === this.assetGeneration) onReady();\n })\n .catch(() => {\n if (generation === this.assetGeneration) this.assetErrors.push(`${label} could not be decoded.`);\n })\n .finally(finish);\n };\n image.onerror = () => {\n if (generation === this.assetGeneration) this.assetErrors.push(`${label} could not be loaded.`);\n finish();\n };\n image.src = source;\n });\n this.assetPromises.push(work);\n }\n\n /** Cancel and release every image retained by the previous chart/export. */\n private cancelAssetLoads(): void {\n this.assetGeneration++;\n for (const cancel of [...this.assetCancels]) cancel();\n this.assetCancels.clear();\n this.assetPromises = [];\n this.assetErrors = [];\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 this.trackAssetImage(img, bg.url, 'Buyer background image', () => {\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 }\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 // Foreground decor rides the overlay layer (above every seat); background\n // decor stays on bgLayer, beneath sections and seats.\n if (obj.layer === 'foreground') this.fgDecorGroup.add(node);\n else this.bgLayer.add(node);\n this.trackAssetImage(img, obj.href, `Decor image “${obj.label || obj.id}”`, () => {\n const layer = node.getLayer();\n if (!layer) return; // chart swapped out before the image loaded\n layer.batchDraw();\n });\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.displayLabel ?? 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 = obj.background?.color ?? this.canvasBackground;\n const preferredInk = obj.color ?? this.theme.textColor ?? DEF_TEXT;\n // Modern venue icons draw as a single-color vector Path — pixel-identical to\n // the Designer. Legacy emoji icons (no iconKey) and captions fall through to\n // the Konva.Text path below, so old charts render unchanged.\n const iconPath = obj.semanticKind === 'icon' ? venueIconPath(obj.iconKey) : undefined;\n if (iconPath) {\n const scale = obj.fontSize / VENUE_ICON_VIEWBOX;\n const iconNode = new Path({\n x: obj.position.x,\n y: obj.position.y,\n data: iconPath,\n rotation: obj.rotation,\n scaleX: scale,\n scaleY: scale,\n stroke: stateAwareBookableLabelInk(background, preferredInk),\n strokeWidth: VENUE_ICON_STROKE,\n lineCap: 'round',\n lineJoin: 'round',\n fillEnabled: false,\n listening: false,\n perfectDrawEnabled: false,\n });\n this.iconNodeById.set(obj.id, { node: iconNode, fontSize: obj.fontSize });\n this.bgLayer.add(iconNode);\n return;\n }\n const padding = obj.background?.padding ?? 0;\n const opacity = obj.opacity ?? 1;\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 // Keep the buyer glyph metrics identical to Designer: wrapping must not\n // gain or lose a line when the authored chart is published.\n fontStyle: konvaFontStyle(obj.bold, obj.italic, '600'),\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: obj.fontFamily ?? this.labelFont(),\n ...(obj.width != null ? { width: obj.width } : {}),\n align: obj.align ?? 'left',\n lineHeight: obj.lineHeight ?? 1.2,\n letterSpacing: obj.letterSpacing ?? 0,\n textDecoration: obj.underline ? 'underline' : '',\n padding,\n opacity,\n wrap: 'word',\n listening: false,\n perfectDrawEnabled: false,\n name: 'buyer-free-text',\n });\n let backdrop: Rect | undefined;\n if (obj.background) {\n backdrop = new Rect({\n x: obj.position.x,\n y: obj.position.y,\n width: node.width(),\n height: node.height(),\n rotation: obj.rotation,\n fill: obj.background.color,\n opacity: opacity * (obj.background.opacity ?? 0.9),\n cornerRadius: obj.background.cornerRadius ?? 4,\n listening: false,\n perfectDrawEnabled: false,\n name: 'buyer-text-background',\n });\n this.bgLayer.add(backdrop);\n }\n this.freeTextById.set(obj.id, {\n node,\n backdrop,\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 const isOpenPath = obj.kind === 'line' || obj.kind === 'polyline';\n // Author outline wins; stage keeps its lit edge; open paths always paint a\n // visible default stroke; reference focals keep their palette outline.\n const stroke = obj.stroke?.color\n ?? (isStage ? lighten(fill, 0.28) : referenceFocal ? palette.focalStroke : isOpenPath ? '#9aa3b5' : undefined);\n // Stage: darker at the back (min-y), brighter toward the audience edge (max-y).\n const strokeWidth = obj.stroke?.width ?? (isStage ? 1 : referenceFocal ? 2 : isOpenPath ? 2 : 0);\n const opacity = obj.opacity != null ? clamp(obj.opacity, 0.1, 1) : 1;\n let cx = 0;\n let cy = 0;\n if (isOpenPath && obj.points && obj.points.length >= 2) {\n // Open path: stroke-only, never filled, never hit-tested.\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 lineStyle = resolvedShapeLineStyle(obj);\n const arrow = shapeArrowMetrics(strokeWidth);\n const path = new Arrow({\n points: obj.points.flatMap((p) => [p.x, p.y]),\n closed: false,\n x: cx,\n y: cy,\n offsetX: cx,\n offsetY: cy,\n rotation: obj.rotation ?? 0,\n stroke,\n fill: stroke,\n strokeWidth,\n opacity,\n lineCap: lineStyle.lineCap,\n lineJoin: lineStyle.lineJoin,\n pointerAtBeginning: lineStyle.startEnding === 'arrow',\n pointerAtEnding: lineStyle.endEnding === 'arrow',\n ...arrow,\n listening: false,\n name: 'buyer-shape-open-path',\n });\n path.setAttr('shapeObjectId', obj.id);\n this.bgLayer.add(path);\n } else 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: clamp(obj.cornerRadius ?? 4, 0, Math.min(obj.width, obj.height) / 2),\n opacity,\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, opacity, 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, opacity, 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 cornerRadius: obj.cornerRadius,\n });\n poly.setAttr('gaId', obj.id);\n poly.on('click tap', (e: KonvaEventObject<Event>) => {\n if (this.isGhostClick(e)) return; // a double onGAClick would double-open the qty picker\n this.opts.onGAClick?.(obj.id);\n });\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.displayLabel ?? 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.displayLabel ?? 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 const bounds = polyBounds(obj.outline);\n const candidates = this.seatIndex\n ? queryRect(this.seatIndex, bounds)\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat)\n : this.seats;\n for (const seat of candidates) {\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 // Every section gets a seat group even at height zero: that parent is the\n // safe unit for production viewport culling on very large live-seat scenes.\n // Side faces (a zone-coloured quad per outline edge) extrude only as isoT rises.\n const elevation = sectionElevationTier(obj.elevation);\n // Real iso lift (Phase B1): authored height when present, else the elevation\n // tier fallback — which reproduces the legacy `elevation × LIFT_PER_STEP`.\n const geometry = sectionGeometry(obj, {\n floorBaseHeightM: this.floorBaseHeightMFor(obj.id),\n });\n const liftWorld = geometry.height * CHART_UNITS_PER_METRE;\n const rootGroupBg = new Group({ listening: false });\n this.bgLayer.add(rootGroupBg);\n const liftGroupBg = new Group({ listening: false });\n rootGroupBg.add(liftGroupBg);\n const liftGroupSeat = new ViewportGroup({ listening: true });\n this.seatLayer.add(liftGroupSeat);\n const sideFaces: Line[] = [];\n if (liftWorld > 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 rootGroupBg.add(face); // behind the top-surface group\n }\n }\n // Top surface must paint above its side faces in both iso and perspective.\n liftGroupBg.moveToTop();\n const bgTarget: Group = liftGroupBg;\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,\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 labelArea: polygonNetArea(obj.outline, obj.holes),\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 liftWorld,\n rakeDeg: geometry.rake,\n surfaceFocal: memberIds.length\n ? { ...(this.seatById.get(memberIds[0])?.focalPoint ?? this.isoCentre) }\n : { ...(this.chartDoc?.focalPoint ?? this.isoCentre) },\n frontDistanceWorld: 0,\n rootGroupBg,\n bgZIndex: rootGroupBg.zIndex(),\n seatZIndex: liftGroupSeat.zIndex(),\n liftGroupBg,\n liftGroupSeat,\n sideFaces,\n };\n const surfaceCandidates = memberIds\n .map((id) => this.seatById.get(id))\n .filter((seat): seat is ExpandedSeat => !!seat);\n const distanceCandidates: Point[] = surfaceCandidates.length ? surfaceCandidates : obj.outline;\n sec.frontDistanceWorld = Math.min(...distanceCandidates.map((point) => Math.hypot(\n point.x - sec.surfaceFocal.x,\n point.y - sec.surfaceFocal.y,\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 availability shading + retained availability text. */\n private refreshSectionFill(sec: SectionRender): void {\n sec.blockPoly.fill(this.sectionBlockFill(sec));\n // The overview shell itself carries the sold-out/nearly-gone signal; this\n // text stays for the focused/detail + a11y layers (kept hidden on the shell).\n sec.subLabel.text(\n this.sectionAvailabilityState(sec) === 'sold-out'\n ? t('map.soldOut')\n : t('map.seatsLeft', { count: sec.free }),\n );\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 /** Resolve the four-bucket overview availability state for a section (OV-69).\n * `closed` (operator) outranks live availability; the availability buckets\n * only apply to seated sections (GA-only shells have no seat capacity here). */\n private sectionAvailabilityState(sec: SectionRender): SectionAvailabilityState {\n if (this.isSectionClosed(sec)) return 'closed';\n if (sec.total <= 0) return 'normal';\n if (sec.free <= 0) return 'sold-out';\n if (sec.free <= sec.total * SECTION_NEARLY_GONE_RATIO) return 'nearly-gone';\n return 'normal';\n }\n\n /** Overview shells stay neutral except for the bounded availability shading\n * (nearly-gone / sold-out) and the operator `closed` slab — never category\n * or price paint, which is deferred to section focus/seat detail. */\n private sectionBlockFill(sec: SectionRender): string {\n return overviewStateFill(overviewPalette(this.canvasBackground), this.sectionAvailabilityState(sec));\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 const deferPerspectiveSeatReveal = this.viewMode === 'perspective'\n && this.glideInProgress\n && this.seats.length > 2_500;\n this.seatLayer.opacity(sectionOverview || deferPerspectiveSeatReveal ? 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 // Fitted polygon labels are expensive (point-in-polygon + text measure).\n // Refit only after a meaningful camera change. The stage still scales text\n // smoothly between checkpoints; exact screen-pixel fitting catches up at\n // the next checkpoint (or once an animated glide settles).\n const rescale = !this.glideInProgress\n && (this.lodScale === 0 || Math.abs(scale - this.lodScale) / (this.lodScale || 1) > 0.08);\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 // The paint-only focus overlay already dims seats, blocks, and labels as\n // one composed scene. Avoid applying the old per-node factor underneath\n // it (which would double-dim section shells to ~2.5%).\n const dim = this.focusDimOverlay\n ? 1\n : (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 && sectionLabelT > 0.01) this.fitSectionRungLabels(sec, sx);\n const labelOpacity = sectionLabelT * (1 - zoneT) * dim;\n sec.nameLabel.opacity(sec.nameLabelFits ? labelOpacity : 0);\n // Availability now reads from the shell FILL (nearly-gone / sold-out\n // shading, OV-69), so the availability text stays a focused/detail + a11y\n // affordance — deliberately not a second map label on the 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 if (!this.glideInProgress && (sectionLabelT > 0.01 || zoneOpacity > 0.01)) {\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 }\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, and keep section\n * names off each other.\n *\n * This used to assume section labels \"do not collide by construction\",\n * because each is proven to fit inside its own shell. That holds only while\n * shells are disjoint. Hand-traced and imported plans routinely produce\n * shells that touch or overlap slightly along a shared edge, and a label\n * fitted into one can then land under its neighbour's — which is exactly the\n * unreadable smear a 36-section arena showed. Section labels now block each\n * other too, largest shell first so the big stands keep their names.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; area?: number; 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) {\n cands.push({ node: sec.nameLabel, tier: 1, section: true, area: sec.labelArea, box: boxOf(sec.nameLabel) });\n }\n }\n if (cands.length < 2) return;\n // Zone pills first (they are the coarser tier), then sections by shell size\n // so a slice never takes the slot from the stand beside it.\n cands.sort((a, b) => a.tier - b.tier\n || (b.area ?? 0) - (a.area ?? 0)\n || 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 // Shrink before hiding — the rule the Designer's own culler already follows.\n //\n // Dropping a colliding pill outright is defensible on an authoring canvas,\n // where the author knows what they drew. On the BUYER map it is not: a\n // section with no name is one the buyer cannot match to the section printed\n // on their ticket, and on a traced arena that was most of the bowl at\n // overview zoom. A smaller readable name beats a missing one.\n //\n // The floor is the same legibility floor the fitter uses, so nothing shrinks\n // into unreadability; anything still colliding at that size is genuinely out\n // of room and is hidden as before, returning as zoom spreads the sections.\n for (const c of cands) {\n if (!collides(c.box)) {\n kept.push(c.box);\n continue;\n }\n let placed = false;\n if (c.section) {\n const fontSize = c.node.fontSize();\n const y = c.node.y();\n for (const factor of SECTION_LABEL_SHRINK_STEPS) {\n const candidate = fontSize * factor;\n if (candidate * sx < MIN_SECTION_LABEL_PX) break;\n this.sizeLabel(c.node, candidate, y);\n const box = boxOf(c.node);\n if (!collides(box)) {\n kept.push(box);\n placed = true;\n break;\n }\n }\n if (!placed) this.sizeLabel(c.node, fontSize, y);\n }\n if (!placed) c.node.opacity(0);\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 if (this.viewMode === 'perspective' && this.perspectiveBaseInverse) {\n return applyAffine(this.perspectiveBaseInverse, iso);\n }\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) => {\n if (this.viewMode === 'perspective' && sec.perspectiveAffine) {\n return pointInPolygonWithHoles(\n world,\n sec.outline.map((point) => this.perspectiveLocalPoint(this.projectedSectionPoint(sec, point))),\n sec.holes.map((hole) => hole.map((point) =>\n this.perspectiveLocalPoint(this.projectedSectionPoint(sec, point)))),\n );\n }\n const offset = sec.liftWorld > 0 ? this.isoLiftLocal(sec.liftWorld) : { x: 0, y: 0 };\n return pointInPolygonWithHoles(\n { x: world.x - offset.x, y: world.y - offset.y },\n sec.outline,\n sec.holes,\n );\n });\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 rendered = this.renderedSeatPoint(seat);\n const marker = new Group({\n name: 'selection-ring',\n x: rendered.x,\n y: rendered.y,\n rotation: dims?.rotation ?? 0,\n listening: false,\n perfectDrawEnabled: false,\n opacity: this.selectionFocusId && !candidate ? 0.2 : 1,\n });\n if (this.viewMode === 'perspective') {\n const projectionScale = this.perspectiveSeatScale.get(id) ?? 1;\n marker.scale({ x: projectionScale, y: projectionScale });\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 // Keep a committed selection inside the authored seat footprint. Charts\n // commonly place adjacent seats only a small gap apart, so an outside\n // selection ring made neighbouring secured seats appear to merge.\n marker.add(new Circle({\n ...common,\n radius: Math.max(1, this.seatR - 1.25),\n strokeWidth: Math.min(2.5, Math.max(1.8, this.seatR * 0.22)),\n }));\n if (candidate) {\n // The pre-add confirmation may extend just beyond the seat, but stays\n // compact enough to respect the original chart's row/column spacing.\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 2,\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) => {\n if (this.viewMode === 'perspective' && section.perspectiveAffine) {\n return polyBounds(section.outline.map((point) => this.projectedSectionPoint(section, point)));\n }\n const offset = section.liftWorld > 0 ? this.isoLiftLocal(section.liftWorld) : { x: 0, y: 0 };\n // Camera position is expressed in the stage's post-affine world space.\n // Frame the outline after both the section lift and the active iso\n // projection; feeding local lifted bounds to focusRegion applies the\n // affine a second time and can send a balcony below the viewport.\n const points = section.outline.map((point) => {\n const local = { x: point.x + offset.x, y: point.y + offset.y };\n return this.isoT === 0 ? local : this.isoForward(local);\n });\n return polyBounds(points);\n });\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 let best: string | null = null;\n let bestD = Infinity;\n const stageScale = this.stage.scaleX() || 1;\n for (const seat of this.seats) {\n if (!this.selection.has(seat.id) && !this.isSelectable(seat.id)) continue;\n const centre = this.worldToScreen(seat);\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\n // Perspective markers are native seat-layer nodes at exact projected\n // coordinates. They do not inherit the section-shell tangent affine.\n const reachPx = this.seatR * stageScale * perspectiveScale + slopPx;\n const d = Math.hypot(centre.x - screen.x, centre.y - screen.y);\n if (d <= reachPx && 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 if (this.isGhostClick(e)) return; // protected only incidentally; lost when cached\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.hoveredId = id;\n this.hoverRing.position(this.renderedSeatPoint(seat));\n const projectionScale = this.viewMode === 'perspective' ? this.perspectiveSeatScale.get(id) ?? 1 : 1;\n this.hoverRing.scale({ x: projectionScale, y: projectionScale });\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.hoveredId = null;\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 if (this.isGhostClick(e)) return; // near-miss rescue below is the ghost-click path\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 sectionId = this.sectionAt(pointer);\n if (sectionId) {\n if (this.opts.onSectionTap) this.opts.onSectionTap(sectionId);\n else this.focusRegion(sectionId);\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 pointer = this.stage.getPointerPosition();\n if (!pointer) return null;\n const p = this.screenToWorld(pointer);\n let best: string | null = null;\n let bestD = Infinity;\n for (const s of this.seats) {\n const rendered = this.renderedSeatPoint(s);\n const dx = rendered.x - p.x;\n const dy = rendered.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.updateSeatGroupVisibility();\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.updateSeatGroupVisibility();\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 this.glideInProgress = true;\n const step = (now: number): void => {\n if (this.destroyed) { this.glideRaf = 0; this.glideInProgress = false; 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 // Cull before crossing out of the overview bitmap: updateLOD may uncache\n // the live graph on this exact frame, which must already be bounded.\n this.updateSeatGroupVisibility();\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.glideInProgress = false;\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 this.glideInProgress = false;\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 localPerspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\n const seatEffectiveScale = (this.viewMode === 'perspective' ? stageScale : effectiveScale)\n * localPerspectiveScale;\n const authoredFontSize = seat.kind === 'booth'\n ? BOOTH_LABEL_FONT_SIZE\n : SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);\n const labelEffectiveScale = this.viewMode === 'perspective' && seat.kind !== 'booth'\n ? effectiveScale * localPerspectiveScale\n : seatEffectiveScale;\n const renderedFontPx = rounded((label?.fontSize() ?? authoredFontSize) * labelEffectiveScale);\n const screen = this.worldToScreen(seat);\n const outside = screen.x < 0 || screen.x > viewport.width || screen.y < 0 || screen.y > viewport.height;\n // Focus dimming and viewport culling are parent-group states, so evidence\n // must report composed scene opacity/visibility rather than the child's\n // local attribute in isolation.\n const opacity = this.focusedSeatOpacity(seat.id, shape?.getAbsoluteOpacity() ?? 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 * localPerspectiveScale : 0;\n const labelHeight = label\n ? label.height() * (this.viewMode === 'perspective' && seat.kind === 'booth' ? stageScale : effectiveScale)\n * localPerspectiveScale\n : 0;\n const directWidthPx = shape instanceof Rect\n ? shape.width() * stageScale * localPerspectiveScale\n : this.seatR * 2 * seatEffectiveScale;\n const directHeightPx = shape instanceof Rect\n ? shape.height() * (this.viewMode === 'perspective' ? stageScale : effectiveScale) * localPerspectiveScale\n : this.seatR * 2 * seatEffectiveScale;\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 * seatEffectiveScale + SEAT_TAP_SLOP_PX);\n const fill = shape?.fill();\n const ink = label?.fill();\n const accessGlyph = this.accessGlyphById.get(seat.id);\n const accessGlyphScale = accessGlyph?.getAbsoluteScale();\n return {\n seatId: seat.id,\n label: seat.label,\n kind: seat.kind === 'booth' ? 'booth' : 'seat',\n markerShape: seat.kind === 'booth'\n ? 'booth'\n : seat.wheelchairSpaceType === 'no-seat'\n ? 'square'\n : 'circle',\n ...(seat.wheelchairSpaceType ? { wheelchairSpaceType: seat.wheelchairSpaceType } : {}),\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 // When no label node exists (the seat is unlabelled at this zoom), fall\n // back to the ink this seat WOULD be painted with — the same expression\n // the seat-level evidence below uses — not to the raw theme default.\n //\n // The old fallback reported `DEF_SEAT_LABEL` (#0b1220) regardless of the\n // seat's paint, so a held seat with no label read as dark ink on\n // HELD_FILL (#6b7280) = 3.87:1 and a booked one as 1.82:1 against\n // TAKEN_FILL. That is a contrast violation the renderer never commits:\n // `seatLabelInk` runs every real label through `stateAwareBookableLabelInk`,\n // which returns #ffffff for both of those fills. A catalog visual audit\n // read this fallback as though it were painted and reported a\n // bookable-state contrast failure on 46 of 50 templates that does not\n // exist on screen.\n ink: typeof ink === 'string' ? ink : (shape ? this.seatLabelInk(seat, shape) : this.seatPreferredLabelInk(seat)),\n opacity: rounded(opacity),\n ...(accessGlyph ? {\n accessibilityMarker: {\n glyphVisible: accessGlyph.isVisible(),\n glyphWidthPx: rounded(ACCESS_GLYPH_VIEWBOX * Math.abs(accessGlyphScale?.x ?? 0)),\n emphasizedByFilter: this.accessGlyphFilterEmphasized(seat.id),\n },\n } : {}),\n pointerTarget: {\n active: !this.cached\n && !this.seatViewportCulled(seat.id)\n && Boolean(shape?.isVisible())\n && Boolean(shape?.isListening())\n && 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 lift = section && section.liftWorld > 0\n ? this.isoLiftLocal(section.liftWorld)\n : { x: 0, y: 0 };\n const screenBounds = pointsBounds(worldCorners.map((corner) => this.worldToScreen({\n x: corner.x + lift.x,\n y: corner.y + lift.y,\n })));\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 // Every bounded availability-state fill (normal / nearly-gone / sold-out /\n // closed) is a legitimate semantic shell — not category paint leaking in.\n const neutralSectionFills = new Set(\n (['normal', 'nearly-gone', 'sold-out', 'closed'] as const)\n .map((state) => overviewStateFill(palette, state).toLowerCase()),\n );\n const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);\n return {\n viewport,\n projection: this.viewMode,\n ...(this.viewMode === 'perspective' ? {\n perspective: {\n model: 'pinhole-exact-seat-anchors' as const,\n sectionSurfaceModel: 'tangent-plane' as const,\n exactSeatAnchorCount: this.perspectiveSeatProjected.size,\n depthSorted: true as const,\n },\n } : {}),\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.updateSeatGroupVisibility();\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.exportMode) return;\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.exportMode\n ? Math.max(this.effScale(), BLOCK_MELT_TOP + 0.01, LABEL_SCALE)\n : 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 // Reveal/hide the per-seat accessibility glyphs for this zoom BEFORE the\n // cache decision below, so the seat-layer bitmap bakes them in/out to match.\n this.updateAccessGlyphs(scale);\n const shouldCache = !this.exportMode && scale < CACHE_THRESHOLD;\n // Perspective section overviews deliberately paint only the bounded shells;\n // the entire native seat layer is opacity 0. Do not synchronously rebuild a\n // 14k-node bitmap that cannot contribute a pixel. If a prior flat overview\n // cache exists it may remain dormant; otherwise disable its hit canvas until\n // the camera crosses into the live-seat rung.\n const suppressPerspectiveSeatCache = this.viewMode === 'perspective'\n && this.hasSections\n && this.seats.length > 2_500\n && shouldCache;\n if (suppressPerspectiveSeatCache) {\n this.seatLayer.listening(false);\n return;\n }\n if (shouldCache && !this.cached) {\n this.cacheSeatLayer();\n } else if (!shouldCache && (this.cached || !this.seatLayer.listening())) {\n // Reveal live seats without Konva's deep cache wipe: releasing only the\n // overview bitmap keeps every seat's local transform/clientRect warm, so\n // the first melt into a section paints at ordinary pan cost (OV-80).\n if (this.cached) this.releaseSeatLayerBitmap();\n this.seatLayer.listening(!this.exportMode);\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 // A cached overview is one pan-able whole-venue bitmap; never bake it from\n // a prior detail view's culled section set.\n this.updateSeatGroupVisibility();\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 * Drop the seat-layer overview bitmap while PRESERVING every descendant's\n * cached local transform + clientRect.\n *\n * Konva's public `Layer.clearCache()` releases the bitmap and then runs a deep\n * `_clearSelfAndDescendantCache()` that clears those caches on all 14k seat\n * nodes. Recomputing them on the single frame the melt first reveals a section's\n * live seats is the ~480ms first-drill stall (OV-80). A camera glide only marks\n * each seat's ABSOLUTE_TRANSFORM dirty (recomputed lazily at ordinary pan cost)\n * and never moves a seat's LOCAL transform, so the local caches stay valid —\n * keeping them lets the first melt paint at pan cost, matching the ~17ms of\n * every subsequent glide on the same section. Any edit that actually moves a\n * seat invalidates its own transform cache through the attr setter, so only\n * still-valid caches survive here.\n */\n private releaseSeatLayerBitmap(): void {\n const layer = this.seatLayer as unknown as {\n _cache: Map<\n 'canvas',\n {\n scene: { _canvas: HTMLCanvasElement };\n filter: { _canvas: HTMLCanvasElement };\n hit: { _canvas: HTMLCanvasElement };\n }\n >;\n };\n const entry = layer._cache.get('canvas');\n if (!entry) return;\n Konva.Util.releaseCanvas(entry.scene._canvas, entry.filter._canvas, entry.hit._canvas);\n layer._cache.delete('canvas');\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 // Same warm-cache-preserving reveal as updateLOD() (OV-80): a returning\n // tab already on the live-seat rung keeps its seat transforms cached.\n this.releaseSeatLayerBitmap();\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 /**\n * Resolve every buyer-visible image requested by the current chart. Export\n * callers get a hard error with the affected layer name; the interactive\n * renderer never calls this and retains its existing best-effort behaviour.\n */\n async ready(): Promise<void> {\n const generation = this.assetGeneration;\n const fontSet = typeof document !== 'undefined' && 'fonts' in document\n ? document.fonts\n : null;\n await Promise.all([\n ...this.assetPromises.slice(),\n ...(fontSet ? [\n fontSet.ready.then(() => undefined),\n fontSet.load('700 24px Inter').then(() => undefined),\n fontSet.load('600 12px \"JetBrains Mono\"').then(() => undefined),\n ] : []),\n ]);\n if (generation !== this.assetGeneration) {\n throw new Error('The chart changed while its export assets were loading.');\n }\n if (this.assetErrors.length) {\n throw new Error(`Export stopped because ${this.assetErrors.join(' ')}`);\n }\n if (this.exportMode) {\n this.fitExportContent();\n this.forceDraw();\n }\n }\n\n /** Exact visible scene bounds in chart coordinates after fonts/assets exist. */\n private exportSceneBounds(): { x: number; y: number; width: number; height: number } {\n const rects = [this.bgLayer, this.seatLayer, this.overlayLayer]\n .map((layer) => layer.getClientRect({ relativeTo: this.stage }))\n .filter((rect) => rect.width > 0 && rect.height > 0);\n if (!rects.length) return this.bounds;\n const minX = Math.min(...rects.map((rect) => rect.x));\n const minY = Math.min(...rects.map((rect) => rect.y));\n const maxX = Math.max(...rects.map((rect) => rect.x + rect.width));\n const maxY = Math.max(...rects.map((rect) => rect.y + rect.height));\n return {\n x: minX,\n y: minY,\n width: Math.max(1, maxX - minX),\n height: Math.max(1, maxY - minY),\n };\n }\n\n /** Fit exact rendered nodes, including rotated text/decor, with pixel padding. */\n private fitExportContent(): void {\n if (!this.exportMode) return;\n const width = this.stage.width();\n const height = this.stage.height();\n const padding = Math.max(12, Math.min(36, Math.min(width, height) * 0.025));\n const fit = () => {\n const bounds = this.exportSceneBounds();\n const availableWidth = Math.max(1, width - padding * 2);\n const availableHeight = Math.max(1, height - padding * 2);\n const scale = Math.min(availableWidth / bounds.width, availableHeight / bounds.height) || 1;\n this.fitScale = scale;\n this.stage.scale({ x: scale, y: scale });\n this.stage.position({\n x: (width - bounds.width * scale) / 2 - bounds.x * scale,\n y: (height - bounds.height * scale) / 2 - bounds.y * scale,\n });\n this.afterViewChange();\n };\n // The first fit can rebuild viewport labels; a second pass includes their\n // exact font metrics and rotated boxes in the final frame.\n fit();\n fit();\n }\n\n /**\n * Capture a clean, opaque fixed-size canvas. The CSS host background is\n * painted explicitly because Konva layers themselves are transparent.\n */\n captureCanvas(): HTMLCanvasElement {\n if (!this.exportMode) {\n throw new Error('captureCanvas() is available only on a renderer created with exportMode.');\n }\n this.forceDraw();\n let scene: HTMLCanvasElement;\n try {\n scene = this.stage.toCanvas({ pixelRatio: 1, imageSmoothingEnabled: true });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new Error(`The chart canvas could not be captured. A buyer-visible image may block export. ${detail}`);\n }\n const canvas = document.createElement('canvas');\n canvas.width = this.stage.width();\n canvas.height = this.stage.height();\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas 2D is unavailable; this browser cannot create an export.');\n context.fillStyle = this.canvasBackground;\n context.fillRect(0, 0, canvas.width, canvas.height);\n try {\n context.drawImage(scene, 0, 0);\n } finally {\n scene.width = 1;\n scene.height = 1;\n }\n return canvas;\n }\n\n private updateFreeTextVisibility(): void {\n const effectiveScale = this.exportMode\n ? Math.max(this.effScale(), LABEL_SCALE)\n : this.effScale();\n for (const { objectId, node, backdrop, 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 const visible = !gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale);\n node.visible(visible);\n backdrop?.visible(visible);\n }\n // Vector venue icons share the free-text rendered-size floor.\n for (const { node, fontSize } of this.iconNodeById.values()) {\n node.visible(isBookableLabelLegibleAtScale(fontSize, effectiveScale));\n }\n }\n\n /** OV-45(a): resolve authored row-letter labels for the buyer/preview map, in\n * world space, matching the Designer's placement contract (start/end/both/none\n * preset, a free-drag `position` that wins over the preset, rotation, and\n * labelStyle colour/size fed through the same auto-contrast guard). Segmented\n * rows keep their own logical-label handling and are resolved by their owner. */\n private buildRowLabelPlan(view: ChartDoc): void {\n this.rowLabelPlan = [];\n const background = this.theme.background ?? '#0e1117';\n const seatsByRow = new Map<string, ExpandedSeat[]>();\n for (const seat of this.seats) {\n if (seat.kind === 'booth') continue;\n const key = seat.logicalRowId ?? seat.rowId;\n (seatsByRow.get(key) ?? seatsByRow.set(key, []).get(key)!).push(seat);\n }\n const seatOrder = (seat: ExpandedSeat): number => seat.logicalSeatIndex\n ?? Number(seat.id.split(':').pop() ?? 0);\n for (const obj of view.objects) {\n if (obj.type !== 'row') continue;\n // A segmented row paints ONE logical label, owned by its first component.\n if (obj.segmentedRow && obj.segmentedRow.componentIndex !== 0) continue;\n const presentation = obj.segmentedRow?.labelPresentation ?? obj.labelPresentation;\n if (presentation?.visible === false || presentation?.positionPreset === 'none') continue;\n const key = obj.segmentedRow ? obj.segmentedRow.groupId : obj.id;\n const seats = (seatsByRow.get(key) ?? []).slice().sort((a, b) => seatOrder(a) - seatOrder(b));\n if (!seats.length) continue;\n const first = seats[0];\n const last = seats[seats.length - 1];\n const labelStyle = presentation?.labelStyle;\n const ink = stateAwareBookableLabelInk(\n background,\n labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? '#e6e9f0',\n AUTHORED_LABEL_MIN_CONTRAST,\n );\n const fontSize = labelStyle?.size ?? 12;\n const rotation = presentation?.rotation ?? 0;\n const text = obj.segmentedRow?.displayLabel ?? obj.displayLabel ?? obj.label;\n const opacity = this.objectFilteredOut(obj) ? 0.15 : 1;\n const push = (x: number, y: number, automaticAway?: Point) => this.rowLabelPlan.push({\n text, x, y, rotation, fontSize, ink, opacity, ...(automaticAway ? { automaticAway } : {}),\n });\n if (presentation?.position) {\n // Free-drag wins: the stored point is the label's visual centre (WYSIWYG\n // with the Designer canvas and its placement handle).\n push(presentation.position.x, presentation.position.y);\n continue;\n }\n const gap = this.seatR + 12;\n const preset = presentation?.positionPreset ?? 'start';\n if (preset === 'start' || preset === 'both') {\n const radians = (obj.rotation * Math.PI) / 180;\n const away = { x: -Math.cos(radians), y: -Math.sin(radians) };\n push(first.x + away.x * gap, first.y + away.y * gap, away);\n }\n if (preset === 'end' || preset === 'both') {\n // Curved rows finish on a different tangent from the one they start on.\n const radians = ((obj.rotation + obj.curve) * Math.PI) / 180;\n const away = { x: Math.cos(radians), y: Math.sin(radians) };\n push(last.x + away.x * gap, last.y + away.y * gap, away);\n }\n }\n }\n\n /** Axis-aligned world bounds of a centred, potentially rotated row label. */\n private rowLabelBox(\n label: Text,\n position: Point,\n padding = ROW_LABEL_CLEARANCE,\n ): WorldBox {\n const radians = (label.rotation() * Math.PI) / 180;\n const cos = Math.abs(Math.cos(radians));\n const sin = Math.abs(Math.sin(radians));\n const halfWidth = (label.width() * cos + label.height() * sin) / 2 + padding;\n const halfHeight = (label.width() * sin + label.height() * cos) / 2 + padding;\n return {\n x: position.x - halfWidth,\n y: position.y - halfHeight,\n width: halfWidth * 2,\n height: halfHeight * 2,\n };\n }\n\n /**\n * Keep an automatic start/end label out of seat markers and already-painted\n * text. The authored point is never altered. Candidates are deliberately\n * bounded and deterministic: the closest clear offset wins; if a chart is so\n * dense that none is clear, the least-colliding candidate wins so the required\n * row label remains present rather than being silently dropped.\n */\n private resolveAutomaticRowLabelPosition(\n label: Text,\n plan: RowLabelPlanEntry,\n occupiedText: WorldBoxIndex,\n ): Point {\n const base = { x: plan.x, y: plan.y };\n const away = plan.automaticAway;\n if (!away) return base;\n const normal = { x: -away.y, y: away.x };\n const step = Math.max(7, Math.min(16, plan.fontSize * 0.75));\n const offsets: Point[] = [{ x: 0, y: 0 }];\n for (let ring = 1; ring <= 4; ring++) {\n const distance = step * ring;\n offsets.push(\n { x: normal.x * distance, y: normal.y * distance },\n { x: -normal.x * distance, y: -normal.y * distance },\n { x: away.x * distance, y: away.y * distance },\n { x: (away.x + normal.x) * distance, y: (away.y + normal.y) * distance },\n { x: (away.x - normal.x) * distance, y: (away.y - normal.y) * distance },\n );\n }\n\n let best = base;\n let bestCollisions = Infinity;\n let bestDistance = Infinity;\n for (const offset of offsets) {\n const candidate = { x: base.x + offset.x, y: base.y + offset.y };\n const box = this.rowLabelBox(label, candidate);\n const seatCollisions = this.seatIndex\n ? queryRect(this.seatIndex, box, { mode: 'overlap' }).length\n : 0;\n const collisions = seatCollisions + occupiedText.collisionCount(box);\n const distance = Math.hypot(offset.x, offset.y);\n if (collisions < bestCollisions || (collisions === bestCollisions && distance < bestDistance)) {\n best = candidate;\n bestCollisions = collisions;\n bestDistance = distance;\n }\n if (collisions === 0) break;\n }\n return best;\n }\n\n /** Row labels never carry status; the buyer just dims them under the same\n * category/price filters that dim their seats. */\n private objectFilteredOut(obj: { categoryKey?: string }): boolean {\n const key = obj.categoryKey;\n if (!key) return false;\n return Boolean((this.categoryHighlight && key !== this.categoryHighlight)\n || (this.categoryFilter && !this.categoryFilter.has(key)));\n }\n\n private updateLabels(): void {\n const effectiveScale = this.exportMode\n ? Math.max(this.effScale(), LABEL_SCALE)\n : 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 && Boolean(shape?.isVisible())\n && this.focusedSeatOpacity(id, shape?.getAbsoluteOpacity() ?? 1) >= 0.5,\n );\n }\n this.labelGroup.destroyChildren();\n this.labelLiftGroups.clear();\n this.seatLabelById.clear();\n if (!show) {\n this.overlayLayer.batchDraw();\n return;\n }\n let count = 0;\n for (const seat of this.visibleSeatCandidates()) {\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 const screen = this.worldToScreen(seat);\n if (screen.x < -20 || screen.x > this.stage.width() + 20\n || screen.y < -20 || screen.y > this.stage.height() + 20) continue;\n // An accessible seat shows its accommodation glyph in place of the seat\n // number (the glyph replaces the number), and keeps its semantic ring.\n if (this.accessGlyphById.has(seat.id) && this.accessGlyphShouldShow(seat.id)) continue;\n const shape = this.circleById.get(seat.id);\n if (!shape?.isVisible() || this.focusedSeatOpacity(seat.id, shape.getAbsoluteOpacity()) < 0.5) continue;\n const status = this.statusById.get(seat.id) ?? 'free';\n const labelPoint = this.renderedSeatPoint(seat);\n const perspectiveScale = this.viewMode === 'perspective'\n ? this.perspectiveSeatScale.get(seat.id) ?? 1\n : 1;\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: labelPoint.x, y: labelPoint.y, listening: false });\n cue.scale({ x: perspectiveScale, y: perspectiveScale });\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.seatLabelContainer(seat.id).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: labelPoint.x,\n y: labelPoint.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 t.scale({ x: perspectiveScale, y: perspectiveScale });\n this.seatLabelContainer(seat.id).add(t);\n this.seatLabelById.set(seat.id, t);\n if (++count >= MAX_LABELS) break;\n }\n // OV-45(a): authored row letters, world-space like seat labels, at the seats\n // rung. Culled by screen bounds; centred and honouring per-row rotation/style.\n // Automatic start/end labels avoid neighbouring inventory and other visible\n // copy. Free-drag positions remain exact WYSIWYG authoring coordinates.\n const occupiedText = new WorldBoxIndex();\n for (const { node } of this.freeTextById.values()) {\n if (!node.isVisible()) continue;\n const box = node.getClientRect({\n relativeTo: this.bgLayer,\n skipShadow: true,\n skipStroke: true,\n });\n occupiedText.insert({\n x: box.x - ROW_LABEL_CLEARANCE,\n y: box.y - ROW_LABEL_CLEARANCE,\n width: box.width + ROW_LABEL_CLEARANCE * 2,\n height: box.height + ROW_LABEL_CLEARANCE * 2,\n });\n }\n for (const rl of this.rowLabelPlan) {\n const screen = this.worldToScreen({ x: rl.x, y: rl.y });\n if (screen.x < -40 || screen.x > this.stage.width() + 40\n || screen.y < -40 || screen.y > this.stage.height() + 40) continue;\n const t = new Text({\n x: rl.x,\n y: rl.y,\n text: rl.text,\n fontSize: rl.fontSize,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: rl.ink,\n rotation: rl.rotation,\n opacity: rl.opacity,\n shadowColor: '#05070c',\n shadowBlur: rl.ink.toLowerCase() === '#ffffff' ? 5 : 0,\n shadowOpacity: rl.ink.toLowerCase() === '#ffffff' ? 0.8 : 0,\n shadowForStrokeEnabled: false,\n listening: false,\n perfectDrawEnabled: false,\n });\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n const resolved = this.resolveAutomaticRowLabelPosition(t, rl, occupiedText);\n t.position(resolved);\n t.setAttr('rowLabel', true);\n occupiedText.insert(this.rowLabelBox(t, resolved));\n this.labelGroup.add(t);\n }\n // Keep freshly-built seat labels upright under the iso layer skew.\n if (this.isoT > 0 && this.viewMode !== 'perspective') 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","import type {\n Category,\n ChartDoc,\n ChartObject,\n ChartReferenceImage,\n Floor,\n} from './types';\n\ntype BackgroundOwner = Pick<ChartDoc, 'referenceImage' | 'backgroundImage'>\n | Pick<Floor, 'referenceImage' | 'backgroundImage'>;\n\n/**\n * Canonical trace lookup with backward compatibility for documents authored\n * before reference and buyer backgrounds became separate fields.\n *\n * Any historical `backgroundImage` carrying a private `assetId` is trace-only,\n * even if it also contains a URL. That fail-closed rule prevents a mistakenly\n * persisted runtime URL from making a private blueprint buyer-visible.\n */\nexport function traceReferenceImage(owner: BackgroundOwner): ChartReferenceImage | undefined {\n return owner.referenceImage ?? (owner.backgroundImage?.assetId ? owner.backgroundImage : undefined);\n}\n\n/** Buyer-visible aesthetic background; private asset-backed values fail closed. */\nexport function buyerBackgroundImage(owner: BackgroundOwner): ChartReferenceImage | undefined {\n const background = owner.backgroundImage;\n return background?.url && !background.assetId ? background : undefined;\n}\n\nfunction buyerBackgroundProjection(owner: BackgroundOwner): ChartReferenceImage | undefined {\n const background = buyerBackgroundImage(owner);\n if (!background?.url) return undefined;\n // Calibration and derived source scale are private authoring evidence. Even a\n // historical URL-only layer must not expose source coordinates to buyers.\n const { calibration: _calibration, derivedScale: _derivedScale, assetId: _assetId, ...placement } = background;\n return placement;\n}\n\n/**\n * Promote historical private `backgroundImage.assetId` values into the\n * canonical `referenceImage` field in place. The migration is deterministic,\n * keeps placement/calibration bytes intact, and never overwrites an explicit\n * canonical trace. A conflicting second legacy asset is left in place so\n * validation can report it instead of silently dropping authored data.\n */\nexport function migrateLegacyBackgroundLayersInPlace(doc: ChartDoc): ChartDoc {\n const migrate = (owner: BackgroundOwner): void => {\n const legacy = owner.backgroundImage;\n if (!legacy?.assetId) return;\n if (!owner.referenceImage) {\n owner.referenceImage = legacy;\n owner.backgroundImage = undefined;\n }\n };\n migrate(doc);\n for (const floor of doc.floors ?? []) migrate(floor);\n return doc;\n}\n\nfunction buyerObject(object: ChartObject): ChartObject {\n const clean = { ...object } as ChartObject & Record<string, unknown>;\n // Private source ids, source hashes and scan provenance are authoring-only.\n delete clean.referenceScan;\n delete clean.referenceInventorySource;\n delete clean.referenceSource;\n delete clean.referenceInventoryExclusion;\n delete clean.editor;\n return clean;\n}\n\nfunction buyerCategory(category: Category): Category {\n const clean = { ...category };\n delete clean.referenceCategorySource;\n return clean;\n}\n\n/**\n * Produce the document a buyer is allowed to receive. This is deliberately a\n * projection, not a mutation: immutable publications and organizer drafts keep\n * their trace evidence, while every public response loses the trace bitmap,\n * calibration/source coordinates and object/category reference provenance.\n */\nexport function buyerFacingChartDoc(doc: ChartDoc): ChartDoc {\n const buyerBackground = buyerBackgroundProjection(doc);\n const floors = doc.floors?.map((floor) => ({\n ...floor,\n objects: floor.objects.map(buyerObject),\n referenceImage: undefined,\n backgroundImage: buyerBackgroundProjection(floor),\n }));\n return {\n ...doc,\n categories: doc.categories.map(buyerCategory),\n objects: doc.objects.map(buyerObject),\n referenceImage: undefined,\n backgroundImage: buyerBackground,\n ...(floors ? { floors } : {}),\n };\n}\n\n/** True when a scope has two different trace candidates and cannot be migrated safely. */\nexport function hasConflictingLegacyTrace(owner: BackgroundOwner): boolean {\n return !!owner.referenceImage?.assetId\n && !!owner.backgroundImage?.assetId\n && owner.referenceImage.assetId !== owner.backgroundImage.assetId;\n}\n","// Venue wayfinding icon registry.\n//\n// Icons are authored as single-color vector paths in a 24×24 viewBox, drawn in a\n// consistent stroke style (Lucide/Material-Symbols aesthetic — 2-unit stroke,\n// round caps/joins, no fill). Both the Designer canvas and the buyer\n// SeatmapRenderer draw the SAME path so a placed marker looks identical\n// everywhere, unlike the emoji glyphs it replaces (which rendered per-OS).\n//\n// Identity + backward compatibility: a placed icon is a TextObject with\n// `semanticKind:'icon'`. NEW placements also carry `iconKey` referencing an entry\n// here and render as a vector Path. LEGACY placements carry only an emoji in\n// `text` (no iconKey) and keep rendering through the shared text/glyph path. The\n// two coexist forever; nothing rewrites old charts.\n\n/** Logical grouping for the Designer palette (plain-language section headers). */\nexport type VenueIconGroup = 'facilities' | 'food-drink' | 'navigation' | 'accessibility';\n\nexport interface VenueIcon {\n /** Stable registry key persisted on the object as `iconKey`. Never shown to users. */\n key: string;\n /** Plain-language name (button label, tooltip, accessible name). */\n label: string;\n group: VenueIconGroup;\n /** SVG path `d` in a 0 0 24 24 viewBox, stroke-styled (fill:none). */\n path: string;\n}\n\n/** The viewBox side length every icon path is authored against. */\nexport const VENUE_ICON_VIEWBOX = 24;\n/** Stroke width in viewBox units; scales with the object's size like a font. */\nexport const VENUE_ICON_STROKE = 2;\n\n/** Human-readable section headers for the palette groups. */\nexport const VENUE_ICON_GROUP_LABELS: Record<VenueIconGroup, string> = {\n facilities: 'Facilities',\n 'food-drink': 'Food & drink',\n navigation: 'Getting around',\n accessibility: 'Accessibility',\n};\n\n/** Display order of the groups in the palette. */\nexport const VENUE_ICON_GROUP_ORDER: VenueIconGroup[] = [\n 'facilities',\n 'food-drink',\n 'navigation',\n 'accessibility',\n];\n\n// Shared sub-marks reused across a couple of icons.\nconst WHEELCHAIR =\n 'M13 4.6a1.6 1.6 0 1 0-3.2 0 1.6 1.6 0 0 0 3.2 0 M11 6.5V13h5l2.4 6 M15 16.4A5 5 0 1 1 9 11.3';\n\nexport const VENUE_ICONS: VenueIcon[] = [\n // ---- Facilities --------------------------------------------------------\n {\n key: 'restroom-men',\n label: \"Men's restroom\",\n group: 'facilities',\n path: 'M16 7a4 4 0 1 0-8 0 4 4 0 0 0 8 0 M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2',\n },\n {\n key: 'restroom-women',\n label: \"Women's restroom\",\n group: 'facilities',\n path: 'M15 5a3 3 0 1 0-6 0 3 3 0 0 0 6 0 M12 8l-4 10h8l-4-10 M10 18v4 M14 18v4',\n },\n {\n key: 'restroom-accessible',\n label: 'Accessible restroom',\n group: 'facilities',\n path: WHEELCHAIR,\n },\n {\n key: 'first-aid',\n label: 'First aid',\n group: 'facilities',\n path: 'M5 4h14a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z M12 8v8 M8 12h8',\n },\n {\n key: 'coat-check',\n label: 'Coat check',\n group: 'facilities',\n path: 'M12 6a2 2 0 0 1 0-4 2 2 0 0 1 1.6 3.2L21 13H3l8.4-7.8 M3 13h18',\n },\n {\n key: 'atm',\n label: 'ATM / cash',\n group: 'facilities',\n path: 'M2 6h20v12H2V6Z M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0 M6 9h.01 M18 15h.01',\n },\n {\n key: 'info',\n label: 'Info point',\n group: 'facilities',\n path: 'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M12 11v5 M12 8h.01',\n },\n {\n key: 'lost-found',\n label: 'Lost & found',\n group: 'facilities',\n path: 'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14 M16 16l5 5 M9 8.5a2 2 0 1 1 3 1.7c-.8.5-1 .8-1 1.8 M11 15h.01',\n },\n {\n key: 'restrooms',\n label: 'Restrooms',\n group: 'facilities',\n path: 'M6 3h12a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M9 18v-3.5a3 3 0 0 1 6 0V18',\n },\n {\n key: 'charging',\n label: 'Charging point',\n group: 'facilities',\n path: 'M3 8h13v8H3V8Z M16 10h3v4h-3 M9.6 9l-2 3.5h2.5l-1.5 3',\n },\n {\n key: 'smoking',\n label: 'Smoking area',\n group: 'facilities',\n path: 'M2 15h13v3H2v-3Z M18 16h2 M19 8c0 1 1 1.5 1 2.5S19 12 19 13',\n },\n {\n key: 'no-smoking',\n label: 'No smoking',\n group: 'facilities',\n path: 'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M5.6 5.6l12.8 12.8 M7 13h6v2H7v-2Z',\n },\n // ---- Food & drink ------------------------------------------------------\n {\n key: 'food',\n label: 'Food',\n group: 'food-drink',\n path: 'M7 3v6a2 2 0 0 0 4 0V3 M9 11v10 M17 3c-1.6 1-2.2 3-2.2 6 0 2 .9 3.2 2.2 3.6V21',\n },\n {\n key: 'bar',\n label: 'Bar',\n group: 'food-drink',\n path: 'M4 5h16l-8 8-8-8Z M12 13v6 M8 20h8',\n },\n {\n key: 'coffee',\n label: 'Café / coffee',\n group: 'food-drink',\n path: 'M4 8h13v4a5 5 0 0 1-5 5H9a5 5 0 0 1-5-5V8Z M17 9h2a2 2 0 0 1 0 4h-2 M8 2v2 M11 2v2 M4 21h14',\n },\n {\n key: 'water',\n label: 'Water / drinks',\n group: 'food-drink',\n path: 'M12 22a7 7 0 0 1-7-7c0-5 7-12 7-12s7 7 7 12a7 7 0 0 1-7 7Z',\n },\n {\n key: 'merch',\n label: 'Merch / shop',\n group: 'food-drink',\n path: 'M6 8h12l-1 12H7L6 8Z M9 8V6a3 3 0 0 1 6 0v2',\n },\n {\n key: 'screen',\n label: 'Screen',\n group: 'facilities',\n path: 'M3 4h18v12H3V4Z M9 20h6 M12 16v4 M10 8l4 2-4 2V8Z',\n },\n {\n key: 'sound-booth',\n label: 'Sound booth',\n group: 'facilities',\n path: 'M6 4v16 M6 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4 M12 4v16 M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M18 4v16 M18 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4',\n },\n // ---- Getting around ----------------------------------------------------\n {\n key: 'entrance',\n label: 'Entrance',\n group: 'navigation',\n path: 'M14 3h5a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-5 M3 12h11 M10 8l4 4-4 4',\n },\n {\n key: 'exit',\n label: 'Exit',\n group: 'navigation',\n path: 'M10 3H5a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h5 M14 12h7 M17 8l4 4-4 4',\n },\n {\n key: 'emergency-exit',\n label: 'Emergency exit',\n group: 'navigation',\n path: 'M14 4.6a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0 M12.5 8l-3.5 2 1.6 3.6-2 4.4 M12.5 10l3.5 1.5 M9 10.5l-3.5 1 M15 12h6 M18 9l3 3-3 3',\n },\n {\n key: 'stairs',\n label: 'Stairs',\n group: 'navigation',\n path: 'M3 20v-4h4v-4h4v-4h4V4h5',\n },\n {\n key: 'elevator',\n label: 'Elevator',\n group: 'navigation',\n path: 'M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M8 11l1.5-2 1.5 2 M8 14l1.5 2 1.5-2 M15 8v8',\n },\n {\n key: 'parking',\n label: 'Parking',\n group: 'navigation',\n path: 'M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M9 17V7h4a3 3 0 0 1 0 6H9',\n },\n // ---- Accessibility -----------------------------------------------------\n {\n key: 'wheelchair',\n label: 'Wheelchair access',\n group: 'accessibility',\n path: WHEELCHAIR,\n },\n {\n key: 'hearing',\n label: 'Hearing assistance',\n group: 'accessibility',\n path: 'M8 20a4 4 0 0 1-2-3c0-1 .5-2 .5-3a4.5 4.5 0 1 1 9 0c0 1.4-1 2-2 2.4-1.2.5-1.5 1-1.5 2.2 M17 6a5 5 0 0 1 1 6 M19.5 4a8 8 0 0 1 1.2 9',\n },\n];\n\n/**\n * Décor-stamp-only glyphs. Some Designer décor presets (e.g. a structural wall)\n * are not buyer-placeable wayfinding markers, so they must NOT appear in the\n * IconPalette / VENUE_ICONS registry — but their flyout stamp button still needs\n * a vector preview in the same stroke language so the Décor row reads as one\n * system (OV-82). Authored against the same 0 0 24 24 viewBox / 2-unit stroke.\n */\nexport const DECOR_STAMP_ICON_PATHS: Record<string, string> = {\n // Running-bond brick courses — a plain structural divider.\n wall: 'M3 5h18v14H3V5Z M3 9.7h18 M3 14.3h18 M9 5v4.7 M15 5v4.7 M6 9.7v4.6 M12 9.7v4.6 M18 9.7v4.6 M9 14.3v4.7 M15 14.3v4.7',\n};\n\nconst BY_KEY = new Map<string, VenueIcon>(VENUE_ICONS.map((icon) => [icon.key, icon]));\n\n/** Resolve a registry entry by key, or undefined for legacy/unknown keys. */\nexport function venueIcon(key: string | undefined | null): VenueIcon | undefined {\n return key ? BY_KEY.get(key) : undefined;\n}\n\n/** Vector path for a key, or undefined when the key is not in the registry. */\nexport function venueIconPath(key: string | undefined | null): string | undefined {\n return venueIcon(key)?.path;\n}\n\n/** True when `key` names a real registry icon (MCP/validation fail-closed guard). */\nexport function isVenueIconKey(key: unknown): key is string {\n return typeof key === 'string' && BY_KEY.has(key);\n}\n\n/** Every valid registry key (for MCP enum + validation messages). */\nexport const VENUE_ICON_KEYS: string[] = VENUE_ICONS.map((icon) => icon.key);\n","/**\n * Pure-TypeScript spatial index for seat hit-testing.\n *\n * WHY THIS EXISTS\n * ---------------\n * `src/engine/SeatmapRenderer.ts` currently leans on Konva's built-in hit graph\n * (the `listening` property, ~58 call sites) for \"which seat did the pointer\n * land on\". No other renderer we care about ships an equivalent: React Native\n * Skia has nothing at all, and Flutter / SwiftUI / Compose canvases all expect\n * the app to own hit-testing. So the index has to exist on every path — and on\n * the web it additionally lets us drop Konva's hit graph, which is a real win at\n * 5k–13k seats (no per-seat hit-canvas rasterisation, no hit-graph traversal).\n *\n * This module is deliberately DEPENDENCY-FREE: no DOM, no Konva, no browser\n * globals. It runs unchanged in a Web Worker, in workerd, and under React\n * Native. All coordinates are WORLD space — converting screen→world is the\n * caller's job, exactly as `SeatmapRenderer.screenToWorld` does today.\n *\n * STRUCTURE: uniform grid, not a quadtree\n * ---------------------------------------\n * Seats in a venue chart are close to uniformly dense by construction — they sit\n * in rows on a near-regular pitch. That is the single case a uniform grid is\n * optimal for, and it beats a quadtree on every axis that matters here:\n * O(n) build with no rebalancing, flat typed-array storage (one contiguous\n * scan per query, no pointer chasing), and O(1) expected candidates per point\n * query. A quadtree only starts to pay when density varies by orders of\n * magnitude across the extent, which a seating chart does not do. If a future\n * chart shape ever breaks that assumption, `gridStats()` exposes the occupancy\n * numbers needed to prove it before reaching for a tree.\n *\n * Each seat is inserted into EVERY cell its axis-aligned bounding box overlaps\n * (not just the cell holding its centre). That is what makes {@link hitTest}\n * examine exactly one cell: any seat whose shape contains a point also has an\n * AABB containing that point, so it is guaranteed to be registered in that\n * point's cell.\n */\n\nimport type { ExpandedSeat, Point } from './types';\n\n/**\n * Default seat radius in world units. Mirrors `SEAT_RADIUS` in\n * `SeatmapRenderer.ts` and `DesignerController.ts` (both 9). The renderer scales\n * this by `theme.seatScale` clamped to [0.7, 1.6]; callers that do the same must\n * pass the scaled value via {@link BuildOptions.seatRadius} so the index agrees\n * with what is actually drawn.\n */\nexport const DEFAULT_SEAT_RADIUS = 9;\n\n/**\n * Hit geometry for one seat. Real seats are circles; trade-show booths render as\n * rotated rounded rects whose dimensions live on the booth object in the\n * ChartDoc, not on `ExpandedSeat` — so the caller supplies them through\n * {@link BuildOptions.shapeOf} rather than this module reaching for the doc.\n */\nexport type SeatShape =\n | { kind: 'circle'; r: number }\n | { kind: 'rect'; width: number; height: number; rotation?: number };\n\nexport interface BuildOptions {\n /** Radius for circular seats when {@link shapeOf} is absent. Default {@link DEFAULT_SEAT_RADIUS}. */\n seatRadius?: number;\n /**\n * Per-seat hit geometry. Return `null`/`undefined` to fall back to a circle of\n * `seatRadius`. Called exactly once per seat during construction.\n */\n shapeOf?: (seat: ExpandedSeat) => SeatShape | null | undefined;\n /**\n * Upper bound on grid cells, to stop a chart with one far-flung stray object\n * from allocating a huge sparse grid. Default `max(64, 4 * seats.length)`.\n * When the natural cell size would exceed this, cells are grown until it fits.\n */\n maxCells?: number;\n}\n\nexport interface QueryOptions {\n /**\n * Restrict results to seats this predicate accepts — used to reproduce the\n * renderer's `isSelectable(id) || selection.has(id)` gate. Kept as a query\n * argument rather than build state on purpose: seat statuses change on every\n * websocket tick, and the geometry does not.\n */\n filter?: (id: string, seat: ExpandedSeat) => boolean;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface RectQueryOptions extends QueryOptions {\n /**\n * `'center'` (default) keeps a seat when its CENTRE falls inside the rect,\n * bounds inclusive. This is what `SeatmapRenderer.finishMarquee` does today,\n * so it is the default in order to be a drop-in replacement.\n *\n * `'overlap'` keeps a seat when its hit SHAPE intersects the rect at all —\n * the right mode for \"which seats are on screen\" viewport culling and\n * label-rendering passes, where a partially visible seat still counts.\n */\n mode?: 'center' | 'overlap';\n}\n\ninterface IndexedSeat {\n seat: ExpandedSeat;\n shape: SeatShape;\n /** Half-extents of the shape's axis-aligned bounding box (rotation applied). */\n hx: number;\n hy: number;\n}\n\nexport interface SeatIndex {\n readonly seats: readonly ExpandedSeat[];\n /** @internal */\n readonly entries: readonly IndexedSeat[];\n /** @internal */\n readonly minX: number;\n /** @internal */\n readonly minY: number;\n /** @internal */\n readonly cell: number;\n /** @internal */\n readonly cols: number;\n /** @internal */\n readonly rows: number;\n /** @internal Prefix-sum offsets into {@link items}; length cols*rows+1. */\n readonly cellStart: Int32Array;\n /** @internal Seat indices grouped by cell. */\n readonly items: Int32Array;\n /** @internal Per-seat visit stamps, for dedup across multi-cell scans. */\n readonly stamp: Int32Array;\n /** @internal Monotonically increasing stamp epoch. */\n epoch: number;\n}\n\n/** Axis-aligned half-extents of a shape, accounting for rotation. */\nfunction halfExtents(shape: SeatShape): { hx: number; hy: number } {\n if (shape.kind === 'circle') return { hx: shape.r, hy: shape.r };\n const hw = shape.width / 2;\n const hh = shape.height / 2;\n const rot = shape.rotation ?? 0;\n if (!rot) return { hx: hw, hy: hh };\n const rad = (rot * Math.PI) / 180;\n const c = Math.abs(Math.cos(rad));\n const s = Math.abs(Math.sin(rad));\n return { hx: hw * c + hh * s, hy: hw * s + hh * c };\n}\n\n/** Exact containment test for one seat's hit shape. */\nfunction shapeContains(e: IndexedSeat, px: number, py: number): boolean {\n const dx = px - e.seat.x;\n const dy = py - e.seat.y;\n if (e.shape.kind === 'circle') {\n return dx * dx + dy * dy <= e.shape.r * e.shape.r;\n }\n const rot = e.shape.rotation ?? 0;\n let lx = dx;\n let ly = dy;\n if (rot) {\n // Rotate the point INTO the rect's local frame (i.e. by -rotation).\n const rad = (-rot * Math.PI) / 180;\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n lx = dx * c - dy * s;\n ly = dx * s + dy * c;\n }\n return Math.abs(lx) <= e.shape.width / 2 && Math.abs(ly) <= e.shape.height / 2;\n}\n\n/** Does a seat's hit shape intersect an axis-aligned rect? */\nfunction shapeIntersectsRect(e: IndexedSeat, x0: number, y0: number, x1: number, y1: number): boolean {\n if (e.shape.kind === 'circle') {\n // Closest point on the rect to the circle centre.\n const cx = Math.min(Math.max(e.seat.x, x0), x1);\n const cy = Math.min(Math.max(e.seat.y, y0), y1);\n const dx = e.seat.x - cx;\n const dy = e.seat.y - cy;\n return dx * dx + dy * dy <= e.shape.r * e.shape.r;\n }\n // Rects: separating-axis test over the 4 candidate axes (2 per box). For the\n // unrotated case this degenerates to a plain AABB overlap.\n const rot = e.shape.rotation ?? 0;\n if (!rot) {\n return (\n e.seat.x - e.hx <= x1 && e.seat.x + e.hx >= x0 && e.seat.y - e.hy <= y1 && e.seat.y + e.hy >= y0\n );\n }\n const rad = (rot * Math.PI) / 180;\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n const hw = e.shape.width / 2;\n const hh = e.shape.height / 2;\n // Rect corners in world space.\n const corners: Array<[number, number]> = [\n [-hw, -hh],\n [hw, -hh],\n [hw, hh],\n [-hw, hh],\n ].map(([lx, ly]) => [e.seat.x + lx * c - ly * s, e.seat.y + lx * s + ly * c] as [number, number]);\n const query: Array<[number, number]> = [\n [x0, y0],\n [x1, y0],\n [x1, y1],\n [x0, y1],\n ];\n const axes: Array<[number, number]> = [\n [1, 0],\n [0, 1],\n [c, s],\n [-s, c],\n ];\n for (const [ax, ay] of axes) {\n let minA = Infinity;\n let maxA = -Infinity;\n for (const [px, py] of corners) {\n const d = px * ax + py * ay;\n if (d < minA) minA = d;\n if (d > maxA) maxA = d;\n }\n let minB = Infinity;\n let maxB = -Infinity;\n for (const [px, py] of query) {\n const d = px * ax + py * ay;\n if (d < minB) minB = d;\n if (d > maxB) maxB = d;\n }\n if (maxA < minB || maxB < minA) return false;\n }\n return true;\n}\n\n/**\n * Build a uniform-grid index over `seats`. O(n) in time and memory.\n *\n * CELL SIZE\n * ---------\n * The nominal cell is `4 × maxHalfExtent`, i.e. twice the largest seat's\n * bounding-box width. Two properties fall out of that choice:\n *\n * - A seat's AABB is at most half a cell across, so it lands in at most 2×2 = 4\n * cells. Build stays O(n) with a small constant, and the index does not blow\n * up in memory from duplicated references.\n * - For the default 9px seat radius the cell is 36 world units, versus a real\n * row/seat pitch of roughly 20–26. That works out to ~1–2 seats per occupied\n * cell, so a point query examines about one or two candidates. Halving the\n * cell would quadruple cell count to shave a fraction of a candidate;\n * doubling it would put ~6 seats in every cell. 4× the half-extent is the\n * flat part of that curve.\n *\n * The one pathological input is a chart whose bounds are enormous relative to\n * its seat count — a single stray object parked far from the venue. `maxCells`\n * caps the grid and grows the cell size until it fits, trading query sharpness\n * for bounded memory. Real charts never hit it.\n */\nexport function buildSeatIndex(seats: readonly ExpandedSeat[], opts: BuildOptions = {}): SeatIndex {\n const seatRadius = opts.seatRadius ?? DEFAULT_SEAT_RADIUS;\n const n = seats.length;\n const entries: IndexedSeat[] = new Array(n);\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let maxHalf = 0;\n\n for (let i = 0; i < n; i++) {\n const seat = seats[i];\n const shape = opts.shapeOf?.(seat) ?? { kind: 'circle' as const, r: seatRadius };\n const { hx, hy } = halfExtents(shape);\n entries[i] = { seat, shape, hx, hy };\n if (seat.x - hx < minX) minX = seat.x - hx;\n if (seat.y - hy < minY) minY = seat.y - hy;\n if (seat.x + hx > maxX) maxX = seat.x + hx;\n if (seat.y + hy > maxY) maxY = seat.y + hy;\n if (hx > maxHalf) maxHalf = hx;\n if (hy > maxHalf) maxHalf = hy;\n }\n\n if (n === 0) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n\n // Guard degenerate inputs: zero-extent shapes, or every seat stacked on one\n // point. A cell size of 0 would make the coordinate maths produce NaN.\n const nominal = maxHalf > 0 ? maxHalf * 4 : 1;\n const spanX = Math.max(maxX - minX, 0);\n const spanY = Math.max(maxY - minY, 0);\n const maxCells = Math.max(64, opts.maxCells ?? n * 4);\n\n let cell = nominal;\n let cols = Math.max(1, Math.ceil(spanX / cell) || 1);\n let rows = Math.max(1, Math.ceil(spanY / cell) || 1);\n // Grow the cell until the grid fits the budget. Each doubling quarters the\n // cell count, so this converges in a handful of iterations even for absurd\n // spans, and cannot loop forever once cols and rows both reach 1.\n while (cols * rows > maxCells && (cols > 1 || rows > 1)) {\n cell *= 2;\n cols = Math.max(1, Math.ceil(spanX / cell) || 1);\n rows = Math.max(1, Math.ceil(spanY / cell) || 1);\n }\n\n const cellCount = cols * rows;\n const cellStart = new Int32Array(cellCount + 1);\n\n // Pass 1 — count how many cells each seat's AABB touches.\n let total = 0;\n for (let i = 0; i < n; i++) {\n const e = entries[i];\n const cx0 = clampInt(Math.floor((e.seat.x - e.hx - minX) / cell), 0, cols - 1);\n const cx1 = clampInt(Math.floor((e.seat.x + e.hx - minX) / cell), 0, cols - 1);\n const cy0 = clampInt(Math.floor((e.seat.y - e.hy - minY) / cell), 0, rows - 1);\n const cy1 = clampInt(Math.floor((e.seat.y + e.hy - minY) / cell), 0, rows - 1);\n for (let cy = cy0; cy <= cy1; cy++) {\n for (let cx = cx0; cx <= cx1; cx++) {\n cellStart[cy * cols + cx + 1]++;\n total++;\n }\n }\n }\n\n // Prefix sum → per-cell start offsets.\n for (let c = 0; c < cellCount; c++) cellStart[c + 1] += cellStart[c];\n\n // Pass 2 — scatter seat indices into their cells.\n const items = new Int32Array(total);\n const cursor = cellStart.slice(0, cellCount);\n for (let i = 0; i < n; i++) {\n const e = entries[i];\n const cx0 = clampInt(Math.floor((e.seat.x - e.hx - minX) / cell), 0, cols - 1);\n const cx1 = clampInt(Math.floor((e.seat.x + e.hx - minX) / cell), 0, cols - 1);\n const cy0 = clampInt(Math.floor((e.seat.y - e.hy - minY) / cell), 0, rows - 1);\n const cy1 = clampInt(Math.floor((e.seat.y + e.hy - minY) / cell), 0, rows - 1);\n for (let cy = cy0; cy <= cy1; cy++) {\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = cy * cols + cx;\n items[cursor[c]++] = i;\n }\n }\n }\n\n return {\n seats,\n entries,\n minX,\n minY,\n cell,\n cols,\n rows,\n cellStart,\n items,\n stamp: new Int32Array(n),\n epoch: 0,\n };\n}\n\nfunction clampInt(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n\n/**\n * The seat whose hit shape contains `p`, or null.\n *\n * On overlap — seats drawn close enough that their circles intersect — the seat\n * whose CENTRE is nearest to `p` wins. That matches what a user perceives (you\n * hit the thing you aimed at) and, unlike Konva, is order-independent: Konva's\n * hit graph resolves overlap by draw order, returning the topmost/last-added\n * node regardless of how far off-centre the pointer was.\n */\nexport function hitTest(index: SeatIndex, p: Point, opts: QueryOptions = {}): string | null {\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n const cx = Math.floor((p.x - minX) / cell);\n const cy = Math.floor((p.y - minY) / cell);\n if (cx < 0 || cy < 0 || cx >= cols || cy >= rows) return null;\n\n // Every seat containing p has an AABB containing p, so it is registered in\n // p's own cell — one cell is a complete candidate set.\n const c = cy * cols + cx;\n const end = cellStart[c + 1];\n let best = -1;\n let bestD = Infinity;\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n if (!shapeContains(e, p.x, p.y)) continue;\n const dx = p.x - e.seat.x;\n const dy = p.y - e.seat.y;\n const d = dx * dx + dy * dy;\n // Ties break toward the lower seat index so the answer never depends on\n // grid layout or cell-scan order — it matches a plain array-order scan.\n if (d < bestD || (d === bestD && i < best)) {\n bestD = d;\n best = i;\n }\n }\n return best < 0 ? null : entries[best].seat.id;\n}\n\n/**\n * Nearest seat CENTRE strictly within `radius` world units of `p`, or null.\n *\n * This is the near-miss rescue from `SeatmapRenderer.nearestSeatToScreen`,\n * lifted verbatim. The caller computes the radius the same way the renderer\n * does today:\n *\n * const reachWorld = seatR + slopPx / stageScale; // SEAT_TAP_SLOP_PX = 14\n * nearestWithin(index, screenToWorld(pointer), reachWorld, { filter });\n *\n * Note the comparison is STRICTLY less-than, mirroring the renderer's\n * `bestD = reachWorld; ... if (d < bestD)` loop: a seat centre sitting exactly\n * `reachWorld` away does not qualify. Distance is measured to the seat centre,\n * not the shape edge — so for the default circle, \"centre within seatR + slop\"\n * is identical to \"edge within slop\", which is what the renderer's docstring\n * describes.\n */\nexport function nearestWithin(\n index: SeatIndex,\n p: Point,\n radius: number,\n opts: QueryOptions = {},\n): string | null {\n if (!(radius > 0)) return null;\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n\n const cx0 = Math.max(0, Math.floor((p.x - radius - minX) / cell));\n const cx1 = Math.min(cols - 1, Math.floor((p.x + radius - minX) / cell));\n const cy0 = Math.max(0, Math.floor((p.y - radius - minY) / cell));\n const cy1 = Math.min(rows - 1, Math.floor((p.y + radius - minY) / cell));\n if (cx0 > cx1 || cy0 > cy1) return null;\n\n // A seat centre within `radius` of p lies inside the box p ± radius, and a\n // seat is always registered in the cell holding its own centre — so scanning\n // the cells overlapping that box is complete.\n let best = -1;\n let bestD = radius * radius;\n const stamp = index.stamp;\n const ep = ++index.epoch;\n for (let cy = cy0; cy <= cy1; cy++) {\n const rowBase = cy * cols;\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = rowBase + cx;\n const end = cellStart[c + 1];\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n if (stamp[i] === ep) continue; // already considered via another cell\n stamp[i] = ep;\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n const dx = p.x - e.seat.x;\n const dy = p.y - e.seat.y;\n const d = dx * dx + dy * dy;\n // Lower seat index wins ties — identical to the renderer's first-wins\n // `for (const seat of this.seats)` loop.\n if (d < bestD || (d === bestD && i < best)) {\n bestD = d;\n best = i;\n }\n }\n }\n }\n return best < 0 ? null : entries[best].seat.id;\n}\n\n/**\n * Seat ids inside a world-space rect. Negative width/height are normalised, so a\n * marquee dragged up-and-left works without the caller sorting the corners.\n *\n * Default `mode: 'center'` reproduces `SeatmapRenderer.finishMarquee` exactly:\n * a seat is kept when its centre is within the rect, bounds INCLUSIVE. Use\n * `mode: 'overlap'` for viewport culling, where a seat straddling the edge\n * should still be drawn.\n *\n * Results come back in ascending seat-array order, so the output is stable\n * across calls regardless of grid layout.\n */\nexport function queryRect(index: SeatIndex, rect: Rect, opts: RectQueryOptions = {}): string[] {\n const x0 = Math.min(rect.x, rect.x + rect.width);\n const x1 = Math.max(rect.x, rect.x + rect.width);\n const y0 = Math.min(rect.y, rect.y + rect.height);\n const y1 = Math.max(rect.y, rect.y + rect.height);\n const mode = opts.mode ?? 'center';\n\n const { cols, rows, cell, minX, minY, cellStart, items, entries } = index;\n const cx0 = Math.max(0, Math.floor((x0 - minX) / cell));\n const cx1 = Math.min(cols - 1, Math.floor((x1 - minX) / cell));\n const cy0 = Math.max(0, Math.floor((y0 - minY) / cell));\n const cy1 = Math.min(rows - 1, Math.floor((y1 - minY) / cell));\n if (cx0 > cx1 || cy0 > cy1) return [];\n\n const found: number[] = [];\n const stamp = index.stamp;\n const ep = ++index.epoch;\n for (let cy = cy0; cy <= cy1; cy++) {\n const rowBase = cy * cols;\n for (let cx = cx0; cx <= cx1; cx++) {\n const c = rowBase + cx;\n const end = cellStart[c + 1];\n for (let k = cellStart[c]; k < end; k++) {\n const i = items[k];\n if (stamp[i] === ep) continue; // seat spans several cells\n stamp[i] = ep;\n const e = entries[i];\n if (opts.filter && !opts.filter(e.seat.id, e.seat)) continue;\n const ok =\n mode === 'center'\n ? e.seat.x >= x0 && e.seat.x <= x1 && e.seat.y >= y0 && e.seat.y <= y1\n : shapeIntersectsRect(e, x0, y0, x1, y1);\n if (ok) found.push(i);\n }\n }\n }\n found.sort((a, b) => a - b);\n return found.map((i) => entries[i].seat.id);\n}\n\n/**\n * Occupancy stats for the built grid. Diagnostic only — this is the evidence to\n * check before anyone argues the uniform grid has stopped being good enough and\n * a tree is warranted.\n */\nexport function gridStats(index: SeatIndex): {\n cell: number;\n cols: number;\n rows: number;\n cells: number;\n occupiedCells: number;\n refs: number;\n maxPerCell: number;\n meanPerOccupiedCell: number;\n} {\n const cells = index.cols * index.rows;\n let occupied = 0;\n let maxPerCell = 0;\n for (let c = 0; c < cells; c++) {\n const len = index.cellStart[c + 1] - index.cellStart[c];\n if (len > 0) occupied++;\n if (len > maxPerCell) maxPerCell = len;\n }\n const refs = index.items.length;\n return {\n cell: index.cell,\n cols: index.cols,\n rows: index.rows,\n cells,\n occupiedCells: occupied,\n refs,\n maxPerCell,\n meanPerOccupiedCell: occupied ? refs / occupied : 0,\n };\n}\n","import type { Point } from './types';\n\n/** Axis-aligned chart bounds used to derive a stable, document-relative camera. */\nexport interface PerspectiveBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * A deterministic pinhole camera for the projected 2.5D buyer/Designer views.\n * Coordinates stay in chart units so the ordinary Stage camera (pan/zoom) can\n * remain the only screen-space transform.\n */\nexport interface PerspectiveCamera {\n target: Point;\n /** Horizontal distance from target to camera, in chart units. */\n distance: number;\n /** Camera height above the chart datum, in chart units. */\n height: number;\n /** Pinhole focal length, in chart units. */\n focalLength: number;\n /** Small plan rotation which keeps the venue from reading as a flat elevation. */\n yawRad: number;\n}\n\n/** Canvas/Konva affine: x' = a·x + c·y + e; y' = b·x + d·y + f. */\nexport interface Affine2D {\n a: number;\n b: number;\n c: number;\n d: number;\n e: number;\n f: number;\n}\n\nexport interface PerspectivePoint extends Point {\n /** Positive camera-space distance; larger values are farther away. */\n depth: number;\n /** Perspective size multiplier at this point (1 at the camera target). */\n scale: number;\n}\n\n/**\n * Choose a camera from venue bounds rather than fixed pixels. The camera rises\n * above the tallest authored surface, so even the (deliberately generous)\n * 120-m validation ceiling cannot cross the near plane.\n */\nexport function createPerspectiveCamera(\n bounds: PerspectiveBounds,\n maxSurfaceHeightWorld = 0,\n): PerspectiveCamera {\n const span = Math.max(1, bounds.width, bounds.height);\n const target = {\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n };\n const distance = span * 1.55;\n const height = Math.max(span * 0.82, Math.max(0, maxSurfaceHeightWorld) + span * 0.45);\n return {\n target,\n distance,\n height,\n focalLength: Math.hypot(distance, height),\n yawRad: (-8 * Math.PI) / 180,\n };\n}\n\n/** Project one 3D chart point through the pinhole camera. */\nexport function projectPerspectivePoint(\n camera: PerspectiveCamera,\n point: Point,\n heightWorld = 0,\n): PerspectivePoint {\n const dx = point.x - camera.target.x;\n const dy = point.y - camera.target.y;\n const cos = Math.cos(camera.yawRad);\n const sin = Math.sin(camera.yawRad);\n const x = dx * cos - dy * sin;\n const y = dx * sin + dy * cos;\n const translatedY = y - camera.distance;\n const translatedZ = heightWorld - camera.height;\n const cameraLength = Math.hypot(camera.distance, camera.height);\n const depth = (-camera.distance * translatedY - camera.height * translatedZ) / cameraLength;\n const up = (-camera.height * translatedY + camera.distance * translatedZ) / cameraLength;\n // Camera construction keeps authored surfaces in front of the near plane.\n // The clamp is still a fail-safe for malformed data loaded without validation.\n const safeDepth = Math.max(cameraLength * 0.08, depth);\n const scale = camera.focalLength / safeDepth;\n return {\n x: camera.target.x + x * scale,\n y: camera.target.y - up * scale,\n depth: safeDepth,\n scale,\n };\n}\n\nexport function applyAffine(affine: Affine2D, point: Point): Point {\n return {\n x: affine.a * point.x + affine.c * point.y + affine.e,\n y: affine.b * point.x + affine.d * point.y + affine.f,\n };\n}\n\nexport function invertAffine(affine: Affine2D): Affine2D {\n const determinant = affine.a * affine.d - affine.b * affine.c;\n if (!Number.isFinite(determinant) || Math.abs(determinant) < 1e-9) {\n throw new Error('perspective projection produced a singular affine');\n }\n const a = affine.d / determinant;\n const b = -affine.b / determinant;\n const c = -affine.c / determinant;\n const d = affine.a / determinant;\n return {\n a,\n b,\n c,\n d,\n e: -(a * affine.e + c * affine.f),\n f: -(b * affine.e + d * affine.f),\n };\n}\n\n/** Return `left(right(point))`. */\nexport function composeAffine(left: Affine2D, right: Affine2D): Affine2D {\n return {\n a: left.a * right.a + left.c * right.b,\n b: left.b * right.a + left.d * right.b,\n c: left.a * right.c + left.c * right.d,\n d: left.b * right.c + left.d * right.d,\n e: left.a * right.e + left.c * right.f + left.e,\n f: left.b * right.e + left.d * right.f + left.f,\n };\n}\n\n/**\n * First-order projection around one object/section anchor. The height callback\n * may describe a raked surface; sampling one chart unit along x/y captures its\n * local slope. Per-section tangents are the intentional shell-performance\n * contract. Buyer seat anchors are projected exactly by `projectPerspectivePoint`;\n * only non-interactive section surfaces use this bounded approximation.\n */\nexport function perspectiveTangentAffine(\n camera: PerspectiveCamera,\n anchor: Point,\n heightAt: (point: Point) => number = () => 0,\n): Affine2D {\n const origin = projectPerspectivePoint(camera, anchor, heightAt(anchor));\n const alongXPoint = { x: anchor.x + 1, y: anchor.y };\n const alongYPoint = { x: anchor.x, y: anchor.y + 1 };\n const alongX = projectPerspectivePoint(camera, alongXPoint, heightAt(alongXPoint));\n const alongY = projectPerspectivePoint(camera, alongYPoint, heightAt(alongYPoint));\n const a = alongX.x - origin.x;\n const b = alongX.y - origin.y;\n const c = alongY.x - origin.x;\n const d = alongY.y - origin.y;\n return {\n a,\n b,\n c,\n d,\n e: origin.x - a * anchor.x - c * anchor.y,\n f: origin.y - b * anchor.x - d * anchor.y,\n };\n}\n\n/** Parameters accepted by Konva's rotation/scale/skew decomposition. */\nexport function decomposeAffineLinear(affine: Affine2D): {\n rotationDeg: number;\n scaleX: number;\n scaleY: number;\n skewX: number;\n} {\n const scaleX = Math.hypot(affine.a, affine.b);\n const determinant = affine.a * affine.d - affine.b * affine.c;\n return {\n rotationDeg: (Math.atan2(affine.b, affine.a) * 180) / Math.PI,\n scaleX,\n scaleY: determinant / Math.max(scaleX, 1e-9),\n skewX: (affine.a * affine.c + affine.b * affine.d) / Math.max(determinant, 1e-9),\n };\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/** Currencies offered in event create/edit selects — shared by the plain and\n * express create forms so the two can never offer different lists. */\nexport const CURRENCY_CHOICES = ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'INR', 'AED', 'SGD', 'JPY', 'CHF', 'SEK', 'NZD', 'ZAR', 'MXN', 'BRL'];\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/**\n * How many decimal places a currency has — 2 for USD/EUR, 0 for JPY/KRW/VND,\n * 3 for KWD/BHD/JOD.\n *\n * Derived from Intl rather than from a table, because ICU already carries ISO\n * 4217's exponents and a second hand-maintained list is a second thing to get\n * wrong. (`workers/api/src/payments/money.ts` DOES keep a table, on purpose: it\n * must THROW for a currency checkout cannot transact. Display has no such duty\n * — it renders whatever the ledger already recorded, including a currency\n * checkout would refuse.)\n *\n * Falls back to 2 for a code Intl rejects, so a bad row cannot blank a chart.\n */\nexport function currencyExponent(currency: string = DEFAULT_CURRENCY): number {\n try {\n return formatter(currency, undefined).resolvedOptions().maximumFractionDigits ?? 2;\n } catch {\n return 2;\n }\n}\n\n/**\n * Minor units → major units. `9000` USD cents is `90`; `9000` JPY is `9000`.\n *\n * Every money field the API returns is an integer in the currency's smallest\n * unit (`grossMinor`, `total_minor`). Dividing by 100 at a call site is right\n * for most currencies and silently wrong for the rest — 100x wrong for yen.\n */\nexport function fromMinorUnits(minor: number, currency: string = DEFAULT_CURRENCY): number {\n return minor / 10 ** currencyExponent(currency);\n}\n\n/** \"$90\" / \"¥9,000\" — a minor-unit integer rendered for display. */\nexport function formatMinor(minor: number, currency: string = DEFAULT_CURRENCY): string {\n return formatMoney(fromMinorUnits(minor, currency), currency);\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.holdExpired': 'Your hold expired — the seats were released. Pick again.',\n 'picker.poweredBy': 'Powered by SeatLayer',\n 'picker.testMode': 'TEST MODE',\n 'picker.orphanHint': 'This leaves a single seat stranded — consider shifting one seat over.',\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.soldOut': 'SOLD OUT',\n 'map.fromPrice': 'FROM {price}',\n 'map.statusHeld': 'On hold',\n 'map.statusTaken': 'Taken',\n\n // buyer picker widget (src/picker/widget/SeatPicker.ts)\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 — sold-out and nearly-gone sections shade to show availability at a glance',\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.entrance': 'Entrance',\n 'picker.tapSeatHint': 'Tap any seat to check its view',\n 'picker.ticketTierFor': 'Ticket tier for {label}',\n 'picker.viewFromSeat': 'View from seat {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'PREVIEW',\n 'picker.sightline': '≈ {m} m to stage',\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 'picker.bestSeatsPremium': 'Best seats',\n 'picker.premiumFallbackNote': 'No premium block of {count} — showing best overall',\n 'picker.loading3d': 'Building the 3D venue…',\n 'picker.unavailable3d': '3D could not start. The seat map is still available.',\n 'picker.jumpToSection': 'Jump to section',\n};\n","/**\n * i18n core — deliberately tiny and framework-free so the embed SDK can share\n * it without dragging in a runtime library — every KB here lands in the complete\n * CDN bundle every buyer downloads, which is ~207 KB gzipped as of 0.37.0+.\n * (This used to cite a \"150 KB product contract\". That number was never true of\n * any shipped bundle — the dashboard advertised it while the artifact measured\n * 215 KB — so it is stated as the measured figure now, not as a budget nobody\n * was holding. See docs/hosted-checkout-programme-2026-08-03.md §W4.)\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","import type {\n ShapeLineCap,\n ShapeLineEnding,\n ShapeLineJoin,\n ShapeObject,\n} from './types';\n\nexport const SHAPE_LINE_CAPS = ['butt', 'round', 'square'] as const satisfies readonly ShapeLineCap[];\nexport const SHAPE_LINE_JOINS = ['miter', 'round', 'bevel'] as const satisfies readonly ShapeLineJoin[];\nexport const SHAPE_LINE_ENDINGS = ['none', 'arrow'] as const satisfies readonly ShapeLineEnding[];\n\n/** These defaults match the renderer behaviour that predates persisted line styling. */\nexport const DEFAULT_SHAPE_LINE_CAP: ShapeLineCap = 'round';\nexport const DEFAULT_SHAPE_LINE_JOIN: ShapeLineJoin = 'round';\nexport const DEFAULT_SHAPE_LINE_ENDING: ShapeLineEnding = 'none';\n\nexport function isOpenShapeKind(kind: ShapeObject['kind']): kind is 'line' | 'polyline' {\n return kind === 'line' || kind === 'polyline';\n}\n\n/**\n * Shape kinds whose geometry is a `points[]` array, so they can be edited\n * vertex by vertex. Lives here rather than in the Designer because both the\n * controller's boundary/handle code and `controller/shapesTextDecorFacet` need\n * the same answer, and the Designer previously carried a private copy of the\n * open-shape rule alongside `isOpenShapeKind`.\n */\nexport function isPointShapeKind(kind: ShapeObject['kind']): kind is 'polygon' | 'line' | 'polyline' {\n return kind === 'polygon' || isOpenShapeKind(kind);\n}\n\nexport function resolvedShapeLineStyle(shape: Pick<ShapeObject, 'lineCap' | 'lineJoin' | 'startEnding' | 'endEnding'>) {\n return {\n lineCap: shape.lineCap ?? DEFAULT_SHAPE_LINE_CAP,\n lineJoin: shape.lineJoin ?? DEFAULT_SHAPE_LINE_JOIN,\n startEnding: shape.startEnding ?? DEFAULT_SHAPE_LINE_ENDING,\n endEnding: shape.endEnding ?? DEFAULT_SHAPE_LINE_ENDING,\n };\n}\n\n/** Keep arrowheads legible for hairlines without letting a 40-unit stroke\n * create unbounded decorations. Both renderers consume this exact contract. */\nexport function shapeArrowMetrics(strokeWidth: number): { pointerLength: number; pointerWidth: number } {\n return {\n pointerLength: Math.min(48, Math.max(8, strokeWidth * 3)),\n pointerWidth: Math.min(40, Math.max(8, strokeWidth * 2.25)),\n };\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 * Best-available seat selection — a PURE, fully unit-testable ranking function.\n *\n * This is the CLIENT-side twin of the server's atomic best-available route\n * (workers/api/src/bestAvailable.ts). The server owns the authoritative pick +\n * hold for the default \"Find best seats\" flow; this pure copy lets the buyer\n * widget run a premium-biased pre-pass locally (it already holds the full seat\n * geometry + commercial flags + live availability) and then hold the resulting\n * block through the normal hold endpoint. The baseline behaviour is kept\n * identical to the server so the two never disagree on what \"best\" means.\n *\n * \"Best\" means, in priority order:\n * 0. (opt-in) a run made entirely of `commercial.premium` seats — only when\n * `preferPremium` is set; absent = this term is inert (byte-identical).\n * 1. A single contiguous run of `qty` adjacent-available seats in ONE row\n * (a booked/held/missing/wrong-category seat breaks contiguity).\n * 2. …that does NOT strand a single isolated free seat (\"orphan\") beside the\n * run — leaving a pair or more is fine, leaving a lone singleton is not.\n * 3. …whose centroid is closest to the focal point (the stage).\n * 4. Deterministic tie-break by rowId then seat index (so it's testable).\n *\n * When no single-row run of `qty` exists, it falls back to the `qty` available\n * seats closest to the focal point overall (which may span rows).\n */\nimport type { ExpandedSeat, Point } from './types';\n\nexport type BestAvailableReason = 'not_enough_together' | 'sold_out';\n\nexport interface BestAvailableResult {\n labels: string[];\n reason?: BestAvailableReason;\n}\n\nexport interface BestAvailableOpts {\n qty: number;\n categoryKey?: string;\n /** Restrict the pick to one authored navigation zone. */\n zoneId?: string;\n focal: Point;\n /**\n * Additive premium bias. When true, candidate scoring STRONGLY prefers seats\n * carrying `commercial.premium` (a fully-premium run beats any run holding a\n * non-premium seat, ahead of orphan/distance). Undefined/false leaves scoring\n * byte-identical to the baseline algorithm — the premium term never runs.\n */\n preferPremium?: boolean;\n}\n\n/** Seat index within its row, parsed from the `${rowId}:${index}` id. */\nfunction seatIndex(seat: ExpandedSeat, fallback: number): number {\n if (Number.isInteger(seat.logicalSeatIndex)) return seat.logicalSeatIndex!;\n const i = seat.id.lastIndexOf(':');\n if (i < 0) return fallback;\n const n = Number(seat.id.slice(i + 1));\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction dist2(a: Point, b: Point): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return dx * dx + dy * dy;\n}\n\n/** Centroid of a set of seats. */\nfunction centroid(seats: ExpandedSeat[]): Point {\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\nfunction candidateFocal(seats: ExpandedSeat[], fallback: Point): Point {\n return seats.find((seat) => seat.focalPoint)?.focalPoint ?? fallback;\n}\n\nfunction isPremium(seat: ExpandedSeat): boolean {\n return seat.commercial?.premium === true;\n}\n\ninterface Slot {\n seat: ExpandedSeat;\n index: number;\n /** Eligible = available AND (no category filter OR category matches). */\n elig: boolean;\n}\n\ninterface Candidate {\n labels: string[];\n seats: ExpandedSeat[];\n rowId: string;\n startIndex: number;\n /** 1 when taking this run strands a lone free seat; 0 otherwise. */\n orphan: number;\n /** Count of non-premium seats in the run — only scored when preferPremium. */\n nonPremium: number;\n d2: number;\n}\n\n/**\n * Pick the `qty` best available seats. Returns `{ labels }` on success, or\n * `{ labels: [], reason }` when the request can't be satisfied at all.\n */\nexport function pickBestAvailable(\n seats: ExpandedSeat[],\n available: Set<string>,\n opts: BestAvailableOpts,\n): BestAvailableResult {\n const qty = Math.floor(opts.qty);\n if (!Number.isFinite(qty) || qty <= 0) return { labels: [], reason: 'sold_out' };\n const { categoryKey, zoneId, focal, preferPremium } = opts;\n\n // Group ALL seats by row (we need the non-eligible ones too, to detect gaps\n // and orphans), preserving original order for a stable fallback tie-break.\n const rows = new Map<string, Slot[]>();\n const eligibleAll: ExpandedSeat[] = [];\n seats.forEach((seat, i) => {\n const elig = available.has(seat.label)\n && (!categoryKey || seat.categoryKey === categoryKey)\n && (!zoneId || seat.zoneId === zoneId);\n const rowId = seat.logicalRowId ?? seat.rowId;\n let arr = rows.get(rowId);\n if (!arr) {\n arr = [];\n rows.set(rowId, arr);\n }\n arr.push({ seat, index: seatIndex(seat, i), elig });\n if (elig) eligibleAll.push(seat);\n });\n\n if (eligibleAll.length === 0) return { labels: [], reason: 'sold_out' };\n\n // --- 1) single-row contiguous runs of `qty` adjacent-available seats ---\n let best: Candidate | null = null;\n const better = (c: Candidate): boolean => {\n if (!best) return true;\n // Premium bias (opt-in) outranks everything else so the buyer lands the\n // best PREMIUM block; inert when preferPremium is off (nonPremium === 0).\n if (preferPremium && c.nonPremium !== best.nonPremium) return c.nonPremium < best.nonPremium;\n if (c.orphan !== best.orphan) return c.orphan < best.orphan;\n if (c.d2 !== best.d2) return c.d2 < best.d2;\n const r = c.rowId.localeCompare(best.rowId);\n if (r !== 0) return r < 0;\n return c.startIndex < best.startIndex;\n };\n\n for (const [rowId, slotsUnsorted] of rows) {\n const slots = [...slotsUnsorted].sort((a, b) => a.index - b.index);\n // Walk maximal eligible segments. A non-eligible slot (taken / wrong\n // category / missing) breaks contiguity.\n let i = 0;\n while (i < slots.length) {\n if (!slots[i].elig) {\n i++;\n continue;\n }\n let j = i;\n while (\n j < slots.length\n && slots[j].elig\n && (j === i || slots[j].index === slots[j - 1].index + 1)\n ) j++;\n const segLen = j - i; // eligible run [i, j)\n // Every window of `qty` within this segment is a candidate.\n for (let p = 0; p + qty <= segLen; p++) {\n const leftRem = p; // eligible seats stranded to the left of the window\n const rightRem = segLen - (p + qty); // …and to the right\n const orphan = leftRem === 1 || rightRem === 1 ? 1 : 0;\n const runSeats = slots.slice(i + p, i + p + qty).map((s) => s.seat);\n const c: Candidate = {\n labels: runSeats.map((s) => s.label),\n seats: runSeats,\n rowId,\n startIndex: slots[i + p].index,\n orphan,\n nonPremium: preferPremium ? runSeats.reduce((n, s) => n + (isPremium(s) ? 0 : 1), 0) : 0,\n d2: dist2(centroid(runSeats), candidateFocal(runSeats, focal)),\n };\n if (better(c)) best = c;\n }\n i = j;\n }\n }\n\n if (best) return { labels: best.labels };\n\n // --- 2) fallback: the `qty` closest-to-focal seats overall (may span rows) ---\n if (eligibleAll.length < qty) return { labels: [], reason: 'not_enough_together' };\n\n const ranked = eligibleAll\n .map((seat, i) => ({ seat, i, d2: dist2(seat, seat.focalPoint ?? focal) }))\n .sort((a, b) => {\n // Premium-first when biased (inert otherwise — both sides score 0).\n if (preferPremium) {\n const pa = isPremium(a.seat) ? 0 : 1;\n const pb = isPremium(b.seat) ? 0 : 1;\n if (pa !== pb) return pa - pb;\n }\n if (a.d2 !== b.d2) return a.d2 - b.d2;\n const r = (a.seat.logicalRowId ?? a.seat.rowId).localeCompare(b.seat.logicalRowId ?? b.seat.rowId);\n if (r !== 0) return r;\n return seatIndex(a.seat, a.i) - seatIndex(b.seat, b.i);\n });\n\n return { labels: ranked.slice(0, qty).map((r) => r.seat.label) };\n}\n","import { allObjects, expandTable } from './layout';\nimport type { ChartDoc, ExpandedSeat, TableObject } from './types';\n\nexport type ClientInventoryModelVersion = 1 | 2;\nexport type GroupedTableBookingMode = 'whole' | 'variable';\n\n/**\n * Buyer-side projection of one atomic table inventory unit. The physical\n * chairs remain renderer geometry, but `label` is the only booking identity.\n */\nexport interface GroupedTableInventoryUnit {\n objectId: string;\n label: string;\n displayLabel?: string;\n displayType?: string;\n categoryKey: string;\n mode: GroupedTableBookingMode;\n capacity: number;\n minOccupancy: number;\n maxOccupancy: number;\n chairs: ExpandedSeat[];\n}\n\nexport class GroupedTableProjectionError extends Error {\n constructor(\n readonly objectId: string,\n message: string,\n ) {\n super(message);\n this.name = 'GroupedTableProjectionError';\n }\n}\n\nfunction bounds(table: TableObject): { min: number; max: number } {\n const min = table.minOccupancy;\n const max = table.maxOccupancy;\n if (\n !Number.isInteger(min)\n || !Number.isInteger(max)\n || min! < 1\n || max! < min!\n || max! > table.seatCount\n ) {\n throw new GroupedTableProjectionError(\n table.id,\n `Table \"${table.label}\" has invalid variable-occupancy bounds`,\n );\n }\n return { min: min!, max: max! };\n}\n\n/**\n * Project grouped tables only for the event's explicit model-2 contract.\n * Model 1 deliberately returns no groups even if a legacy snapshot happens to\n * carry a grouping flag, preserving per-chair selection byte-for-byte.\n */\nexport function groupedTableInventory(\n doc: ChartDoc,\n modelVersion: ClientInventoryModelVersion,\n): GroupedTableInventoryUnit[] {\n if (modelVersion !== 2) return [];\n const units: GroupedTableInventoryUnit[] = [];\n for (const object of allObjects(doc)) {\n if (object.type !== 'table' || (!object.bookAsWhole && !object.variableOccupancy)) continue;\n if (object.bookAsWhole && object.variableOccupancy) {\n throw new GroupedTableProjectionError(\n object.id,\n `Table \"${object.label}\" cannot be whole-table and variable-occupancy inventory`,\n );\n }\n if (!Number.isInteger(object.seatCount) || object.seatCount < 1 || !object.label.trim()) {\n throw new GroupedTableProjectionError(object.id, 'Grouped tables require a label and at least one chair');\n }\n const mode: GroupedTableBookingMode = object.variableOccupancy ? 'variable' : 'whole';\n const occupancy = mode === 'variable'\n ? bounds(object)\n : { min: object.seatCount, max: object.seatCount };\n units.push({\n objectId: object.id,\n label: object.label,\n ...(object.displayLabel ? { displayLabel: object.displayLabel } : {}),\n ...(object.displayType ? { displayType: object.displayType } : {}),\n categoryKey: object.categoryKey,\n mode,\n capacity: object.seatCount,\n minOccupancy: occupancy.min,\n maxOccupancy: occupancy.max,\n chairs: expandTable(object),\n });\n }\n return units;\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 { pickBestAvailable } from '../core/bestAvailable';\nimport { t } from '../i18n';\nimport type {\n AccessibilityType,\n CategoryTier,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n ISeatmapRenderer,\n LodRung,\n RendererCallbacks,\n RendererViewMode,\n SeatCommercialAttributes,\n SeatStatus,\n SectionObject,\n} from '../core/types';\nimport { gaAreasOf, gaUnitLabels } from '../core/ga';\nimport {\n groupedTableInventory,\n type GroupedTableInventoryUnit,\n} from '../core/tableInventory';\n\nconst DEFAULT_MAX_SELECTION = 10;\nconst MAX_BACKOFF_MS = 15_000;\n\nexport interface PickerSeat {\n id: string;\n label: string;\n /** Buyer-facing label (row `displayLabel` applied). Falls back to `label`;\n * never use for booking — `label` is the inventory/booking identity. */\n displayLabel?: string;\n /** Buyer-facing object type word authored in Designer. Pure presentation. */\n displayType?: string;\n /** @deprecated Use `displayType`; retained for source compatibility. */\n rowType?: string;\n /** Stable parent chart-object id (row/table/booth), separate from seat id. */\n objectId?: string;\n /** Buyer-facing spatial context shared by selection, hold, and hover callbacks. */\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: 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 /** Accessibility semantics exposed to SDK callbacks and buyer summaries. */\n accessibility?: AccessibilityType[];\n /** Explicit physical wheelchair chair/bay distinction. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n /** Physical/bookable source kind; booking identity remains `label`. */\n objectType?: 'seat' | 'booth' | 'table';\n /** Grouped-table booking contract; absent for normal chair inventory. */\n bookingMode?: 'whole' | 'variable';\n /** Guest quantity represented by this one atomic table line. */\n quantity?: number;\n capacity?: number;\n minOccupancy?: number;\n maxOccupancy?: number;\n}\n\n/** Accessible quantity/confirmation payload for one model-2 table selection. */\nexport interface TableSelectionDetails extends PickerSeat {\n objectType: 'table';\n bookingMode: 'whole' | 'variable';\n quantity: number;\n capacity: number;\n minOccupancy: number;\n maxOccupancy: number;\n physicalSeatIds: 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}\n\nexport interface PickerGAArea {\n id: string;\n /** Stable technical/inventory prefix. */\n label: string;\n /** Buyer-facing area name and type; absent fields use UI defaults. */\n displayLabel?: string;\n displayType?: string;\n capacity: number;\n available: number;\n categoryKey: string;\n price: number;\n currency: string;\n tiers?: CategoryTier[];\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 /** Buyer-facing section name (`displayLabel` when set, else the inventory label). */\n label: string;\n /** Zone label (from ChartDoc.zones); '' when the section has no zone. */\n zoneLabel: string;\n /** Buyer-facing entrance/door hint (\"Entrance X\"); absent when unset. */\n entrance?: 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' | 'table';\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; quantity?: number }\ninterface BestAvailableResponse extends HoldResponse {\n labels: string[];\n}\n\n/** One unit's status as the realtime wire words it (`free`/`held`/`booked`/`blocked`/…). */\nexport interface PickerStatusChange {\n label: string;\n status: string;\n}\n\n/**\n * Where a transport-owned realtime client pushes reconstructed inventory.\n *\n * Structurally identical to the SDK's `RealtimeSink` on purpose: this file is\n * mirrored byte-for-byte into `@seatlayer/core`, which the SDK's `@seatlayer/js`\n * depends on — so it can never import BuyerRealtimeClient without inverting that\n * dependency. Structural typing lets the SDK hand its client this object with no\n * import in either direction.\n */\nexport interface PickerRealtimeSink {\n /** Apply a batch of label→status changes as ONE paint pass, not one per label. */\n applyStatuses(changes: PickerStatusChange[]): void;\n /**\n * Paint a COMPLETE projection: the default every unnamed unit takes, plus the\n * units that differ from it.\n *\n * Optional so a host implementing an older sink keeps working — a client that\n * finds it missing falls back to {@link resync}. Where it exists it replaces\n * that HTTP round trip entirely, because the frame that triggered the resync\n * already carried the whole authoritative state. On a 52k venue that is the\n * difference between a ~960 KiB verbose fetch and painting what already\n * arrived in a ~200 KiB socket frame.\n */\n applyProjection?(projection: { default: string; exceptions: Record<string, string> }): void;\n /** Re-pull authoritative state over HTTP (a frame that cannot be diffed). */\n resync(): void | Promise<void>;\n /** Section availability changed (hidden = stripped, closed = greyed). */\n onSections?(hidden: string[], closed: string[]): void;\n /** Scope-projected presence counters. Unused by the picker today. */\n onPresence?(counts: { shoppingSessions: number; activeHolds: number }): void;\n}\n\n/** The live feed itself, owned by the transport. */\nexport interface PickerRealtimeConnection {\n start(): void;\n stop(): void;\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; timezone?: string | null; currency?: string; mode?: string; inventoryModelVersion?: 1 | 2 };\n }>;\n /** `default` is the status of every seat NOT in `seats`; absent means `free`\n * (an older server names every seat). Never assume it. */\n objects(key: string): Promise<{ seats: Record<string, string>; default?: 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, zoneId?: string, ttlMs?: number): 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 /** Optional — WebSocket subprotocols for the live feed (e.g. a one-use\n * subscribe ticket via `Sec-WebSocket-Protocol`, realtime-protocol v1).\n * Absent or empty means today's plain connection. */\n socketProtocols?(key: string): string[];\n /**\n * Optional — the transport owns the live feed and hands back a client that\n * speaks the compact `seatlayer.v1` protocol (snapshot diffing, `sv.<n>`\n * resume, ping/pong liveness, jittered reconnect).\n *\n * When this returns a connection the controller does NOT open its own socket:\n * one socket client, one reconnect/backoff/resume implementation. Returning\n * null (or omitting the method) keeps the plain-WebSocket path below, which is\n * what a transport with no realtime client of its own still gets.\n */\n createRealtime?(key: string, sink: PickerRealtimeSink): PickerRealtimeConnection | null;\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 grouped table was selected and needs buyer confirmation/guest quantity. */\n onTableSelectionRequest?: (table: TableSelectionDetails) => 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 * Host overrides for the DRAWN map — see {@link PickerMapTheme}. Absent (the\n * default, and every embed) leaves the chart document's own theme untouched.\n */\n mapTheme?: PickerMapTheme | null;\n}\n\n/**\n * The subset of `ChartTheme` a HOST may override on the drawn canvas.\n *\n * WHY A SUBSET, AND WHY THESE FOUR. Everything here paints directly ON the\n * ground this same object sets, so a caller supplying it can be held to a\n * contrast contract over its own values (the event-page palettes are). The\n * fields deliberately left out — `seatLabelColor`, `decorFill` — paint on top\n * of CHART-authored colours instead: a category's fill, an authored décor fill.\n * A page palette knows nothing about those, so an override there would be an\n * unverifiable guess about legibility, and the chart keeps them.\n *\n * `seatScale`, `fontFamily` and the white-label branding fields are not here\n * either: they are the ORGANIZER's, authored once with the chart, and a page\n * theme is not the place to resize a venue.\n */\nexport interface PickerMapTheme {\n /** The canvas ground behind the seats. */\n background?: string;\n /** Row identifiers (A, B, C) drawn beside the rows. */\n rowLabelColor?: string;\n /** Default ink for free text drawn on the canvas. */\n textColor?: string;\n /** Selection / hover ring. */\n selectionColor?: string;\n}\n\n/** The four keys, as data, so a merge cannot silently miss one. */\nconst MAP_THEME_KEYS = ['background', 'rowLabelColor', 'textColor', 'selectionColor'] as const;\n\nfunction sameMapTheme(a: PickerMapTheme | null, b: PickerMapTheme | null): boolean {\n if (!a || !b) return !a && !b;\n return MAP_THEME_KEYS.every((key) => a[key] === b[key]);\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 /** Host overrides folded over the chart's own theme in `visibleDoc()`. */\n private mapTheme: PickerMapTheme | null = null;\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, {\n objectId: string;\n objectType: 'seat' | 'booth' | 'table';\n sectionLabel?: string;\n rowLabel?: string;\n seatNumber?: string;\n displayType?: string;\n /** @deprecated compatibility alias for older tooltip consumers. */\n rowType?: string;\n }>();\n private allIds: string[] = [];\n /** Model-2 tables are one booking unit whose chairs remain renderer geometry. */\n private groupedTablesByObject = new Map<string, GroupedTableInventoryUnit>();\n private groupedTablesByLabel = new Map<string, GroupedTableInventoryUnit>();\n private groupedTableBySeatId = new Map<string, GroupedTableInventoryUnit>();\n private tableQuantities = new Map<string, number>();\n /** Variable quantity is a buyer contract, never an inferred default. */\n private confirmedVariableTables = new Set<string>();\n private groupedSelectionOverhead = 0;\n\n // realtime socket\n private ws: WebSocket | null = null;\n /** Transport-owned v1 client; mutually exclusive with `ws`. */\n private realtime: PickerRealtimeConnection | 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 /**\n * What a label absent from `liveStatuses` is.\n *\n * `free` while the verbose HTTP map is the source (it names every unit), but a\n * compact realtime frame names only its exceptions — so on a mostly-sold event\n * the seats NOT listed are the booked ones. Read through {@link statusOf};\n * a bare `liveStatuses.get()` silently answers `undefined` for the majority of\n * a sold-out venue.\n */\n private liveDefault = 'free';\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 this.mapTheme = options.mapTheme ?? null;\n }\n\n get doc(): ChartDoc | null {\n return this._doc;\n }\n\n /**\n * The chart with hidden sections' seats removed, and the host's map theme\n * folded over the chart's own — what buyers actually see.\n *\n * THE THEME IS MERGED HERE rather than pushed at the renderer separately\n * because the renderer reads its theme out of the document it is given. One\n * merge point means every rebuild — a hidden section arriving mid-sale, a\n * floor switch, a theme change — repaints from the same resolved theme\n * instead of from whichever of two sources ran last.\n *\n * The chart's theme is the BASE and only named keys are overwritten, so a\n * host that overrides the ground does not thereby erase the organizer's\n * `seatScale`, `fontFamily`, logo or badge entitlement.\n */\n private visibleDoc(): ChartDoc {\n if (!this._doc) return { objects: [] } as unknown as ChartDoc;\n const doc = applyHidden(this._doc, this.hidden);\n if (!this.mapTheme) return doc;\n const theme = { ...(doc.theme ?? {}) };\n for (const key of MAP_THEME_KEYS) {\n const value = this.mapTheme[key];\n if (value) theme[key] = value;\n }\n return { ...doc, theme };\n }\n\n /**\n * Re-ink the drawn map, in place, without losing the buyer's place in it.\n *\n * WHY THIS IS A SETTER AND NOT A MOUNT OPTION. On a templated event page the\n * palette is not known when the map mounts: the page config is a separate\n * cached read and the map is explicitly not allowed to wait for it. The\n * alternative — remounting the widget once the palette lands — would destroy\n * a hold the buyer may already be holding.\n *\n * The rebuild is the SAME recipe `render()` uses (setChart → colorblind →\n * closed sections → statuses), because setChart resets all four; the one\n * addition is restoring the selection, which `render()` has no need to do.\n * Statuses are repainted from the map already in memory rather than re-read,\n * so this costs no round trip and cannot flash a stale seat.\n *\n * Returns whether anything actually changed, so a caller may call it freely.\n */\n setMapTheme(theme: PickerMapTheme | null): boolean {\n if (sameMapTheme(this.mapTheme, theme ?? null)) return false;\n this.mapTheme = theme ?? null;\n const r = this.renderer;\n if (!r) return true; // not mounted yet — the first setChart will carry it\n const selected = r.getSelection().map((seat) => seat.id);\n const floorId = this.getActiveFloorId();\n r.setChart(this.visibleDoc(), floorId ? { floorId } : undefined);\n if (this.opts.colorblindSafe) r.setColorblindSafe?.(true);\n if (this.closedSections.size) r.setClosedSections?.([...this.closedSections]);\n // The authoritative statuses we are already holding — including the\n // buyer-ownership layer, which `applySeatsMap` restores for exactly this\n // \"setChart just reset everything\" case.\n this.applySeatsMap(Object.fromEntries(this.liveStatuses), this.liveDefault);\n if (selected.length) r.select?.(selected);\n return true;\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 private idsForLabel(label: string): string[] {\n const table = this.groupedTablesByLabel.get(label);\n if (table) return table.chairs.map((chair) => chair.id);\n const id = this.labelToId.get(label);\n return id ? [id] : [];\n }\n\n private idsForLabels(labels: Iterable<string>): string[] {\n return [...new Set([...labels].flatMap((label) => this.idsForLabel(label)))];\n }\n\n /** Resolve a physical chair id (or table inventory label) to its table unit. */\n tableSelection(seatIdOrLabel: string): TableSelectionDetails | null {\n const group = this.groupedTableBySeatId.get(seatIdOrLabel)\n ?? this.groupedTablesByLabel.get(seatIdOrLabel);\n return group ? this.toTableSeat(group) : null;\n }\n\n /**\n * Buyer-facing name + type word for a checkout line item, resolved from the\n * SAME author overrides the tray/tooltip already render. `label` stays the\n * booking identity; a host builds its own order summary from `displayLabel`/\n * `displayType` so the buyer sees the designer's copy, not the internal label.\n * Absent fields = no override (host falls back to `label`).\n */\n lineItemDisplay(\n item: { label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga' | 'table' },\n ): { displayLabel?: string; displayType?: string } {\n if (item.objectType === 'ga') {\n const doc = this.visibleDoc();\n const area = gaAreasOf(doc).find((candidate) => candidate.id === item.objectId);\n return {\n ...(area?.displayLabel ? { displayLabel: area.displayLabel } : {}),\n ...(area?.displayType ? { displayType: area.displayType } : {}),\n };\n }\n if (item.objectType === 'table') {\n const group = this.groupedTablesByLabel.get(item.label);\n return {\n ...(group?.displayLabel && group.displayLabel !== group.label ? { displayLabel: group.displayLabel } : {}),\n ...(group?.displayType ? { displayType: group.displayType } : {}),\n };\n }\n const seat = this.labelToSeat.get(item.label);\n const context = seat ? this.seatContext.get(seat.id) : undefined;\n return {\n ...(seat?.displayLabel ? { displayLabel: seat.displayLabel } : {}),\n ...(context?.displayType ? { displayType: context.displayType } : {}),\n };\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 /** The EVENT's IANA zone. Every surface that prints `startsAt` must format\n * in it — see the note in pub.ts's chart route. */\n timezone?: string | 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 try {\n const groups = groupedTableInventory(\n res.doc,\n res.event.inventoryModelVersion === 2 ? 2 : 1,\n );\n this.groupedTablesByObject = new Map(groups.map((group) => [group.objectId, group]));\n this.groupedTablesByLabel = new Map(groups.map((group) => [group.label, group]));\n this.groupedTableBySeatId = new Map(\n groups.flatMap((group) => group.chairs.map((chair) => [chair.id, group] as const)),\n );\n this.tableQuantities = new Map(groups.map((group) => [\n group.label,\n group.mode === 'whole' ? group.capacity : group.minOccupancy,\n ]));\n this.confirmedVariableTables = new Set();\n this.groupedSelectionOverhead = groups.reduce(\n (sum, group) => sum + Math.max(0, group.chairs.length - 1),\n 0,\n );\n } catch (err) {\n // A model-2 event with an invalid grouping contract is not safe to sell.\n // Fail before mounting the interactive renderer instead of falling back\n // to per-chair labels that the server does not own.\n this.emitError(err);\n return null;\n }\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 logicalRow = source?.type === 'row' ? source.segmentedRow : undefined;\n // Buyer-facing row name honours the designer's row `displayLabel`; inventory\n // `label` stays the booking identity used everywhere seats are held/booked.\n const sourceDisplayLabel = logicalRow?.displayLabel\n ?? (source && 'displayLabel' in source && typeof source.displayLabel === 'string' && source.displayLabel\n ? source.displayLabel\n : sourceLabel);\n const groupedTable = this.groupedTablesByObject.get(s.rowId);\n const objectType = source?.type === 'table' ? 'table' : source?.type === 'booth' ? 'booth' : 'seat';\n const rowLabel = sourceDisplayLabel;\n // Buyer-facing type word override (seats.io \"Displayed type\") — replaces the\n // default \"Row\" in tooltip/confirm/cart for rows and tables when set.\n const rowType = logicalRow?.displayType?.trim()\n || (source && 'displayType' in source && typeof source.displayType === 'string' && source.displayType.trim()\n ? source.displayType.trim()\n : undefined);\n // Seat number is read off the buyer-facing seat label so a renamed row shows\n // the buyer copy; both labels share the same `${prefix}-${number}` suffix.\n const visibleSeatLabel = s.displayLabel ?? s.label;\n const labelParts = visibleSeatLabel.split('-');\n const seatNumber = groupedTable\n ? undefined\n : s.kind === 'booth'\n ? undefined\n : sourceDisplayLabel && visibleSeatLabel.startsWith(`${sourceDisplayLabel}-`)\n ? visibleSeatLabel.slice(sourceDisplayLabel.length + 1)\n : labelParts[labelParts.length - 1] ?? visibleSeatLabel;\n this.seatContext.set(s.id, {\n objectId: s.rowId,\n objectType,\n sectionLabel: sectionLabels.get(membership.objectToSection.get(s.rowId) ?? ''),\n rowLabel,\n seatNumber,\n ...(rowType ? { displayType: rowType, rowType } : {}),\n });\n }\n // The backend speaks the table label, while the renderer still speaks chair\n // ids. Point the atomic label at a stable representative chair; every\n // status/selection mutation expands through idsForLabel() below.\n for (const group of this.groupedTablesByLabel.values()) {\n const representative = group.chairs[0];\n if (!representative) continue;\n this.labelToId.set(group.label, representative.id);\n this.labelToSeat.set(group.label, representative);\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 // Group chairs are selected together for paint, but count as one logical\n // inventory line. The controller enforces the guest-weighted cap.\n maxSelection: this.rendererSelectionCap(),\n confirmSelection: this.opts.confirmSelection,\n currency,\n onSelect: (seat) => {\n this.handleRendererSelect(seat);\n },\n onDeselect: (seat) => {\n this.handleRendererDeselect(seat);\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 seatsDefault = 'free';\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 seatsDefault = objs.default ?? 'free';\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, seatsDefault);\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 timezone: res.event.timezone ?? null,\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 const out: PickerSeat[] = [];\n const grouped = new Set<string>();\n for (const seat of this.renderer.getSelection()) {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n if (!grouped.has(table.label)) {\n grouped.add(table.label);\n out.push(this.toTableSeat(table));\n }\n } else {\n out.push(this.toSeat(seat));\n }\n }\n return out;\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.resetUnheldTableQuantities();\n this.emitSelectionChange();\n }\n deselect(ids: string[]): void {\n const expanded = new Set<string>();\n for (const id of ids) {\n const table = this.groupedTableBySeatId.get(id) ?? this.groupedTablesByLabel.get(id);\n if (table) {\n table.chairs.forEach((chair) => expanded.add(chair.id));\n if (!this.hold_?.labels.includes(table.label)) {\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n } else expanded.add(id);\n }\n this.renderer?.deselect([...expanded]);\n this.emitSelectionChange();\n }\n setMaxSelection(maxSelection: number): void {\n this.maxSelection = Math.max(0, Math.floor(maxSelection));\n this.renderer?.setMaxSelection?.(this.rendererSelectionCap());\n }\n select(ids: string[]): PickerSeat[] {\n const before = new Set(this.getSelection().map((seat) => seat.label));\n const expanded = new Set<string>();\n for (const id of ids) {\n const table = this.groupedTableBySeatId.get(id) ?? this.groupedTablesByLabel.get(id);\n if (table) table.chairs.forEach((chair) => expanded.add(chair.id));\n else expanded.add(id);\n }\n this.renderer?.select?.([...expanded]);\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect([...expanded]);\n this.opts.onSelectionLimit?.(this.maxSelection);\n return [];\n }\n const added = this.getSelection().filter((seat) => !before.has(seat.label));\n if (added.length) this.emitSelectionChange();\n return added;\n }\n\n /** Confirm/update the guest quantity for a selected variable table. */\n setTableQuantity(label: string, quantity: number): boolean {\n const table = this.groupedTablesByLabel.get(label);\n if (!table) return false;\n const q = table.mode === 'whole' ? table.capacity : Math.floor(quantity);\n if (!Number.isInteger(q) || q < table.minOccupancy || q > table.maxOccupancy) return false;\n const previous = this.tableQuantities.get(label) ?? table.minOccupancy;\n this.tableQuantities.set(label, q);\n if (this.selectionGuestCount() > this.maxSelection) {\n this.tableQuantities.set(label, previous);\n this.opts.onSelectionLimit?.(this.maxSelection);\n return false;\n }\n if (table.mode === 'variable') this.confirmedVariableTables.add(label);\n this.emitSelectionChange();\n return true;\n }\n\n /**\n * Atomically replace an active variable-table hold with a new guest count.\n * `ttlMs` keeps the host's checkout window across the replacement — without it\n * a guest-count change silently re-based the countdown on the server default.\n */\n async replaceTableQuantity(label: string, quantity: number, ttlMs?: number): Promise<HoldInfo | null> {\n const table = this.groupedTablesByLabel.get(label);\n const hold = this.hold_;\n if (!table || table.mode !== 'variable' || !hold?.labels.includes(label)) return null;\n const q = Math.floor(quantity);\n if (!Number.isInteger(q) || q < table.minOccupancy || q > table.maxOccupancy) return null;\n const otherGuests = (hold.items ?? [])\n .filter((item) => item.label !== label)\n .reduce((sum, item) => sum + (item.quantity ?? 1), 0);\n if (otherGuests + q > this.maxSelection) {\n this.opts.onSelectionLimit?.(this.maxSelection);\n return null;\n }\n const selections: HoldSelectionRequest[] = (hold.items ?? []).map((item) => ({\n label: item.label,\n tierId: item.tierId,\n quantity: item.label === label ? q : item.quantity,\n }));\n if (!selections.some((item) => item.label === label)) return null;\n const result = await this.api.hold(this.key, selections, ttlMs, hold.holdId);\n this.tableQuantities.set(label, q);\n this.setHold({\n holdId: result.holdId,\n labels: selections.map((item) => item.label),\n expiresAt: result.expiresAt,\n items: result.items,\n });\n return this.hold_;\n }\n\n private rendererSelectionCap(): number {\n return this.maxSelection + this.groupedSelectionOverhead;\n }\n\n private selectionGuestCount(): number {\n return this.getSelection().reduce((sum, seat) => sum + (seat.quantity ?? 1), 0);\n }\n\n private handleRendererSelect(seat: ExpandedSeat): void {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect(table.chairs.map((chair) => chair.id));\n this.opts.onSelectionLimit?.(this.maxSelection);\n this.emitSelectionChange();\n return;\n }\n // One click paints every chair as selected; the public selection remains\n // one table line through getSelection(). Programmatic select is silent.\n this.renderer?.select?.(table.chairs.map((chair) => chair.id));\n this.opts.onSelect?.(table.chairs[0] ?? seat);\n this.opts.onTableSelectionRequest?.(this.toTableSeat(table));\n this.emitSelectionChange();\n return;\n }\n if (this.selectionGuestCount() > this.maxSelection) {\n this.renderer?.deselect([seat.id]);\n this.opts.onSelectionLimit?.(this.maxSelection);\n this.emitSelectionChange();\n return;\n }\n this.opts.onSelect?.(seat);\n this.emitSelectionChange();\n }\n\n private handleRendererDeselect(seat: ExpandedSeat): void {\n const table = this.groupedTableBySeatId.get(seat.id);\n if (table) {\n this.renderer?.deselect(table.chairs.map((chair) => chair.id));\n if (!this.hold_?.labels.includes(table.label)) {\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n this.opts.onDeselect?.(table.chairs[0] ?? seat);\n } else {\n this.opts.onDeselect?.(seat);\n }\n this.emitSelectionChange();\n }\n\n private resetUnheldTableQuantities(): void {\n for (const table of this.groupedTablesByLabel.values()) {\n if (this.hold_?.labels.includes(table.label)) continue;\n this.tableQuantities.set(\n table.label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(table.label);\n }\n }\n\n private resetTableQuantitiesForLabels(labels: Iterable<string>): void {\n for (const label of labels) {\n const table = this.groupedTablesByLabel.get(label);\n if (!table) continue;\n this.tableQuantities.set(\n label,\n table.mode === 'whole' ? table.capacity : table.minOccupancy,\n );\n if (table.mode === 'variable') this.confirmedVariableTables.delete(label);\n }\n }\n\n private tableQuantityRequest(seat: PickerSeat | null): { quantity?: number } {\n if (seat?.objectType !== 'table') return {};\n if (seat.bookingMode === 'variable' && !this.confirmedVariableTables.has(seat.label)) {\n throw new Error('picker: confirm a variable table guest quantity before holding');\n }\n return { quantity: seat.quantity };\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 ?? this.getSelection().map((seat) => seat.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, quantity: ga.quantity };\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n return {\n label,\n ...(resolved?.tierId ? { tierId: resolved.tierId } : {}),\n ...this.tableQuantityRequest(resolved),\n };\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 (this.groupedTableBySeatId.has(id)) continue;\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 for (const table of this.groupedTablesByLabel.values()) {\n if (table.chairs.some((chair) => closedMembers.has(chair.id))) continue;\n const representative = table.chairs[0];\n if (representative && (this.getStatus(representative.id) ?? 'free') === 'free') {\n // Availability is guest capacity, while atomic ownership remains one row.\n out[table.categoryKey] = (out[table.categoryKey] ?? 0) + table.maxOccupancy;\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(): PickerGAArea[] {\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 ...(area.displayLabel ? { displayLabel: area.displayLabel } : {}),\n ...(area.displayType ? { displayType: area.displayType } : {}),\n capacity: Math.max(0, Math.floor(area.capacity)),\n available: gaUnitLabels(area).filter((label) => this.statusOf(label) === '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.statusOf(label) === 'free')\n .slice(0, Math.floor(qty));\n if (labels.length !== Math.floor(qty)) return null;\n const selections = new Map<string, HoldSelectionRequest>();\n for (const item of this.hold_?.items ?? []) selections.set(item.label, {\n label: item.label,\n tierId: item.tierId,\n quantity: item.quantity,\n });\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.getSelection()) {\n selections.set(seat.label, {\n label: seat.label,\n ...(seat.tierId ? { tierId: seat.tierId } : {}),\n ...this.tableQuantityRequest(seat),\n });\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 /** True when any seat on the visible chart carries the `premium` commercial\n * flag — gates the buyer widget's \"★ Best seats\" premium quick-pick (chip is\n * present-only, exactly like the accessibility filter chips). */\n hasPremiumSeats(): boolean {\n for (const seat of this.labelToSeat.values()) {\n if (seat.commercial?.premium) return true;\n }\n return false;\n }\n\n /** Zones which still own visible buyer inventory, in authored order. */\n getBestAvailableZones(): Array<{ id: string; label: string }> {\n const doc = this.visibleDoc();\n if (!doc?.zones?.length) return [];\n const used = new Set(\n computeSections(doc).sections\n .filter((section) => section.seatCount > 0 && !!section.zone)\n .map((section) => section.zone!),\n );\n return doc.zones.filter((zone) => used.has(zone.id)).map((zone) => ({ id: zone.id, label: zone.label }));\n }\n\n /**\n * Client-side premium pre-pass: find the best contiguous block of `qty`\n * PREMIUM-flagged free seats (orphan-avoiding, closest to the focal point)\n * using the local seat geometry + live availability, mirroring the server's\n * held-back exclusion via the visible (hidden-stripped) chart and current\n * seat status. Returns a FULL premium block of `qty`, or null when none\n * exists (the caller then falls back to the normal server pick).\n */\n private pickPremiumBlock(qty: number, categoryKey?: string, zoneId?: string): string[] | null {\n const doc = this.visibleDoc();\n if (!doc?.objects?.length) return null;\n const focal = doc.focalPoint ?? { x: 0, y: 0 };\n const groupedObjectIds = new Set(this.groupedTablesByObject.keys());\n // Group chairs are geometry, never adjacency inventory. Excluding their\n // rowIds prevents premium fallback from bridging/splitting a table.\n const seats = expandChart(doc).filter((seat) => !groupedObjectIds.has(seat.rowId));\n const held = new Set(this.hold_?.labels ?? []);\n const available = new Set<string>();\n for (const seat of seats) {\n if (held.has(seat.label)) continue;\n const id = this.labelToId.get(seat.label);\n const status = id ? this.getStatus(id) : undefined;\n if ((status ?? 'free') === 'free') available.add(seat.label);\n }\n const pick = pickBestAvailable(seats, available, { qty, categoryKey, zoneId, focal, preferPremium: true });\n if (pick.labels.length !== qty) return null;\n // Only treat it as a premium block when EVERY picked seat is premium — a\n // partial run means there's no true premium block of `qty` to offer.\n const allPremium = pick.labels.every((l) => this.labelToSeat.get(l)?.commercial?.premium);\n return allPremium ? [...pick.labels] : null;\n }\n\n /**\n * Server-picks `qty` best free seats and holds them atomically. Throws on\n * failure. With `preferPremium`, first tries to hold the best PREMIUM block\n * locally; when none matches the requested quantity it falls back to the\n * normal server pick (the widget surfaces a subtle note on that fallback).\n *\n * `ttlMs` is the host's checkout window and MUST reach both branches: a hold\n * born here is the same buyer commitment as one made by clicking seats, so\n * omitting it silently handed the buyer the server default instead.\n */\n async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: { preferPremium?: boolean; zoneId?: string; ttlMs?: number } = {},\n ): Promise<HoldInfo | null> {\n const r = this.renderer;\n if (!r) return null;\n if (opts.preferPremium) {\n const block = this.pickPremiumBlock(qty, categoryKey, opts.zoneId);\n if (block) {\n // Drop any prior auto-hold before claiming the premium block.\n if (this.hold_ && !(await this.release())) return null;\n try {\n const selection = block.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 const result = await this.api.hold(this.key, selection, opts.ttlMs);\n r.clearSelection();\n const ids = this.idsForLabels(block);\n if (ids.length) r.setStatus(ids, 'held');\n this.setHold({ holdId: result.holdId, labels: [...block], expiresAt: result.expiresAt, items: result.items });\n const seats = block\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') {\n this.opts.onSalesClosed?.();\n throw err;\n }\n // Lost a race for the premium block (a seat was taken) — fall through\n // to the atomic server pick below rather than failing the buyer.\n }\n }\n // No premium block available — fall through to the normal server pick.\n }\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, opts.zoneId, opts.ttlMs);\n r.clearSelection();\n const ids = this.idsForLabels(result.labels);\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 * `ttlMs` only matters on the hold-first path: if the book call then fails, the\n * seats sit held for the host's window rather than the longer server default.\n */\n async book(bookingRef: string, labelsArg?: string[], ttlMs?: number): 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 ?? this.getSelection().map((seat) => seat.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 {\n label,\n ...(resolved?.tierId ? { tierId: resolved.tierId } : {}),\n ...this.tableQuantityRequest(resolved),\n };\n }),\n ttlMs,\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 = this.idsForLabels(takenLabels);\n if (takenIds.length) {\n r.setStatus(takenIds, 'booked');\n r.deselect(takenIds);\n this.resetTableQuantitiesForLabels(takenLabels);\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 = this.idsForLabels(labels);\n if (ids.length) {\n r.setStatus(ids, 'booked');\n r.deselect(ids);\n }\n this.clearHold();\n this.resetTableQuantitiesForLabels(labels);\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 this.resetTableQuantitiesForLabels(hold.labels);\n const ids = this.idsForLabels(hold.labels);\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 this.resetTableQuantitiesForLabels(drop);\n const ids = this.idsForLabels(drop);\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. No-op on a flat-only renderer. */\n setViewMode(mode: RendererViewMode): void {\n this.renderer?.setViewMode?.(mode);\n }\n getViewMode(): RendererViewMode {\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 const seenTables = new Set<string>();\n let seatsLeft = 0;\n for (const sid of memberIds) {\n const seat = this.seatById.get(sid);\n if (!seat) continue;\n const table = this.groupedTableBySeatId.get(sid);\n if (table) {\n if (seenTables.has(table.label)) continue;\n seenTables.add(table.label);\n byCat.set(table.categoryKey, (byCat.get(table.categoryKey) ?? 0) + table.maxOccupancy);\n if (r.getStatus(table.chairs[0]?.id ?? sid) === 'free') seatsLeft += table.maxOccupancy;\n } else {\n byCat.set(seat.categoryKey, (byCat.get(seat.categoryKey) ?? 0) + 1);\n if (r.getStatus(sid) === 'free') seatsLeft++;\n }\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.displayLabel ?? sec.label,\n zoneLabel: zone?.label ?? '',\n ...(sec.entrance && sec.entrance.trim() ? { entrance: sec.entrance.trim() } : {}),\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.realtime) {\n try {\n this.realtime.stop();\n } catch {\n /* ignore */\n }\n this.realtime = 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 table = this.groupedTableBySeatId.get(s.id);\n if (table) return this.toTableSeat(table);\n const commercial = s.commercial ? { commercial: s.commercial } : undefined;\n const display = s.displayLabel ? { displayLabel: s.displayLabel } : undefined;\n const accessibility = s.accessibility?.length ? { accessibility: s.accessibility } : undefined;\n const wheelchair = s.wheelchairSpaceType ? { wheelchairSpaceType: s.wheelchairSpaceType } : undefined;\n const context = this.seatContext.get(s.id);\n const tiers = this.tiersFor(s.categoryKey);\n if (!tiers) {\n return { id: s.id, label: s.label, ...display, ...context, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), ...commercial, ...accessibility, ...wheelchair };\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 ...display,\n ...context,\n categoryKey: s.categoryKey,\n price: chosen.price,\n tiers,\n tierId: chosen.id,\n ...commercial,\n ...accessibility,\n ...wheelchair,\n };\n }\n\n private toTableSeat(table: GroupedTableInventoryUnit): TableSelectionDetails {\n const representative = table.chairs[0];\n const tiers = this.tiersFor(table.categoryKey);\n const chosen = tiers?.find((tier) => tier.id === this.seatTiers.get(representative?.id ?? '')) ?? tiers?.[0];\n return {\n id: representative?.id ?? table.objectId,\n label: table.label,\n displayLabel: table.displayLabel ?? table.label,\n ...(table.displayType ? { displayType: table.displayType, rowType: table.displayType } : {}),\n objectId: table.objectId,\n sectionLabel: representative ? this.seatContext.get(representative.id)?.sectionLabel : undefined,\n rowLabel: table.displayLabel ?? table.label,\n categoryKey: table.categoryKey,\n price: chosen?.price ?? this.priceFor(table.categoryKey),\n ...(tiers ? { tiers, tierId: chosen?.id } : {}),\n objectType: 'table',\n bookingMode: table.mode,\n quantity: this.tableQuantities.get(table.label)\n ?? (table.mode === 'whole' ? table.capacity : table.minOccupancy),\n capacity: table.capacity,\n minOccupancy: table.minOccupancy,\n maxOccupancy: table.maxOccupancy,\n physicalSeatIds: table.chairs.map((chair) => chair.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 const quantities = new Map((h.items ?? []).map((item) => [item.label, item.quantity ?? 1]));\n return labels.every((label) => {\n const seat = this.labelToSeat.get(label);\n const resolved = seat ? this.toSeat(seat) : null;\n const currentTier = resolved?.tierId ?? null;\n const quantityMatches = resolved?.objectType !== 'table'\n || (resolved.bookingMode !== 'variable' || this.confirmedVariableTables.has(label))\n && (!quantities.has(label) || quantities.get(label) === resolved.quantity);\n return quantityMatches && (!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 = this.idsForLabels(conflicts.map((conflict) => conflict.label));\n if (takenIds.length) {\n r.deselect(takenIds);\n r.setStatus(takenIds, 'held');\n this.resetTableQuantitiesForLabels(conflicts.map((conflict) => conflict.label));\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 for (const item of hold.items ?? []) {\n if (this.groupedTablesByLabel.has(item.label) && item.quantity != null) {\n this.tableQuantities.set(item.label, item.quantity);\n if (this.groupedTablesByLabel.get(item.label)?.mode === 'variable') {\n this.confirmedVariableTables.add(item.label);\n }\n }\n }\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 this.idsForLabels(full.labels),\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, snap.default ?? 'free');\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.statusOf(label) === 'held')) {\n this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 1_000);\n return;\n }\n this.clearHold();\n this.opts.onHoldExpired?.();\n }\n\n /**\n * Repaint from an authoritative map of unit statuses.\n *\n * `defaultStatus` is what every unit NOT named in `seats` is. The verbose HTTP\n * route names every unit and leaves it at `free`; the compact realtime frame\n * names only the exceptions and states its own default, which on a mostly-sold\n * event is `booked` rather than `free`. Applying a compact map while assuming\n * `free` would paint a sold-out stadium as fully available, so the default is\n * a parameter rather than a constant.\n */\n private applySeatsMap(seats: Record<string, string>, defaultStatus = 'free'): void {\n const r = this.renderer;\n if (!r) return;\n this.liveStatuses = new Map(Object.entries(seats));\n this.liveDefault = defaultStatus;\n const defaultSeatStatus = mapStatus(defaultStatus);\n if (this.allIds.length) r.setStatus(this.allIds, defaultSeatStatus);\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.idsForLabels(this.hold_?.labels ?? []),\n );\n const byStatus: Record<SeatStatus, string[]> = { free: [], held: [], booked: [], not_for_sale: [] };\n for (const [label, st] of Object.entries(seats)) {\n byStatus[mapStatus(st)].push(...this.idsForLabel(label));\n }\n // Every status EXCEPT the one the reset pass just painted. With the verbose\n // map that skips `free` exactly as before; with a compact `booked` default\n // it is the free seats that need painting back.\n (['free', 'held', 'booked', 'not_for_sale'] as SeatStatus[]).forEach((st) => {\n if (st !== defaultSeatStatus && byStatus[st].length) r.setStatus(byStatus[st], st);\n });\n // Clear a completed checkout hold before notifying the widget. `onStatusChange`\n // is where SeatPicker detects a booking; notifying first left the hosted\n // buyer stranded on \"Continue to checkout\" even though the API had booked\n // the seats successfully.\n this.clearBookedHoldIfSettled();\n this.opts.onStatusChange?.();\n }\n\n /** The live status of one unit, honouring the projection's default. */\n private statusOf(label: string): string {\n return this.liveStatuses.get(label) ?? this.liveDefault;\n }\n\n private clearBookedHoldIfSettled(): void {\n const hold = this.hold_;\n if (hold?.labels.every((label) => this.statusOf(label) === 'booked')) {\n this.clearHold();\n this.resetTableQuantitiesForLabels(hold.labels);\n }\n }\n\n private async resnapshot(): Promise<void> {\n try {\n const objs = await this.api.objects(this.key);\n this.applySeatsMap(objs.seats, objs.default ?? 'free');\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 /**\n * The sink a transport-owned v1 client pushes into.\n *\n * Deliberately byte-compatible with the inline socket handler below: the same\n * liveStatuses bookkeeping (which the hold-expiry verification reads), the\n * same one-call-per-status paint, the same free→taken flash rule that skips\n * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the\n * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same\n * callbacks in the same order whichever path is live.\n */\n private realtimeSink(): PickerRealtimeSink {\n return {\n applyStatuses: (changes) => this.applyStatusChanges(changes),\n applyProjection: (projection) => this.applySeatsMap(projection.exceptions, projection.default),\n resync: () => this.resnapshot(),\n onSections: (hidden, closed) => {\n // Hidden sections STRIP seats, so the chart is rebuilt and repainted\n // from an authoritative snapshot; closed sections are a cheap grey\n // restyle. Same reconciliation the inline handler does — an\n // access-scoped picker only repaints statuses here, this one restructures.\n const rebuilt = this.syncHidden(hidden);\n const restyled = this.syncClosed(closed);\n if (rebuilt) void this.resnapshot();\n if (rebuilt || restyled) this.opts.onStatusChange?.();\n },\n };\n }\n\n /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */\n private applyStatusChanges(changes: PickerStatusChange[]): void {\n const r = this.renderer;\n if (!r) return;\n for (const ch of changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const ids = this.idsForLabel(ch.label);\n if (!ids.length) 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 ids.some((id) => 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 ids.forEach((id) => r.flashSeat(id, next === 'held' ? '#f4b740' : '#f43f5e'));\n }\n r.setStatus(ids, 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 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\n // Preferred path: the transport owns a `seatlayer.v1` client. An anonymous\n // buyer gets exactly what a private-channel one gets — a compact snapshot\n // instead of every unit of the event, and a resume on reconnect instead of\n // a fresh full snapshot. The client also owns the reconnect, so nothing\n // below runs and there is no second backoff to keep in step.\n if (!this.realtime && this.api.createRealtime) {\n let connection: PickerRealtimeConnection | null = null;\n try {\n connection = this.api.createRealtime(this.key, this.realtimeSink());\n } catch {\n connection = null; // fall through to the plain socket\n }\n if (connection) {\n this.realtime = connection;\n connection.start();\n return;\n }\n }\n if (this.realtime) return;\n\n let ws: WebSocket;\n try {\n const protocols = this.api.socketProtocols?.(this.key);\n ws = protocols && protocols.length ? new WebSocket(url, protocols) : 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 this.applyStatusChanges(m.changes);\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 /**\n * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its\n * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a\n * deterministic `2**attempt` schedule brings every browser that lost the same\n * socket back in the same millisecond, and an on-sale crowd reconnecting in\n * lockstep turns one blip into a thundering herd. The ceiling still doubles,\n * so a sustained outage still backs off.\n */\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.random() * 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 * Pure sightline math for the auto-360° generator — no DOM, no canvas — so it can\n * be unit-tested and reused headless. Kept out of `generatePanorama.ts` (which\n * touches `document`/`canvas`) on purpose.\n */\nimport { SEATED_EYE_HEIGHT_M } from '../core/units';\n\n// Stage extents in metres, relative to the flat-ground seated eye baseline — the\n// heights the legacy formulas implicitly baked into `atan2(5,…)` / `atan2(1.1,…)`.\nexport const STAGE_TOP_M = 5;\nexport const STAGE_BASE_M = -1.1;\n/** Plausibility cap: a raised seat never looks further DOWN than this at the stage. */\nexport const MAX_LOOKDOWN_DEG = 35;\n\n/**\n * Pitch (deg) to the top and base of the stage for a seat whose eye sits\n * `eyeHeightM` above the focal/stage datum, `distM` metres away horizontally.\n *\n * A flat, ground-level seat (`eyeHeightM = SEATED_EYE_HEIGHT_M`) reproduces the\n * legacy `atan2(5,distM)` / `-atan2(1.1,distM)` byte-for-byte. A raised/raked seat\n * (larger `eyeHeightM`) looks DOWN at the stage: both pitches drop and go negative,\n * capped at `MAX_LOOKDOWN_DEG` of depression so a top-balcony view stays plausible.\n */\nexport function stageSightlinePitch(eyeHeightM: number, distM: number): { topPitch: number; basePitch: number } {\n const extraEyeM = eyeHeightM - SEATED_EYE_HEIGHT_M; // 0 for a flat ground-level seat\n let topPitch = (Math.atan2(STAGE_TOP_M - extraEyeM, distM) * 180) / Math.PI;\n let basePitch = (Math.atan2(STAGE_BASE_M - extraEyeM, distM) * 180) / Math.PI;\n if (basePitch < -MAX_LOOKDOWN_DEG) {\n // Shift the whole stage up so the base rests at the depression cap, preserving\n // its angular height (top stays above base).\n topPitch += -MAX_LOOKDOWN_DEG - basePitch;\n basePitch = -MAX_LOOKDOWN_DEG;\n }\n return { topPitch, basePitch };\n}\n","/**\n * Synthetic view-from-seat panorama, generated from chart geometry alone.\n *\n * Draws a 2048×1024 equirectangular texture of the hall as seen from THIS seat.\n * Everything is placed from geometry the viewer already carries — the seat's\n * position, its per-seat eye height (which already bakes in its section's\n * height + rake + row rise), and every other seat's position + eye height:\n *\n * • the SCENE at the correct bearing/angular size, chosen from the chart's own\n * geometry — a proscenium theatre stage, an in-the-round centre-stage deck,\n * or a flat sports playing surface (see {@link classifyScene});\n * • the SURROUNDING STANDS — other sections drawn as darker raked banks\n * rising to the pitch of their highest seat at their true bearing (upper\n * tiers loom higher, a pit sits below the horizon), so the buyer senses the\n * bowl wrapping around them;\n * • a BALCONY-OVERHANG ceiling lip where a high, near section sits overhead;\n * • the AUDIENCE — nearby people drawn as stylised head/neck/shoulder\n * silhouettes at their true bearing, rising behind and dropping in front\n * with the rake, near rows occluding far ones (painter's order).\n *\n * Used whenever the organizer hasn't uploaded a real photo/360 for the seat;\n * both go through the same viewer, and the designer preview reuses this exact\n * generator so authors see what buyers will.\n *\n * Height data drives the extra depth: a FLAT chart (no eye-height spread) draws\n * only the plain dark hall + scene + audience it always has — no raked masses,\n * no overhang, nothing invented from absent data.\n *\n * SCENE + PER-VENUE VARIATION. The picker hands this generator only seats — never\n * the stage object — so scene TYPE is inferred from the audience geometry around\n * the focal point (a bowl that wraps ~360° with a small central void is a\n * centre-stage arena; a large elongated void is a sports surface; a one-sided\n * audience is a proscenium theatre), and a stable per-chart seed (hashed from the\n * seat count + section ids + focal) drives backdrop hue, lighting tint and rig\n * layout so every venue looks like its own place. All deterministic: same\n * chart + seat ⇒ byte-identical texture (no Date, no Math.random).\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';\nimport { METRES_PER_CHART_UNIT, SEATED_EYE_HEIGHT_M } from '../core/units';\nimport { stageSightlinePitch } from './sightline';\n\nconst W = 2048;\nconst H = 1024;\n/** Chart units → meters, for plausible eye-level proportions (seatSpacing 24 ≈ 0.55m). */\nconst UNIT = METRES_PER_CHART_UNIT;\nconst TAU = Math.PI * 2;\n/** Equirectangular vertical resolution: pixels per degree of pitch. */\nconst PX_PER_DEG = H / 180;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\n// --- deterministic helpers ---------------------------------------------------\n\n/** FNV-1a → uint32, for a stable seed from a string descriptor. */\nfunction fnv1a(str: string): number {\n let h = 2166136261;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 16777619);\n }\n return h >>> 0;\n}\n\n/** mulberry32 PRNG — seeded, deterministic, for per-venue dressing choices. */\nfunction rng(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n// --- surrounding-stands model ------------------------------------------------\n// The buyer picker (SDK-owned, unmodifiable) hands us the full expanded seat\n// list, not raw section outlines — so we reconstruct each OTHER section as a\n// ring of yaw bins from its member seats. Each seat's `eyeHeightM` already\n// encodes its section's height + rake + drawn row rise (see layout.assignEye-\n// Heights), so the bank rises to exactly the pitch a real spectator would see.\n// Deriving from seats (not outlines) is also what keeps the buyer and the\n// designer preview pixel-identical: both feed the same expanded list in.\n\nconst NBINS = 96;\nconst BIN_DEG = 360 / NBINS;\n/** Below this eye-height spread (m) the venue reads as flat: no raked banks, no\n * overhang — the plain dark hall is the honest floor for a flat chart. */\nconst FLAT_DELTA_M = 0.6;\n/** Mid sky tone the distance haze blends banks toward (matches the shell). */\nconst HAZE_SKY: [number, number, number] = [17, 23, 42];\n\ntype RGB = [number, number, number];\n\nfunction blendToSky(base: RGB, t: number, a = 1): string {\n // Distance haze: blend toward the sky, but keep more of the band's own colour\n // at distance than before (cap 0.58, was 0.72) so far stands stay legible\n // architecture rather than dissolving into flat silhouettes.\n const k = Math.max(0, Math.min(0.58, t));\n const r = Math.round(base[0] + (HAZE_SKY[0] - base[0]) * k);\n const g = Math.round(base[1] + (HAZE_SKY[1] - base[1]) * k);\n const b = Math.round(base[2] + (HAZE_SKY[2] - base[2]) * k);\n return `rgba(${r},${g},${b},${a})`;\n}\n\nfunction mixRgb(a: RGB, b: RGB, t: number): RGB {\n return [\n Math.round(a[0] + (b[0] - a[0]) * t),\n Math.round(a[1] + (b[1] - a[1]) * t),\n Math.round(a[2] + (b[2] - a[2]) * t),\n ];\n}\n\nfunction hslToRgb(h: number, s: number, l: number): RGB {\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const hp = (((h % 360) + 360) % 360) / 60;\n const x = c * (1 - Math.abs((hp % 2) - 1));\n let r = 0, g = 0, b = 0;\n if (hp < 1) [r, g, b] = [c, x, 0];\n else if (hp < 2) [r, g, b] = [x, c, 0];\n else if (hp < 3) [r, g, b] = [0, c, x];\n else if (hp < 4) [r, g, b] = [0, x, c];\n else if (hp < 5) [r, g, b] = [x, 0, c];\n else [r, g, b] = [c, 0, x];\n const m = l - c / 2;\n return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];\n}\n\n/**\n * A stable, DESATURATED tint for a section from its category key. The panorama\n * has no access to the doc's category→colour map (its signature takes only\n * seats), so it derives a deterministic hue per category and mutes it hard —\n * same spirit as the 3D tier tinting in sceneModel.tintTop: enough to tell\n * adjacent sections apart as coloured architecture, never a saturated poster.\n */\nconst tintCache = new Map<string, RGB>();\nfunction tintFromKey(key: string | undefined): RGB | null {\n if (!key) return null;\n const cached = tintCache.get(key);\n if (cached) return cached;\n let h = 2166136261;\n for (let i = 0; i < key.length; i++) { h ^= key.charCodeAt(i); h = Math.imul(h, 16777619); }\n const hue = (h >>> 0) % 360;\n const rgb = hslToRgb(hue, 0.3, 0.42);\n tintCache.set(key, rgb);\n return rgb;\n}\n\ninterface StandBin {\n /** Pitch (deg) to the highest seat's head in this bin — the bank crest. */\n top: number;\n /** Pitch (deg) to the section's seat surface — its front-edge base. */\n base: number;\n /** Nearest member distance (m) in this bin, for the distance haze. */\n nearM: number;\n /** A high, near mass overhead → hint a balcony ceiling lip. */\n overhead: boolean;\n /** Desaturated section-colour hint (from the nearest member's category). */\n tint: RGB | null;\n}\n\n/**\n * Bin the OTHER sections' member seats by bearing into a surrounding ring.\n * Returns `maxDelta` (the largest eye-height difference seen) so the caller can\n * fall back to the flat hall when there is no real relief to draw.\n */\nfunction buildStands(\n seat: ExpandedSeat,\n neighborSeats: ExpandedSeat[],\n stageBearing: number,\n myEyeM: number,\n): { bins: (StandBin | null)[]; maxDelta: number } {\n const bins: (StandBin | null)[] = new Array(NBINS).fill(null);\n let maxDelta = 0;\n const own = seat.sectionId;\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const os = other.sectionId;\n // Own section is the foreground crowd (drawn as heads + a seat-back rail);\n // seats with no section can't be attributed to a bank, so skip them.\n if (!os || (own && os === own)) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const dM = Math.hypot(ox, oy) * UNIT;\n if (dM < 1.5 || dM > 95) continue;\n const otherEye = other.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const dTop = otherEye - myEyeM;\n if (Math.abs(dTop) > maxDelta) maxDelta = Math.abs(dTop);\n const top = (Math.atan2(dTop, dM) * 180) / Math.PI;\n const base = (Math.atan2(otherEye - SEATED_EYE_HEIGHT_M - myEyeM, dM) * 180) / Math.PI;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = (((bearing * 180) / Math.PI + 540) % 360) - 180;\n const idx = Math.min(NBINS - 1, Math.max(0, Math.floor((yaw + 180) / BIN_DEG)));\n const overhead = top > 34 && dM < 16;\n const cur = bins[idx];\n if (!cur) bins[idx] = { top, base, nearM: dM, overhead, tint: tintFromKey(other.categoryKey) };\n else {\n if (top > cur.top) cur.top = top;\n if (base < cur.base) cur.base = base;\n // The nearest member drives the visible tint (it fills most of the bank).\n if (dM < cur.nearM) { cur.nearM = dM; cur.tint = tintFromKey(other.categoryKey); }\n cur.overhead = cur.overhead || overhead;\n }\n }\n return { bins, maxDelta };\n}\n\n/**\n * Paint the binned banks: each is a dark raked mass from its crest down past the\n * horizon (so it reads solid, never floating), hazed by distance, with faint row\n * banding and — where a high near mass sits overhead — a balcony ceiling lip.\n */\nfunction drawStands(\n ctx: CanvasRenderingContext2D,\n bins: (StandBin | null)[],\n toX: (yawDeg: number) => number,\n toY: (pitchDeg: number) => number,\n): void {\n for (let i = 0; i < NBINS; i++) {\n const b = bins[i];\n if (!b) continue;\n const yaw0 = -180 + i * BIN_DEG;\n const x0 = toX(yaw0);\n const x1 = toX(yaw0 + BIN_DEG);\n if (!(x1 > x0)) continue; // equirect seam inside this bin → skip the sliver\n const top = Math.min(72, b.top);\n const bottom = Math.min(b.base, -4); // always reach just past the horizon\n const yTop = toY(top);\n const yBot = toY(bottom);\n if (yBot <= yTop) continue;\n const haze = b.nearM / 95;\n // Fold the section's desaturated colour hint into the bank so the panorama\n // and the 3D view read as the same venue. Kept subtle (~0.34) and only on\n // the lit upper stops so the shadowed facade stays neutral.\n const tint = b.tint;\n const crest: RGB = tint ? mixRgb([44, 54, 80], tint, 0.34) : [44, 54, 80];\n const seating: RGB = tint ? mixRgb([24, 30, 48], tint, 0.28) : [24, 30, 48];\n const grad = ctx.createLinearGradient(0, yTop, 0, yBot);\n grad.addColorStop(0, blendToSky(crest, haze)); // lit seat-row crest\n grad.addColorStop(0.24, blendToSky(seating, haze)); // seating\n grad.addColorStop(1, blendToSky([10, 13, 22], haze)); // facade into shadow\n ctx.fillStyle = grad;\n ctx.fillRect(x0, yTop, x1 - x0 + 1, yBot - yTop);\n // crest edge: a faint lit rim so the bank top reads as a hard architectural\n // line even far away (distance no longer melts it into the sky).\n ctx.fillStyle = `rgba(150,165,205,${0.35 * (1 - haze * 0.55)})`;\n ctx.fillRect(x0, yTop, x1 - x0 + 1, 1.5);\n // tier-band striping on the seated portion (crest down to the horizon):\n // alternating lit/shadow rows so distant stands read as populated tiers, not\n // a flat wash. More bands + higher contrast than before.\n const bandBottom = Math.min(yBot, toY(0));\n const bandSpan = bandBottom - yTop;\n if (bandSpan > 8) {\n const bands = 6;\n const contrast = 1 - haze * 0.4;\n for (let r = 1; r < bands; r++) {\n const y = yTop + (bandSpan * r) / bands;\n ctx.fillStyle = `rgba(0,0,0,${0.16 * contrast})`; // seat-row shadow gap\n ctx.fillRect(x0, y, x1 - x0 + 1, 1.5);\n ctx.fillStyle = `rgba(120,134,170,${0.1 * contrast})`; // lit seat-back band\n ctx.fillRect(x0, y + 1.5, x1 - x0 + 1, 1.2);\n }\n }\n // balcony overhang: a dark ceiling lip fading down onto the crest\n if (b.overhead) {\n const lipY = toY(Math.min(86, top + 12));\n const g2 = ctx.createLinearGradient(0, lipY, 0, yTop);\n g2.addColorStop(0, 'rgba(3,4,8,0.9)');\n g2.addColorStop(1, 'rgba(3,4,8,0)');\n ctx.fillStyle = g2;\n ctx.fillRect(x0, lipY, x1 - x0 + 1, yTop - lipY);\n ctx.fillStyle = 'rgba(120,130,160,0.14)'; // faint lit underside rim\n ctx.fillRect(x0, yTop - 1.5, x1 - x0 + 1, 1.5);\n }\n }\n}\n\n// --- scene classification ----------------------------------------------------\n// The generator never sees the stage object (its signature takes only seats), so\n// scene TYPE is inferred from where the audience sits around the focal point:\n// • a bowl wrapping ~360° with a SMALL central void → in-the-round centre-stage;\n// • a bowl wrapping ~360° with a LARGE, elongated void → a sports playing surface;\n// • a one-sided audience → a proscenium theatre.\n// A per-chart seed (seat count + section ids + focal) drives the dressing.\n\ntype SceneMode = 'proscenium' | 'arena' | 'sport';\ninterface Scene {\n mode: SceneMode;\n seed: number;\n /** Median radius (m) of the central void the audience rings — the performance area. */\n voidRadiusM: number;\n /** Elongation of the void (long axis / short axis); ~1 round, ~2 a rink. */\n aspect: number;\n}\n\nfunction classifyScene(_seat: ExpandedSeat, focal: Point, neighbors: ExpandedSeat[]): Scene {\n const NB = 72;\n const occ = new Array<boolean>(NB).fill(false);\n const innerM = new Array<number>(NB).fill(Infinity);\n const secSet = new Set<string>();\n let n = 0;\n for (const s of neighbors) {\n n++;\n if (s.sectionId) secSet.add(s.sectionId);\n const dx = s.x - focal.x;\n const dy = s.y - focal.y;\n const dM = Math.hypot(dx, dy) * UNIT;\n if (dM < 0.5) continue;\n const bearing = Math.atan2(dx, -dy); // −π..π, 0 = toward focal's −y\n let idx = Math.floor(((bearing + Math.PI) / TAU) * NB);\n if (idx < 0) idx = 0; else if (idx >= NB) idx = NB - 1;\n occ[idx] = true;\n if (dM < innerM[idx]) innerM[idx] = dM;\n }\n let occN = 0;\n const inner: number[] = [];\n for (let i = 0; i < NB; i++) if (occ[i]) { occN++; inner.push(innerM[i]); }\n const coverage = (occN / NB) * 360;\n inner.sort((a, b) => a - b);\n const median = inner.length ? inner[inner.length >> 1] : 0;\n const lo = inner.length ? (inner[Math.floor(inner.length * 0.15)] ?? median) : 0;\n const hi = inner.length ? (inner[Math.floor(inner.length * 0.85)] ?? median) : 0;\n const aspect = lo > 0.5 ? hi / lo : 1;\n const seed = fnv1a(`${n}|${[...secSet].sort().join(',')}|${Math.round(focal.x)},${Math.round(focal.y)}`);\n\n let mode: SceneMode;\n if (coverage >= 300 && median > 11 && aspect > 1.35) mode = 'sport';\n else if (coverage >= 285) mode = 'arena';\n else mode = 'proscenium';\n return { mode, seed, voidRadiusM: median, aspect };\n}\n\n// --- stylised human silhouettes ----------------------------------------------\n// Theatre-poster silhouettes, NOT photoreal: a slightly-oval head, a visible neck\n// gap, and shoulders that slope from the neck (a trapezius curve) into upper arms.\n// Deterministic per seat/performer index — head size/tilt, hair outline, shoulder\n// width and clothing tone all vary so no two neighbours are identical.\n\nconst HAIR_KINDS = 5; // 0 short · 1 full · 2 tied/bun · 3 cap · 4 long\n\n/** Hair as extra silhouette shapes on top of the base head oval (local head coords). */\nfunction drawHair(ctx: CanvasRenderingContext2D, r: number, kind: number): void {\n switch (kind) {\n case 1: // full / bushy — a larger rounded mass sitting over and around the head\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.14, r * 1.16, r * 1.16, 0, 0, TAU);\n ctx.fill();\n break;\n case 2: // tied back — a bun above the crown\n ctx.beginPath();\n ctx.ellipse(0, -r * 1.02, r * 0.42, r * 0.42, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.2, r * 0.98, r * 1.02, 0, 0, TAU);\n ctx.fill();\n break;\n case 3: // cap / hat — flattened crown with a small forward brim\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.36, r * 1.04, r * 0.6, 0, Math.PI, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.52, r * 1.22, r * 0.24, 0, 0, TAU); // brim\n ctx.fill();\n break;\n case 4: // long — hair falling past the neck on both sides\n ctx.beginPath();\n ctx.ellipse(-r * 0.66, r * 0.5, r * 0.5, r * 1.35, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(r * 0.66, r * 0.5, r * 0.5, r * 1.35, 0, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.08, r * 1.06, r * 1.08, 0, 0, TAU);\n ctx.fill();\n break;\n default: // short — the clean head oval already reads as short hair\n break;\n }\n}\n\ninterface SeatedOpts {\n tone: RGB;\n clothing: RGB;\n alpha: number;\n tilt: number; // head tilt, radians\n shoulderK: number; // shoulder half-width in head-radii\n hair: number;\n rim: number; // 0..1 warm rim strength on head/shoulder crown\n turn: number; // head yaw offset in head-radii (−0.12..0.12) — neighbours chat\n lean: number; // shoulder asymmetry in head-radii (one side rides higher)\n}\n\n/**\n * A seated spectator seen from behind: sloping shoulders (drawn first) with a\n * trapezius curve into the upper arms, then a narrower neck + head on top so the\n * neck gap reads, then a hair-variant silhouette and an optional warm rim.\n */\nfunction drawSeated(ctx: CanvasRenderingContext2D, hx: number, hy: number, r: number, o: SeatedOpts): void {\n const neckHalf = r * 0.44;\n const shHalf = r * o.shoulderK;\n const neckTopY = r * 0.66;\n const shoulderY = r * 1.68;\n const botY = r * 5.4; // runs off below the crop / into the seat back\n const clo = `rgba(${o.clothing[0]},${o.clothing[1]},${o.clothing[2]},${o.alpha})`;\n const skin = `rgba(${o.tone[0]},${o.tone[1]},${o.tone[2]},${o.alpha})`;\n\n ctx.save();\n ctx.translate(hx, hy);\n\n // shoulders + torso (clothing tone) — trapezius slope from neck to shoulder,\n // then upper-arm drop. Lean lifts one shoulder and drops the other so close\n // figures don't sit in a perfectly level row.\n const leanPx = o.lean * r;\n ctx.fillStyle = clo;\n ctx.beginPath();\n ctx.moveTo(-neckHalf, neckTopY);\n ctx.quadraticCurveTo(-neckHalf * 1.18, shoulderY - leanPx - r * 0.6, -shHalf, shoulderY - leanPx);\n ctx.quadraticCurveTo(-shHalf * 1.05, shoulderY + r * 1.2, -shHalf * 0.94, botY);\n ctx.lineTo(shHalf * 0.94, botY);\n ctx.quadraticCurveTo(shHalf * 1.05, shoulderY + r * 1.2, shHalf, shoulderY + leanPx);\n ctx.quadraticCurveTo(neckHalf * 1.18, shoulderY + leanPx - r * 0.6, neckHalf, neckTopY);\n ctx.closePath();\n ctx.fill();\n\n // neck column (head tone), narrower than both head and shoulders → the gap.\n ctx.fillStyle = skin;\n ctx.fillRect(-neckHalf * 0.82, r * 0.5, neckHalf * 1.64, r * 0.9);\n\n // head + hair, with a small tilt and a seeded turn (heads angled toward a\n // neighbour, not all facing dead ahead).\n ctx.save();\n ctx.rotate(o.tilt);\n ctx.translate(o.turn * r, 0);\n ctx.fillStyle = skin;\n if (r >= 18) {\n // Close-up head: a cranium-to-jaw egg, not a balloon — full crown up top,\n // cheeks tapering through the jaw to a narrower chin.\n ctx.beginPath();\n ctx.moveTo(-r * 0.9, -r * 0.15);\n ctx.quadraticCurveTo(-r * 0.96, -r * 1.12, 0, -r * 1.06);\n ctx.quadraticCurveTo(r * 0.96, -r * 1.12, r * 0.9, -r * 0.15);\n ctx.quadraticCurveTo(r * 0.86, r * 0.55, r * 0.36, r * 0.98);\n ctx.quadraticCurveTo(0, r * 1.14, -r * 0.36, r * 0.98);\n ctx.quadraticCurveTo(-r * 0.86, r * 0.55, -r * 0.9, -r * 0.15);\n ctx.closePath();\n ctx.fill();\n // ear hints — small lobes just below the head's widest line.\n if (r >= 22) {\n ctx.beginPath();\n ctx.ellipse(-r * 0.9, r * 0.18, r * 0.13, r * 0.22, 0, 0, TAU);\n ctx.ellipse(r * 0.9, r * 0.18, r * 0.13, r * 0.22, 0, 0, TAU);\n ctx.fill();\n }\n } else {\n ctx.beginPath();\n ctx.ellipse(0, 0, r * 0.9, r * 1.06, 0, 0, TAU);\n ctx.fill();\n }\n drawHair(ctx, r, o.hair);\n // warm rim catching the stage light on the crown + a shoulder edge.\n if (o.rim > 0.01) {\n ctx.strokeStyle = `rgba(245,205,150,${(0.5 * o.rim).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, r * 0.14);\n ctx.beginPath();\n ctx.ellipse(0, -r * 0.06, r * 0.86, r * 1.0, 0, Math.PI * 1.12, Math.PI * 1.9);\n ctx.stroke();\n }\n ctx.restore();\n\n if (o.rim > 0.01) {\n ctx.strokeStyle = `rgba(240,200,150,${(0.28 * o.rim).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, r * 0.12);\n ctx.beginPath();\n ctx.moveTo(-shHalf * 0.8, shoulderY - r * 0.05);\n ctx.quadraticCurveTo(-neckHalf, shoulderY - r * 0.75, 0, shoulderY - r * 0.82);\n ctx.quadraticCurveTo(neckHalf, shoulderY - r * 0.75, shHalf * 0.8, shoulderY - r * 0.05);\n ctx.stroke();\n }\n ctx.restore();\n}\n\n/** Cheap head+shoulders for the mid LOD band — a defined trapezius slope with a\n * visible neck notch (the near-LOD silhouette language, two curves cheaper). */\nfunction drawSeatedMid(ctx: CanvasRenderingContext2D, hx: number, hy: number, r: number, clothing: RGB, tone: RGB, alpha: number): void {\n ctx.fillStyle = `rgba(${clothing[0]},${clothing[1]},${clothing[2]},${alpha})`;\n ctx.beginPath();\n ctx.moveTo(hx - r * 1.72, hy + r * 4);\n ctx.quadraticCurveTo(hx - r * 1.78, hy + r * 1.55, hx - r * 0.46, hy + r * 1.02);\n ctx.lineTo(hx - r * 0.4, hy + r * 0.62); // neck notch, left\n ctx.lineTo(hx + r * 0.4, hy + r * 0.62); // neck notch, right\n ctx.lineTo(hx + r * 0.46, hy + r * 1.02);\n ctx.quadraticCurveTo(hx + r * 1.78, hy + r * 1.55, hx + r * 1.72, hy + r * 4);\n ctx.closePath();\n ctx.fill();\n ctx.fillStyle = `rgba(${tone[0]},${tone[1]},${tone[2]},${alpha})`;\n ctx.beginPath();\n ctx.ellipse(hx, hy, r * 0.9, r * 1.05, 0, 0, TAU);\n ctx.fill();\n}\n\ninterface PerformerOpts {\n tone: RGB;\n alpha: number;\n pose: number; // 0 neutral · 1 arms up · 2 instrument · 3 mic\n rim: RGB; // rim-light colour (from the scene lighting)\n rimStrength: number;\n}\n\n/**\n * A standing performer on the stage/deck: full body with varied poses, grounded\n * by a contact shadow on the deck. Same silhouette language as the audience.\n */\nfunction drawPerformer(ctx: CanvasRenderingContext2D, x: number, footY: number, h: number, o: PerformerOpts): void {\n const headR = h * 0.1;\n const headCy = footY - h * 0.9;\n const shoulderY = footY - h * 0.74;\n const hipY = footY - h * 0.46;\n const shHalf = h * 0.13;\n const hipHalf = h * 0.09;\n const skin = `rgba(${o.tone[0]},${o.tone[1]},${o.tone[2]},${o.alpha})`;\n\n // contact shadow — an elongated soft ellipse under the feet, on the deck.\n const sh = ctx.createRadialGradient(x, footY, 1, x, footY, h * 0.24);\n sh.addColorStop(0, 'rgba(0,0,0,0.4)');\n sh.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.save();\n ctx.scale(1, 0.28);\n ctx.fillStyle = sh;\n ctx.beginPath();\n ctx.ellipse(x, footY / 0.28, h * 0.24, h * 0.24, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n\n ctx.fillStyle = skin;\n // legs — two tapered columns to the feet.\n ctx.beginPath();\n ctx.moveTo(x - hipHalf, hipY);\n ctx.lineTo(x - hipHalf * 0.7, footY);\n ctx.lineTo(x - hipHalf * 0.1, footY);\n ctx.lineTo(x - hipHalf * 0.1, hipY + h * 0.02);\n ctx.lineTo(x + hipHalf * 0.1, hipY + h * 0.02);\n ctx.lineTo(x + hipHalf * 0.1, footY);\n ctx.lineTo(x + hipHalf * 0.7, footY);\n ctx.lineTo(x + hipHalf, hipY);\n ctx.closePath();\n ctx.fill();\n\n // torso — shoulders down to hips.\n ctx.beginPath();\n ctx.moveTo(x - shHalf, shoulderY);\n ctx.quadraticCurveTo(x - shHalf * 0.9, hipY - h * 0.12, x - hipHalf, hipY);\n ctx.lineTo(x + hipHalf, hipY);\n ctx.quadraticCurveTo(x + shHalf * 0.9, hipY - h * 0.12, x + shHalf, shoulderY);\n ctx.quadraticCurveTo(x, shoulderY - h * 0.05, x - shHalf, shoulderY);\n ctx.closePath();\n ctx.fill();\n\n // arms by pose.\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.strokeStyle = skin;\n ctx.lineWidth = h * 0.055;\n const armY = shoulderY + h * 0.02;\n if (o.pose === 1) {\n // arms up in a V.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x - shHalf * 1.5, footY - h * 1.02);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x + shHalf * 1.5, footY - h * 1.02);\n ctx.stroke();\n } else if (o.pose === 2) {\n // instrument: one arm across the body, a guitar body hint at the hip.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x + hipHalf * 1.4, hipY - h * 0.02);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x - hipHalf * 0.4, hipY - h * 0.06);\n ctx.stroke();\n ctx.fillStyle = skin;\n ctx.beginPath();\n ctx.ellipse(x + hipHalf * 1.5, hipY - h * 0.04, h * 0.07, h * 0.09, -0.5, 0, TAU);\n ctx.fill();\n } else if (o.pose === 3) {\n // mic stance: one arm up toward the head, a thin mic stand in front.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.8, armY);\n ctx.lineTo(x - shHalf * 0.2, headCy + headR * 0.6);\n ctx.moveTo(x + shHalf * 0.8, armY);\n ctx.lineTo(x + shHalf * 1.1, hipY);\n ctx.stroke();\n ctx.lineWidth = h * 0.02;\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.2, headCy + headR * 0.9);\n ctx.lineTo(x - shHalf * 0.2, footY - h * 0.02);\n ctx.stroke();\n } else {\n // neutral — arms at the sides.\n ctx.beginPath();\n ctx.moveTo(x - shHalf * 0.85, armY);\n ctx.lineTo(x - shHalf * 0.95, hipY + h * 0.02);\n ctx.moveTo(x + shHalf * 0.85, armY);\n ctx.lineTo(x + shHalf * 0.95, hipY + h * 0.02);\n ctx.stroke();\n }\n\n // neck + head.\n ctx.fillStyle = skin;\n ctx.fillRect(x - headR * 0.34, headCy + headR * 0.6, headR * 0.68, headR * 0.9);\n ctx.beginPath();\n ctx.ellipse(x, headCy, headR * 0.86, headR * 1.05, 0, 0, TAU);\n ctx.fill();\n\n // rim light on the figure's lit edge.\n if (o.rimStrength > 0.01) {\n ctx.strokeStyle = `rgba(${o.rim[0]},${o.rim[1]},${o.rim[2]},${(0.6 * o.rimStrength).toFixed(3)})`;\n ctx.lineWidth = Math.max(1, h * 0.02);\n ctx.beginPath();\n ctx.moveTo(x - shHalf, shoulderY);\n ctx.lineTo(x - headR * 0.6, headCy + headR * 0.4);\n ctx.moveTo(x - headR * 0.7, headCy);\n ctx.ellipse(x, headCy, headR * 0.84, headR * 1.02, 0, Math.PI * 1.05, Math.PI * 1.55);\n ctx.stroke();\n }\n}\n\n/** A tapered light-beam cone that ADDS light ('lighter' composite), strong at the\n * fixture and fading down. Narrow at the source (halfTop), wide at the target\n * pool (halfBot). */\nfunction drawBeam(\n ctx: CanvasRenderingContext2D,\n x0: number, y0: number, x1: number, y1: number,\n halfTop: number, halfBot: number, tint: string, strength: number,\n): void {\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n const g = ctx.createLinearGradient(0, y0, 0, y1);\n g.addColorStop(0, `rgba(${tint},${strength})`);\n g.addColorStop(0.5, `rgba(${tint},${(strength * 0.4).toFixed(3)})`);\n g.addColorStop(1, `rgba(${tint},0)`);\n ctx.fillStyle = g;\n ctx.beginPath();\n ctx.moveTo(x0 - halfTop, y0);\n ctx.lineTo(x1 - halfBot, y1);\n ctx.lineTo(x1 + halfBot, y1);\n ctx.lineTo(x0 + halfTop, y0);\n ctx.closePath();\n ctx.fill();\n ctx.restore();\n}\n\n/** A rig fixture: a bright dot with a soft halo where a beam originates. */\nfunction drawFixture(ctx: CanvasRenderingContext2D, x: number, y: number, r: number, tint: string): void {\n const g = ctx.createRadialGradient(x, y, 0, x, y, r * 3);\n g.addColorStop(0, `rgba(${tint},0.9)`);\n g.addColorStop(0.4, `rgba(${tint},0.35)`);\n g.addColorStop(1, `rgba(${tint},0)`);\n ctx.fillStyle = g;\n ctx.beginPath();\n ctx.arc(x, y, r * 3, 0, TAU);\n ctx.fill();\n ctx.fillStyle = `rgba(${tint},1)`;\n ctx.beginPath();\n ctx.arc(x, y, r, 0, TAU);\n ctx.fill();\n}\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 const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n\n const scene = classifyScene(seat, focalPoint, neighborSeats);\n const rand = rng(scene.seed);\n // Per-venue lighting identity: a base hue steers the backdrop, a cool rig tint\n // shifts a little off the default periwinkle, and a warm accent lights figures.\n const baseHue = 210 + rand() * 150; // violet → magenta → amber sweep\n const rigTint: RGB = hslToRgb(220 + (rand() - 0.5) * 60, 0.55, 0.82);\n const rigTintStr = `${rigTint[0]},${rigTint[1]},${rigTint[2]}`;\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#080b12');\n sky.addColorStop(0.42, '#12182c');\n sky.addColorStop(0.5, '#1c2440');\n sky.addColorStop(0.56, '#151b2c');\n sky.addColorStop(0.78, '#171e30');\n sky.addColorStop(1, '#131829');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // Ambient floor wash — a broad dim lift across the lower hall.\n const floorAmb = ctx.createLinearGradient(0, pitchToY(-6), 0, H);\n floorAmb.addColorStop(0, 'rgba(30, 37, 56, 0)');\n floorAmb.addColorStop(0.55, 'rgba(30, 37, 56, 0.22)');\n floorAmb.addColorStop(1, 'rgba(22, 28, 44, 0.12)');\n ctx.fillStyle = floorAmb;\n ctx.fillRect(0, pitchToY(-6), W, H - pitchToY(-6));\n\n // Bearing of the stage in screen coords (-y is \"up\" the hall).\n const stageBearing = Math.atan2(dx, -dy);\n\n // ---- surrounding stands: other sections as raked banks (all modes) ------\n const stands = buildStands(seat, neighborSeats, stageBearing, eyeM);\n const hasRelief = stands.maxDelta >= FLAT_DELTA_M;\n if (hasRelief) drawStands(ctx, stands.bins, yawToX, pitchToY);\n\n // Distance drama factor.\n const nearGlow = Math.max(0.3, Math.min(1, 1 - (distM - 6) / 60));\n\n // ---- the scene, centered at yaw 0 --------------------------------------\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(45, sightline.topPitch);\n const stageBasePitch = sightline.basePitch;\n\n if (scene.mode === 'sport') {\n drawSportScene(ctx, distM, eyeM, scene, nearGlow, baseHue, rigTintStr, rand);\n } else if (scene.mode === 'arena') {\n drawArenaScene(ctx, distM, eyeM, scene, nearGlow, rigTintStr, rand);\n } else {\n drawProsceniumScene(ctx, stageHalfYaw, stageTopPitch, stageBasePitch, nearGlow, baseHue, rigTintStr, rand);\n }\n\n // ---- rig lights along the ceiling all around ---------------------------\n // Sport gets even flood banks; performance venues get a warmer scattered rig.\n const rigCount = scene.mode === 'sport' ? 34 : 24 + Math.floor(rand() * 8);\n ctx.fillStyle = `rgba(${rigTintStr},0.8)`;\n for (let i = 0; i < rigCount; i++) {\n const x = ((i + 0.5) / rigCount) * W;\n const y = pitchToY(scene.mode === 'sport' ? 58 : 54 + ((i * 7) % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, scene.mode === 'sport' ? 2.6 : 3.2, 0, TAU);\n ctx.fill();\n }\n\n // ---- audience: stylised silhouettes of nearby seats --------------------\n drawAudience(ctx, seat, neighborSeats, focalPoint, stageBearing, eyeM, dx, dy, hasRelief, scene);\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.9, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.55)');\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// ---- scene drawers ----------------------------------------------------------\n\n/**\n * Proscenium theatre: a perspective arch (top valance + tapering legs) with dark\n * masking wings, a backdrop INSET in the opening that falls off softly at its\n * edges (never a hard rectangle floating in black), a lit stage-floor front edge\n * with footlights, tapered light-beam cones, and posed performer silhouettes.\n */\nfunction drawProsceniumScene(\n ctx: CanvasRenderingContext2D,\n stageHalfYaw: number,\n stageTopPitch: number,\n stageBasePitch: number,\n nearGlow: number,\n baseHue: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n const sw = sx1 - sx0;\n const sh = sy1 - sy0;\n const archTop = pitchToY(Math.min(50, stageTopPitch + 10));\n\n // Warm glow bloom behind the opening.\n const glowR = sw * (1.1 + (1 - nearGlow) * 0.5);\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 8, W / 2, (sy0 + sy1) / 2, glowR);\n glow.addColorStop(0, 'rgba(255, 214, 150, 0.34)');\n glow.addColorStop(0.28, 'rgba(150, 150, 230, 0.3)');\n glow.addColorStop(0.6, 'rgba(99, 102, 241, 0.12)');\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 // Backdrop inset — a seeded gradient painted only inside the opening, then a\n // soft edge falloff so it melts into the masking instead of a hard edge.\n const topCol = hslToRgb(baseHue, 0.62, 0.55);\n const midCol = hslToRgb(baseHue + 40, 0.7, 0.5);\n const botCol = hslToRgb(baseHue + 70, 0.78, 0.52);\n ctx.save();\n ctx.beginPath();\n ctx.rect(sx0, sy0, sw, sh);\n ctx.clip();\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, `rgb(${topCol[0]},${topCol[1]},${topCol[2]})`);\n backdrop.addColorStop(0.5, `rgb(${midCol[0]},${midCol[1]},${midCol[2]})`);\n backdrop.addColorStop(1, `rgb(${botCol[0]},${botCol[1]},${botCol[2]})`);\n ctx.globalAlpha = 0.8;\n ctx.fillStyle = backdrop;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.globalAlpha = 1;\n // Edge falloff: transparent centre → dark at the opening's borders.\n const fall = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, sw * 0.12, W / 2, (sy0 + sy1) / 2, sw * 0.62);\n fall.addColorStop(0, 'rgba(6,8,14,0)');\n fall.addColorStop(0.7, 'rgba(6,8,14,0.15)');\n fall.addColorStop(1, 'rgba(5,6,11,0.92)');\n ctx.fillStyle = fall;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.restore();\n\n // Performers on the stage floor.\n const perfCount = 3 + Math.floor(rand() * 3);\n const perfH = sh * 0.46;\n const floorY = sy1 - sh * 0.08;\n for (let i = 0; i < perfCount; i++) {\n const t = (i + 1) / (perfCount + 1);\n const px = sx0 + sw * (0.22 + t * 0.56 + (rand() - 0.5) * 0.06);\n drawPerformer(ctx, px, floorY, perfH * (0.9 + rand() * 0.24), {\n tone: [8, 10, 16],\n alpha: 0.9,\n pose: Math.floor(rand() * 4),\n rim: hslToRgb(baseHue + 20, 0.5, 0.7),\n rimStrength: 0.7,\n });\n }\n\n // Masking wings — dark vertical legs beyond the opening.\n ctx.fillStyle = '#05070d';\n ctx.fillRect(sx0 - sw * 0.5, archTop, sw * 0.5, sy1 - archTop);\n ctx.fillRect(sx1, archTop, sw * 0.5, sy1 - archTop);\n\n // Perspective arch: legs lean inward slightly toward the top, a top beam/valance.\n const legBot = sw * 0.055 + 3; // leg thickness at the base\n const legTop = legBot * 1.35; // wider at the top (perspective)\n ctx.fillStyle = '#03050a';\n // left leg\n ctx.beginPath();\n ctx.moveTo(sx0, sy1);\n ctx.lineTo(sx0 - legBot, sy1);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.lineTo(sx0 + sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n // right leg\n ctx.beginPath();\n ctx.moveTo(sx1, sy1);\n ctx.lineTo(sx1 + legBot, sy1);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx1 - sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n // top beam.\n ctx.fillRect(sx0 - legTop, archTop, sw + legTop * 2, (sy1 - archTop) * 0.12);\n // valance: a soft draped border hanging below the beam.\n const valH = sh * 0.14;\n const valY = archTop + (sy1 - archTop) * 0.12;\n ctx.fillStyle = 'rgba(4,6,12,0.96)';\n const scallops = 7;\n ctx.beginPath();\n ctx.moveTo(sx0 - legTop, valY);\n for (let i = 0; i <= scallops; i++) {\n const xx = sx0 - legTop + ((sw + legTop * 2) * i) / scallops;\n ctx.quadraticCurveTo(xx - (sw + legTop * 2) / scallops / 2, valY + valH, xx, valY);\n }\n ctx.lineTo(sx1 + legTop, valY);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.closePath();\n ctx.fill();\n // faint lit inner rim on the arch legs.\n ctx.fillStyle = `rgba(${rigTintStr},0.12)`;\n ctx.fillRect(sx0 - 1.5, valY, 1.5, sy1 - valY);\n ctx.fillRect(sx1, valY, 1.5, sy1 - valY);\n\n // Stage floor front edge + footlight glow.\n ctx.fillStyle = '#0b0f18';\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.05 + 3);\n const foot = ctx.createLinearGradient(0, sy1 - sh * 0.05, 0, sy1 + sh * 0.12);\n foot.addColorStop(0, `rgba(255,206,140,${(0.5 * nearGlow).toFixed(3)})`);\n foot.addColorStop(1, 'rgba(255,206,140,0)');\n ctx.fillStyle = foot;\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.2);\n\n // Tapered light-beam cones from rig fixtures above the arch.\n const beams = 3 + Math.floor(rand() * 2);\n for (let i = 0; i < beams; i++) {\n const t = (i + 1) / (beams + 1);\n const fx = sx0 + sw * (t + (rand() - 0.5) * 0.08);\n const fy = pitchToY(Math.min(62, stageTopPitch + 26));\n const skew = (rand() - 0.5) * sw * 0.16;\n drawBeam(ctx, fx, fy, fx + skew, sy1, 4, sw * 0.09, rigTintStr, 0.16 * (0.7 + nearGlow * 0.5));\n drawFixture(ctx, fx, fy, 2.4, rigTintStr);\n }\n}\n\n/**\n * In-the-round centre-stage: an elevated elliptical deck with a lit rim and a\n * visible riser side, a truss ring above with hanging fixtures and tapered beam\n * cones onto the deck, a warm floor-spill pool, and performers standing ON the\n * deck. No proscenium — the opposite stands stay visible behind it.\n */\nfunction drawArenaScene(\n ctx: CanvasRenderingContext2D,\n distM: number,\n eyeM: number,\n scene: Scene,\n nearGlow: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n // Bound the deck radius so a seat AT the stage edge (distM ≈ void radius) can't\n // blow the near-edge pitch up to the pole — the deck never exceeds the viewer's\n // own distance, and the near edge stays a safe fraction of the way in.\n const stageR = Math.min(distM * 0.6, Math.max(3, scene.voidRadiusM));\n const halfYaw = Math.min(55, (Math.atan2(stageR, distM) * 180) / Math.PI);\n const cx = W / 2;\n const deckRiserM = 1.2;\n const nearDist = Math.max(distM * 0.45, distM - stageR);\n const farDist = distM + stageR;\n // Near/far edges of the deck top, in pitch.\n const nearTopPitch = (Math.atan2(deckRiserM - eyeM, nearDist) * 180) / Math.PI;\n const farTopPitch = (Math.atan2(deckRiserM - eyeM, farDist) * 180) / Math.PI;\n const nearBasePitch = (Math.atan2(-eyeM, nearDist) * 180) / Math.PI; // floor at the near edge\n const yNearTop = pitchToY(nearTopPitch);\n const yFarTop = pitchToY(farTopPitch);\n const yBase = pitchToY(nearBasePitch);\n const halfW = yawToX(halfYaw) - cx;\n const topRy = Math.max(6, (yNearTop - yFarTop) / 2); // ellipse vertical radius (foreshortened)\n const topCy = (yNearTop + yFarTop) / 2;\n\n // Floor-spill pool around the deck base.\n const pool = ctx.createRadialGradient(cx, yBase, 4, cx, yBase, halfW * 2.6);\n pool.addColorStop(0, `rgba(255,206,150,${(0.2 * nearGlow).toFixed(3)})`);\n pool.addColorStop(0.5, 'rgba(150,140,190,0.08)');\n pool.addColorStop(1, 'rgba(40,44,60,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = pool;\n ctx.fillRect(cx - halfW * 2.6, yFarTop - topRy, halfW * 5.2, yBase - yFarTop + topRy + 40);\n ctx.restore();\n\n // Riser side (the deck wall) — dark, from the near-top ellipse down to the floor.\n ctx.fillStyle = '#0c1019';\n ctx.beginPath();\n ctx.moveTo(cx - halfW, topCy);\n ctx.ellipse(cx, topCy, halfW, topRy, 0, Math.PI, 0, false);\n ctx.lineTo(cx + halfW, yBase);\n ctx.ellipse(cx, yBase, halfW, topRy, 0, 0, Math.PI, false);\n ctx.closePath();\n ctx.fill();\n // lit vertical seam on the riser front.\n const riser = ctx.createLinearGradient(0, topCy, 0, yBase);\n riser.addColorStop(0, `rgba(${rigTintStr},0.14)`);\n riser.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.fillStyle = riser;\n ctx.fillRect(cx - halfW, topCy, halfW * 2, yBase - topCy);\n\n // Compose the ensemble BEFORE painting the deck so the lighting can key onto\n // the lead performer instead of blooming dead-centre. Deck-local coords:\n // u across (−1..1, screen x), v depth (−1 far edge .. +1 near edge). The old\n // even line-up at exact centre read static — a real in-the-round act stands\n // in an asymmetric cluster with the frontman worked toward one side.\n interface PerfSpot { u: number; v: number; lead?: boolean; pose: number }\n const FORMATIONS: PerfSpot[][] = [\n // frontman + guitarist + one at the back\n [{ u: -0.24, v: 0.4, lead: true, pose: 3 }, { u: 0.34, v: -0.04, pose: 2 }, { u: -0.52, v: -0.38, pose: 0 }],\n // duo — singer forward, instrument behind the shoulder\n [{ u: 0.2, v: 0.34, lead: true, pose: 3 }, { u: -0.3, v: -0.08, pose: 2 }],\n // 4-piece — lead just off-centre, band staggered around the far half\n [{ u: -0.1, v: 0.28, lead: true, pose: 1 }, { u: 0.44, v: -0.2, pose: 2 }, { u: -0.46, v: -0.14, pose: 2 }, { u: 0.08, v: -0.46, pose: 0 }],\n ];\n const form = FORMATIONS[Math.floor(rand() * FORMATIONS.length)];\n const mirror = rand() < 0.5 ? -1 : 1; // seeded side, so venues differ\n const spotX = (p: PerfSpot) => cx + p.u * mirror * halfW * 0.84;\n const spotY = (p: PerfSpot) => topCy + p.v * topRy * 0.8;\n const lead = form.find((p) => p.lead) ?? form[0];\n const leadX = spotX(lead);\n\n // Deck top face — a lit elliptical platform.\n const deckTop = ctx.createLinearGradient(0, topCy - topRy, 0, topCy + topRy);\n deckTop.addColorStop(0, '#3d4a72');\n deckTop.addColorStop(1, '#232b47');\n ctx.fillStyle = deckTop;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.fill();\n // warm bloom on the deck, centred under the LEAD, not the geometric middle.\n const deckGlow = ctx.createRadialGradient(leadX, topCy, 2, leadX, topCy, halfW);\n deckGlow.addColorStop(0, `rgba(255,214,160,${(0.5 * nearGlow).toFixed(3)})`);\n deckGlow.addColorStop(1, 'rgba(255,214,160,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = deckGlow;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n // lit rim around the deck edge.\n ctx.strokeStyle = `rgba(${rigTintStr},0.7)`;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.ellipse(cx, topCy, halfW, topRy, 0, 0, TAU);\n ctx.stroke();\n\n // Backline gear on the far half of the deck (amps/risers + a drum hint for\n // bigger acts) — silhouette furniture so the disc doesn't float empty.\n const perfH = Math.max(24, (yBase - yFarTop) * 1.3);\n const gearN = form.length >= 3 ? 3 : 2;\n for (let i = 0; i < gearN; i++) {\n const gu = (-0.62 + i * 0.52 + (rand() - 0.5) * 0.12) * -mirror;\n const gx = cx + gu * halfW * 0.7;\n const gy = topCy - topRy * (0.45 + rand() * 0.18);\n const gw = halfW * (0.07 + rand() * 0.04);\n const gh = perfH * (0.26 + rand() * 0.12);\n ctx.fillStyle = '#0a0e18';\n ctx.fillRect(gx - gw / 2, gy - gh, gw, gh);\n ctx.fillStyle = `rgba(${rigTintStr},0.3)`;\n ctx.fillRect(gx - gw / 2, gy - gh, gw, 1.5);\n }\n if (form.length >= 3) {\n // drum-kit hint: a low wide disc behind the ensemble's empty quarter.\n const drumX = cx - lead.u * mirror * halfW * 0.4;\n ctx.fillStyle = '#0b0f1a';\n ctx.beginPath();\n ctx.ellipse(drumX, topCy - topRy * 0.34, halfW * 0.08, topRy * 0.1, 0, 0, TAU);\n ctx.fill();\n ctx.strokeStyle = `rgba(${rigTintStr},0.35)`;\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n\n // Performers, far → near so the near ones occlude; height foreshortens with\n // deck depth (far-side figures smaller, higher on the ellipse).\n for (const p of [...form].sort((a, b) => a.v - b.v)) {\n const depthScale = 0.82 + (p.v + 1) * 0.14; // −1..1 → 0.82..1.1\n drawPerformer(ctx, spotX(p), spotY(p), perfH * depthScale * (p.lead ? 1.06 : 0.92), {\n tone: [18, 21, 34],\n alpha: 0.95,\n pose: p.pose,\n rim: hslToRgb(40, 0.72, 0.8),\n rimStrength: p.lead ? 1.4 : 0.9,\n });\n }\n\n // Truss ring above the deck with hanging fixtures + tapered beams onto the deck.\n const trussY = pitchToY(Math.min(60, farTopPitch + 34));\n const trussRy = topRy * 1.1 + 6;\n ctx.strokeStyle = 'rgba(60,68,92,0.85)';\n ctx.lineWidth = 3;\n ctx.beginPath();\n ctx.ellipse(cx, trussY, halfW * 1.15, trussRy, 0, 0, TAU);\n ctx.stroke();\n const fixtures = 4 + Math.floor(rand() * 3);\n for (let i = 0; i < fixtures; i++) {\n const a = (i / fixtures) * TAU;\n const fxX = cx + Math.cos(a) * halfW * 1.15;\n const fxY = trussY + Math.sin(a) * trussRy;\n if (Math.sin(a) > -0.2) {\n // front-facing fixtures cast visible beams down onto the deck.\n const tx = cx + (rand() - 0.5) * halfW * 0.8;\n drawBeam(ctx, fxX, fxY, tx, topCy, 3, halfW * 0.32, rigTintStr, 0.2 * (0.7 + nearGlow * 0.4));\n }\n drawFixture(ctx, fxX, fxY, 3, rigTintStr);\n }\n\n // Centre-hung scoreboard over the deck — the iconic in-the-round silhouette.\n // Without it the upper hemisphere is a black void at close range; with it the\n // eye gets an anchor above the show and the room reads unmistakably \"arena\".\n const scoreY = pitchToY(Math.min(52, farTopPitch + 24));\n const scoreW = Math.max(60, halfW * 0.4);\n const scoreH = Math.max(24, scoreW * 0.34);\n // cables up toward the roof\n ctx.strokeStyle = 'rgba(70,78,102,0.6)';\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n ctx.moveTo(cx - scoreW * 0.3, scoreY - scoreH / 2);\n ctx.lineTo(cx - scoreW * 0.16, scoreY - scoreH * 2.2);\n ctx.moveTo(cx + scoreW * 0.3, scoreY - scoreH / 2);\n ctx.lineTo(cx + scoreW * 0.16, scoreY - scoreH * 2.2);\n ctx.stroke();\n // body\n ctx.fillStyle = '#0d1220';\n ctx.fillRect(cx - scoreW / 2, scoreY - scoreH / 2, scoreW, scoreH);\n // glowing screen face with a soft video wash\n const screen = ctx.createLinearGradient(0, scoreY - scoreH * 0.3, 0, scoreY + scoreH * 0.42);\n screen.addColorStop(0, `rgba(${rigTintStr},0.5)`);\n screen.addColorStop(1, 'rgba(255,214,160,0.32)');\n ctx.fillStyle = screen;\n ctx.fillRect(cx - scoreW * 0.42, scoreY - scoreH * 0.3, scoreW * 0.84, scoreH * 0.72);\n // lit underside rim — reads as the ribbon board\n ctx.fillStyle = 'rgba(255,214,160,0.55)';\n ctx.fillRect(cx - scoreW / 2, scoreY + scoreH / 2 - 2, scoreW, 2);\n // soft glow bleeding off the screens into the air\n const scoreGlow = ctx.createRadialGradient(cx, scoreY, 4, cx, scoreY, scoreW * 1.1);\n scoreGlow.addColorStop(0, `rgba(${rigTintStr},0.2)`);\n scoreGlow.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = scoreGlow;\n ctx.fillRect(cx - scoreW * 1.1, scoreY - scoreW * 0.8, scoreW * 2.2, scoreW * 1.6);\n // haze of light in the air between the rig and the deck — show-light spill.\n const airGlow = ctx.createRadialGradient(cx, (trussY + topCy) / 2, 6, cx, (trussY + topCy) / 2, halfW * 1.5);\n airGlow.addColorStop(0, `rgba(${rigTintStr},${(0.1 * (0.6 + nearGlow * 0.5)).toFixed(3)})`);\n airGlow.addColorStop(1, 'rgba(0,0,0,0)');\n ctx.fillStyle = airGlow;\n ctx.fillRect(cx - halfW * 1.5, trussY - 40, halfW * 3, topCy - trussY + 80);\n ctx.restore();\n // Key light: one stronger, tighter beam pinned on the lead — the eye lands\n // where the show is, which is what was missing from the dead-centre wash.\n const keyX = cx + Math.sign(leadX - cx || 1) * halfW * 0.5;\n drawBeam(ctx, keyX, trussY - trussRy * 0.4, leadX, spotY(lead), 2.5, halfW * 0.16, '255,224,178', 0.42 * (0.7 + nearGlow * 0.4));\n // hot pool where the key lands — grounds the lead in light.\n const pool2 = ctx.createRadialGradient(leadX, spotY(lead), 1, leadX, spotY(lead), halfW * 0.2);\n pool2.addColorStop(0, `rgba(255,228,185,${(0.4 * nearGlow).toFixed(3)})`);\n pool2.addColorStop(1, 'rgba(255,228,185,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = pool2;\n ctx.beginPath();\n ctx.ellipse(leadX, spotY(lead), halfW * 0.2, topRy * 0.24, 0, 0, TAU);\n ctx.fill();\n ctx.restore();\n}\n\n/**\n * A flat sports playing surface (rink/court) in the middle of the bowl: a bright\n * lit ellipse with faint markings, a scoreboard glow overhead instead of a stage\n * screen, and even arena flood lighting. No proscenium, no performers.\n */\nfunction drawSportScene(\n ctx: CanvasRenderingContext2D,\n distM: number,\n eyeM: number,\n scene: Scene,\n _nearGlow: number,\n baseHue: number,\n rigTintStr: string,\n rand: () => number,\n): void {\n const cx = W / 2;\n const surfR = Math.max(10, scene.voidRadiusM);\n // The surface spans a wide arc; near edge close, far edge across the bowl.\n const nearEdge = Math.max(2, distM - surfR);\n const farEdge = distM + surfR;\n const halfYaw = Math.min(78, (Math.atan2(surfR * 1.15, distM) * 180) / Math.PI);\n const nearPitch = (Math.atan2(-eyeM, nearEdge) * 180) / Math.PI;\n const farPitch = (Math.atan2(-eyeM, farEdge) * 180) / Math.PI;\n const yNear = pitchToY(nearPitch);\n const yFar = pitchToY(farPitch);\n const halfW = yawToX(halfYaw) - cx;\n const cy = (yNear + yFar) / 2;\n const ry = Math.max(10, (yNear - yFar) / 2);\n\n // Cool bright playing surface (ice/court), a soft blue-white.\n const surfCol = ctx.createRadialGradient(cx, cy, 4, cx, cy, halfW);\n surfCol.addColorStop(0, '#e8f0fb');\n surfCol.addColorStop(0.7, '#b9c9e2');\n surfCol.addColorStop(1, '#8fa3c4');\n ctx.save();\n ctx.beginPath();\n ctx.ellipse(cx, cy, halfW, ry, 0, 0, TAU);\n ctx.clip();\n ctx.fillStyle = surfCol;\n ctx.fillRect(cx - halfW, cy - ry, halfW * 2, ry * 2);\n // faint markings: centre line + centre circle + two zone lines.\n ctx.strokeStyle = 'rgba(90,120,170,0.5)';\n ctx.lineWidth = 3;\n ctx.beginPath();\n ctx.moveTo(cx, cy - ry);\n ctx.lineTo(cx, cy + ry);\n ctx.moveTo(cx - halfW * 0.5, cy - ry);\n ctx.lineTo(cx - halfW * 0.5, cy + ry);\n ctx.moveTo(cx + halfW * 0.5, cy - ry);\n ctx.lineTo(cx + halfW * 0.5, cy + ry);\n ctx.stroke();\n ctx.strokeStyle = 'rgba(180,90,110,0.45)';\n ctx.beginPath();\n ctx.ellipse(cx, cy, ry * 0.9, ry * 0.5, 0, 0, TAU);\n ctx.stroke();\n ctx.restore();\n // lit rim / board line around the surface.\n ctx.strokeStyle = 'rgba(210,225,245,0.6)';\n ctx.lineWidth = 2.5;\n ctx.beginPath();\n ctx.ellipse(cx, cy, halfW, ry, 0, 0, TAU);\n ctx.stroke();\n\n // A couple of tiny player marks for life (small, not performers).\n ctx.fillStyle = 'rgba(20,26,40,0.8)';\n for (let i = 0; i < 5; i++) {\n const px = cx + (rand() - 0.5) * halfW * 1.4;\n const py = cy + (rand() - 0.5) * ry * 1.1;\n const s = Math.max(2, ry * 0.06);\n ctx.beginPath();\n ctx.ellipse(px, py, s * 0.6, s, 0, 0, TAU);\n ctx.fill();\n }\n\n // Cool even wash of light on the surface.\n const wash = ctx.createRadialGradient(cx, cy, 4, cx, cy, halfW * 1.4);\n wash.addColorStop(0, 'rgba(200,220,255,0.12)');\n wash.addColorStop(1, 'rgba(200,220,255,0)');\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = wash;\n ctx.fillRect(cx - halfW * 1.4, yFar - ry, halfW * 2.8, yNear - yFar + ry * 2);\n ctx.restore();\n\n // Scoreboard cluster overhead — a glowing hexagonal bank centred over the ice.\n const sbY = pitchToY(Math.min(66, farPitch + 60));\n const sbW = Math.max(80, halfW * 0.7);\n const sbH = sbW * 0.5;\n const sbGlow = ctx.createRadialGradient(cx, sbY, 4, cx, sbY, sbW * 1.6);\n sbGlow.addColorStop(0, `rgba(${rigTintStr},0.3)`);\n sbGlow.addColorStop(1, `rgba(${rigTintStr},0)`);\n ctx.save();\n ctx.globalCompositeOperation = 'lighter';\n ctx.fillStyle = sbGlow;\n ctx.fillRect(cx - sbW * 1.6, sbY - sbW * 1.2, sbW * 3.2, sbW * 2.4);\n ctx.restore();\n // scoreboard body — four lit screens around a dark hexagon.\n ctx.fillStyle = '#080b12';\n ctx.beginPath();\n ctx.moveTo(cx - sbW / 2, sbY - sbH / 2);\n ctx.lineTo(cx + sbW / 2, sbY - sbH / 2);\n ctx.lineTo(cx + sbW * 0.6, sbY);\n ctx.lineTo(cx + sbW / 2, sbY + sbH / 2);\n ctx.lineTo(cx - sbW / 2, sbY + sbH / 2);\n ctx.lineTo(cx - sbW * 0.6, sbY);\n ctx.closePath();\n ctx.fill();\n const screenHue = baseHue;\n for (let i = 0; i < 3; i++) {\n const scol = hslToRgb(screenHue + i * 30, 0.5, 0.5);\n ctx.fillStyle = `rgba(${scol[0]},${scol[1]},${scol[2]},0.75)`;\n const swid = sbW * 0.26;\n ctx.fillRect(cx - sbW * 0.42 + i * (swid + sbW * 0.06), sbY - sbH * 0.32, swid, sbH * 0.64);\n }\n // hanging rig lights under the scoreboard.\n ctx.fillStyle = `rgba(${rigTintStr},0.9)`;\n for (let i = 0; i < 8; i++) {\n const lx = cx - sbW * 0.6 + (sbW * 1.2 * i) / 7;\n ctx.beginPath();\n ctx.arc(lx, sbY + sbH * 0.62, 2.4, 0, TAU);\n ctx.fill();\n }\n}\n\n// ---- audience ---------------------------------------------------------------\n\n/**\n * Nearby seats drawn as stylised silhouettes at their true bearing, sorted far→\n * near so front rows occlude the rows behind (painter's order). Three LOD bands:\n * near = full head/neck/shoulders + hair + rim; mid = simplified head+shoulders;\n * far = a dot + shoulder cap. A seat-back rail is drawn last when a seat sits\n * directly ahead (front-row seats face open floor and get none).\n */\nfunction drawAudience(\n ctx: CanvasRenderingContext2D,\n seat: ExpandedSeat,\n neighborSeats: ExpandedSeat[],\n _focalPoint: Point,\n stageBearing: number,\n eyeM: number,\n dx: number,\n dy: number,\n hasRelief: boolean,\n scene: Scene,\n): void {\n const own = seat.sectionId;\n let seatAhead = false;\n interface Fig { hx: number; hy: number; r: number; d: number; hash: number }\n const figs: Fig[] = [];\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 (own && other.sectionId === own && d < 3 && ox * dx + oy * dy > 0) seatAhead = true;\n if (d < 0.3 || d > 32) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const rise = hasRelief ? (other.eyeHeightM ?? SEATED_EYE_HEIGHT_M) - eyeM : 0;\n // Head sits ~0.28m below the eye-line of its own seat, rake-shifted.\n const headPitch = (Math.atan2(rise - 0.28, d) * 180) / Math.PI;\n // Skip the far-and-high leak: same-section neighbours up the rake that the\n // fan curvature bends into the forward cone would otherwise read as a crowd\n // floating above the stage. A believable \"row in front\" sits at or below the\n // eye-line, so anything far AND well above it is culled.\n if (headPitch > 10 && d > 5) continue;\n let hh = 0;\n for (let k = 0; k < other.id.length; k++) hh = (hh * 31 + other.id.charCodeAt(k)) & 0xffff;\n // Physically-based head size: a ~0.16 m head half-width at distance d.\n const jitter = 0.9 + (hh & 15) / 40; // ~0.9..1.28\n const r = Math.min(78, (Math.atan2(0.16, d) * 180 / Math.PI) * PX_PER_DEG * jitter);\n if (r < 1.2) continue;\n figs.push({ hx: yawToX(yaw), hy: pitchToY(headPitch), r, d, hash: hh });\n }\n // Painter's order: far first so nearer figures overlap on top.\n figs.sort((a, b) => b.d - a.d);\n\n // Group figures into screen-space rows (similar head pitch → same physical\n // row) so each row can carry a seat-back strip behind its heads: the strip\n // fills the gaps BETWEEN figures, which is what makes a crowd read dense —\n // background showing between every head reads as a half-empty house.\n interface FigRow { figs: Fig[]; d: number; hy: number; r: number }\n const figRows: FigRow[] = [];\n {\n const byY = [...figs].sort((a, b) => a.hy - b.hy);\n let cur: Fig[] = [];\n const flush = () => {\n if (!cur.length) return;\n const d = cur.reduce((s, f) => s + f.d, 0) / cur.length;\n const hy = cur.reduce((s, f) => s + f.hy, 0) / cur.length;\n const r = cur.reduce((s, f) => s + f.r, 0) / cur.length;\n figRows.push({ figs: cur.sort((a, b) => b.d - a.d), d, hy, r });\n cur = [];\n };\n for (const f of byY) {\n const last = cur[cur.length - 1];\n if (last && Math.abs(f.hy - last.hy) > Math.max(5, ((last.r + f.r) / 2) * 1.7)) flush();\n cur.push(f);\n }\n flush();\n }\n figRows.sort((a, b) => b.d - a.d); // rows far → near: strip, then its figures\n\n const CLOTHES: RGB[] = [[22, 26, 40], [28, 27, 42], [24, 31, 46], [31, 30, 47], [20, 24, 36]];\n for (const row of figRows) {\n // Seat-back strip: contiguous runs of figures (split at real aisles) get a\n // soft dark band at shoulder height. Subtle — texture, not architecture.\n if (row.figs.length >= 3 && row.r >= 1.6 && row.r < 26) {\n const runs: Fig[][] = [];\n const byX = [...row.figs].sort((a, b) => a.hx - b.hx);\n let run: Fig[] = [];\n for (const f of byX) {\n const last = run[run.length - 1];\n if (last && f.hx - last.hx > Math.max(14, f.r * 7)) {\n if (run.length >= 3) runs.push(run);\n run = [];\n }\n run.push(f);\n }\n if (run.length >= 3) runs.push(run);\n const stripAlpha = Math.min(0.42, 0.5 * (1 - row.d / 42));\n if (stripAlpha > 0.05) {\n ctx.fillStyle = `rgba(15, 19, 31, ${stripAlpha.toFixed(3)})`;\n for (const seg of runs) {\n const x0 = seg[0].hx - row.r * 1.6;\n const x1 = seg[seg.length - 1].hx + row.r * 1.6;\n ctx.beginPath();\n ctx.roundRect(x0, row.hy + row.r * 0.8, x1 - x0, row.r * 2.4, row.r * 0.8);\n ctx.fill();\n }\n }\n }\n for (const f of row.figs) {\n // Near figures are near-solid so they occlude cleanly; the extended\n // mid-band tail fades out gently so the crowd dissolves into the stands\n // instead of stopping at a hard radius.\n const alpha = f.d < 12 ? 0.95 : f.d < 17 ? Math.max(0.66, 0.95 - (f.d - 12) / 18) : Math.max(0.3, 0.68 - (f.d - 17) / 34);\n const lift = Math.round((1 - Math.min(1, f.d / 16)) * 10);\n const headTone: RGB = [14 + ((f.hash >> 4) & 6) + lift, 17 + ((f.hash >> 4) & 6) + lift, 25 + ((f.hash >> 4) & 6) + lift];\n const clo0 = CLOTHES[f.hash % CLOTHES.length];\n const clothing: RGB = [clo0[0] + lift, clo0[1] + lift, clo0[2] + lift];\n if (f.r >= 13) {\n const rim = f.d < 9 ? 0.16 * (1 - f.d / 9) + (scene.mode === 'proscenium' ? 0.06 : 0) : 0;\n drawSeated(ctx, f.hx, f.hy, f.r, {\n tone: headTone,\n clothing,\n alpha,\n tilt: (((f.hash >> 2) & 7) - 3.5) * 0.018, // ±~7°\n shoulderK: 1.72 + ((f.hash >> 5) & 7) / 22, // ~1.72..2.04\n hair: f.hash % HAIR_KINDS,\n rim,\n turn: (((f.hash >> 8) & 7) - 3.5) * 0.034, // ±~0.12 head-radii sideways\n lean: (((f.hash >> 10) & 3) - 1.5) * 0.09, // one shoulder rides higher\n });\n } else if (f.r >= 5.5) {\n drawSeatedMid(ctx, f.hx, f.hy, f.r, clothing, headTone, alpha);\n } else {\n ctx.fillStyle = `rgba(${headTone[0]},${headTone[1]},${headTone[2]},${alpha.toFixed(3)})`;\n ctx.beginPath();\n ctx.arc(f.hx, f.hy, f.r, 0, TAU);\n ctx.fill();\n ctx.beginPath();\n ctx.ellipse(f.hx, f.hy + f.r * 1.4, f.r * 1.85, f.r * 0.95, 0, Math.PI, 0, true);\n ctx.fill();\n }\n }\n }\n\n // Foreground seat-back rail (only when a seat sits directly ahead).\n if (seatAhead) {\n const railTop = pitchToY(-34);\n ctx.fillStyle = 'rgba(6, 8, 14, 0.92)';\n ctx.fillRect(0, railTop, W, H - railTop);\n ctx.fillStyle = 'rgba(24, 30, 46, 0.9)';\n const humps = 16;\n for (let i = 0; i < humps; i++) {\n const cx = ((i + 0.5) / humps) * W;\n ctx.beginPath();\n ctx.ellipse(cx, railTop + 6, (W / humps) * 0.42, 22, 0, Math.PI, 0, true);\n ctx.fill();\n }\n }\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. It has no neighbour list, so it always\n// draws a compact upgraded proscenium (arch + inset backdrop + posed performers\n// + tapered beams), seeded off the seat id so venues still differ.\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 const rand = rng(fnv1a(`${seat.id}|${Math.round(focalPoint.x)},${Math.round(focalPoint.y)}`));\n const baseHue = 210 + rand() * 150;\n const rigTint = hslToRgb(220 + (rand() - 0.5) * 60, 0.55, 0.82);\n const rigTintStr = `${rigTint[0]},${rigTint[1]},${rigTint[2]}`;\n\n // hall shell (ceiling → wall → floor), horizon at mid-height.\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#080b12');\n sky.addColorStop(0.44, '#151c32');\n sky.addColorStop(0.5, '#1d2644');\n sky.addColorStop(0.58, '#161c2e');\n sky.addColorStop(1, '#131829');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageHalfYaw = Math.min(HALF_HFOV - 2, (Math.atan2(4, distM) * 180) / Math.PI);\n const stageTopPitch = Math.min(HALF_VFOV - 2, sightline.topPitch);\n const stageBasePitch = Math.max(-HALF_VFOV + 2, sightline.basePitch);\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 const nearGlow = Math.max(0.35, Math.min(1, 1 - (distM - 6) / 60));\n const archTop = pitchToTY(Math.min(HALF_VFOV - 1, stageTopPitch + 8));\n\n // glow bloom behind the opening.\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.15);\n glow.addColorStop(0, 'rgba(255,214,150,0.34)');\n glow.addColorStop(0.28, 'rgba(150,150,230,0.3)');\n glow.addColorStop(0.6, 'rgba(99,102,241,0.12)');\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 // backdrop inset with soft edge falloff.\n const topCol = hslToRgb(baseHue, 0.62, 0.55);\n const midCol = hslToRgb(baseHue + 40, 0.7, 0.5);\n const botCol = hslToRgb(baseHue + 70, 0.78, 0.52);\n ctx.save();\n ctx.beginPath();\n ctx.rect(sx0, sy0, sw, sh);\n ctx.clip();\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, `rgb(${topCol[0]},${topCol[1]},${topCol[2]})`);\n backdrop.addColorStop(0.5, `rgb(${midCol[0]},${midCol[1]},${midCol[2]})`);\n backdrop.addColorStop(1, `rgb(${botCol[0]},${botCol[1]},${botCol[2]})`);\n ctx.globalAlpha = 0.8;\n ctx.fillStyle = backdrop;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.globalAlpha = 1;\n const fall = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, sw * 0.12, TW / 2, (sy0 + sy1) / 2, sw * 0.6);\n fall.addColorStop(0, 'rgba(6,8,14,0)');\n fall.addColorStop(0.7, 'rgba(6,8,14,0.15)');\n fall.addColorStop(1, 'rgba(5,6,11,0.9)');\n ctx.fillStyle = fall;\n ctx.fillRect(sx0, sy0, sw, sh);\n ctx.restore();\n\n // performers.\n const perfCount = 3;\n const floorY = sy1 - sh * 0.08;\n for (let i = 0; i < perfCount; i++) {\n const t = (i + 1) / (perfCount + 1);\n drawPerformer(ctx, sx0 + sw * (0.24 + t * 0.52), floorY, sh * 0.46 * (0.9 + rand() * 0.24), {\n tone: [8, 10, 16],\n alpha: 0.9,\n pose: Math.floor(rand() * 4),\n rim: hslToRgb(baseHue + 20, 0.5, 0.7),\n rimStrength: 0.7,\n });\n }\n\n // masking wings + arch.\n ctx.fillStyle = '#05070d';\n ctx.fillRect(sx0 - sw * 0.5, archTop, sw * 0.5, sy1 - archTop);\n ctx.fillRect(sx1, archTop, sw * 0.5, sy1 - archTop);\n const legBot = sw * 0.05 + 2;\n const legTop = legBot * 1.35;\n ctx.fillStyle = '#03050a';\n ctx.beginPath();\n ctx.moveTo(sx0, sy1);\n ctx.lineTo(sx0 - legBot, sy1);\n ctx.lineTo(sx0 - legTop, archTop);\n ctx.lineTo(sx0 + sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n ctx.beginPath();\n ctx.moveTo(sx1, sy1);\n ctx.lineTo(sx1 + legBot, sy1);\n ctx.lineTo(sx1 + legTop, archTop);\n ctx.lineTo(sx1 - sw * 0.012, archTop);\n ctx.closePath();\n ctx.fill();\n ctx.fillRect(sx0 - legTop, archTop, sw + legTop * 2, (sy1 - archTop) * 0.13);\n ctx.fillStyle = `rgba(${rigTintStr},0.12)`;\n ctx.fillRect(sx0 - 1.2, archTop, 1.2, sy1 - archTop);\n ctx.fillRect(sx1, archTop, 1.2, sy1 - archTop);\n\n // stage floor front edge + footlights.\n ctx.fillStyle = '#0b0f18';\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.05 + 2);\n const foot = ctx.createLinearGradient(0, sy1 - sh * 0.05, 0, sy1 + sh * 0.14);\n foot.addColorStop(0, `rgba(255,206,140,${(0.5 * nearGlow).toFixed(3)})`);\n foot.addColorStop(1, 'rgba(255,206,140,0)');\n ctx.fillStyle = foot;\n ctx.fillRect(sx0 - legBot, sy1 - sh * 0.05, sw + legBot * 2, sh * 0.22);\n\n // tapered beams.\n for (let i = 0; i < 3; i++) {\n const t = (i + 1) / 4;\n const fx = sx0 + sw * t;\n const fy = pitchToTY(Math.min(HALF_VFOV - 1, stageTopPitch + 20));\n drawBeam(ctx, fx, fy, fx + (rand() - 0.5) * sw * 0.14, sy1, 3, sw * 0.09, rigTintStr, 0.17 * nearGlow);\n drawFixture(ctx, fx, fy, 1.8, rigTintStr);\n }\n\n // rig lights across the ceiling.\n ctx.fillStyle = `rgba(${rigTintStr},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, TAU);\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++) {\n const bx = i * (TW / 9) + TW / 18;\n ctx.beginPath();\n ctx.ellipse(bx, TH - 22, (TW / 9) * 0.4, 15, 0, Math.PI, 0, true);\n ctx.fill();\n }\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 — they are ~2.5 KB gzipped of the complete CDN artifact — and\n * code-splits each locale so a page/SDK only downloads the language it actually\n * uses. (The \"150 KB product contract\" this used to cite was never true of a\n * shipped bundle; see docs/hosted-checkout-programme-2026-08-03.md §W4.)\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":["objects","bounds","t","rgb","bounds","scale","stageX","stageY","centroid","seatIndex","active","t","t","rgb"]}