@seatlayer/core 0.27.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +110 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +110 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/types.ts","../src/core/complexGeometry.ts","../src/core/sectionPath.ts","../src/core/labeling.ts","../src/core/units.ts","../src/core/layout.ts","../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":["/**\n * SeatMap chart document — the single source of truth shared by the\n * Designer (authoring) and the Renderer (buyer picker).\n *\n * Coordinates are abstract units (roughly \"pixels at scale 1\"); the renderer\n * fits the chart to its container.\n * Rows are PARAMETRIC (origin + count + spacing + curve + rotation) — never\n * store per-seat coordinates in the document; expansion happens in layout.ts.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface CubicPath {\n start: Point;\n control1: Point;\n control2: Point;\n end: Point;\n}\n\n/** A real closed section boundary. `outline` remains its sampled collision and\n * persistence fallback; this path is the smooth authoring/buyer paint source. */\nexport type SectionPathSegment =\n | { kind: 'line'; end: Point }\n | { kind: 'arc'; center: Point; radius: number; clockwise: boolean; end: Point }\n | { kind: 'bezier'; control1: Point; control2: Point; end: Point };\n\nexport interface SectionOutlinePath {\n version: 1;\n closed: true;\n start: Point;\n segments: SectionPathSegment[];\n}\n\nexport interface Category {\n key: string;\n label: string;\n color: string;\n /** Base price — used when the category has no explicit tiers. */\n price?: number;\n /** Durable evidence for semantic/display facts proposed while converting a\n * private reference into sellable inventory. */\n referenceCategorySource?: ReferenceCategorySource;\n /**\n * Ticket tiers (Adult / Child / Senior…). When present, a buyer picks a tier\n * per seat in this category and the tier's price applies; the first tier is the\n * default. Per-category (not per-seat) pricing — see Batch 3.5. Empty/absent =\n * a single price (the `price` above).\n */\n tiers?: CategoryTier[];\n}\n\nexport interface ReferenceCategorySource {\n assetId: string;\n /** Original sampled section color. `Category.color` is the approved output\n * color and may differ only with separately recorded evidence. */\n sourceColor: string;\n /** Every exact sampled color normalized into the same original 4-bit/channel\n * segmentation class. Older documents may contain only `sourceColor`. */\n sourceColors?: string[];\n /** Logical sections whose generated inventory uses this category. */\n logicalSectionIds?: string[];\n /** Source-color grouping is deterministic; a semantic regrouping needs its\n * own confirmed assignment evidence. */\n assignmentDerivation?: 'source-color-class' | 'confirmed-logical-sections';\n assignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription?: string;\n /** Optional legend/commercial swatch stated by the source. This remains\n * immutable provenance when the approved accessible output color differs. */\n sourcePaletteColor?: string;\n sourcePaletteColorEvidence?: 'user-confirmed' | 'authoritative-source';\n sourcePaletteColorSourceDescription?: string;\n labelEvidence: 'user-confirmed' | 'authoritative-source';\n labelSourceDescription: string;\n priceEvidence: 'user-confirmed' | 'authoritative-source';\n priceSourceDescription: string;\n outputColorEvidence?: 'user-confirmed' | 'authoritative-source';\n outputColorSourceDescription?: string;\n}\n\n/** One ticket tier within a category: a named price (Adult, Child, Senior…). */\nexport interface CategoryTier {\n id: string;\n name: string;\n price: number;\n}\n\n/**\n * Accessibility accommodations a seat can carry. Mirrors the taxonomy real\n * venues (and seats.io) expose so buyers can filter for exactly what they need\n * and organizers can mark seats precisely. `wheelchair` is the legacy default.\n */\nexport type AccessibilityType =\n | 'wheelchair'\n | 'companion'\n | 'semi-ambulatory'\n | 'hearing'\n | 'cart'\n | 'sign-language'\n | 'plus-size'\n | 'lift-armrest';\n\nexport interface AccessibilityMeta {\n key: AccessibilityType;\n /** Full descriptive label (designer checkbox, picker legend). */\n label: string;\n /** Compact label for chips/badges. */\n short: string;\n /** Single-glyph badge shown on seat chips + filter chips. */\n icon: string;\n}\n\n/** Ordered taxonomy — drives the designer seat panel and the picker filters. */\nexport const ACCESSIBILITY_TYPES: AccessibilityMeta[] = [\n { key: 'wheelchair', label: 'Wheelchair space', short: 'Wheelchair', icon: '♿' },\n { key: 'companion', label: 'Companion seat', short: 'Companion', icon: '🧑🤝🧑' },\n { key: 'semi-ambulatory', label: 'Semi-ambulatory (limited mobility)', short: 'Limited mobility', icon: '🦯' },\n { key: 'hearing', label: 'Assistive listening', short: 'Hearing', icon: '🦻' },\n { key: 'cart', label: 'CART live-caption view', short: 'CART captions', icon: 'CC' },\n { key: 'sign-language', label: 'Sign-language view', short: 'Sign language', icon: '🤟' },\n { key: 'plus-size', label: 'Plus-size seat', short: 'Plus-size', icon: '💺' },\n { key: 'lift-armrest', label: 'Lift-up armrest', short: 'Lift armrest', icon: '↕️' },\n];\n\nconst ACCESSIBILITY_LABEL = new Map(ACCESSIBILITY_TYPES.map((a) => [a.key, a]));\n\n/** Metadata for one accessibility key (undefined for unknown keys). */\nexport function accessibilityMeta(key: AccessibilityType): AccessibilityMeta | undefined {\n return ACCESSIBILITY_LABEL.get(key);\n}\n\n/**\n * Outer-ring colour per accommodation. Shared by the buyer picker and the\n * designer canvas so an accessible seat reads with the same hue in both — the\n * seat's first-listed type wins. `wheelchair` blue is the default fallback.\n */\nexport const ACCESSIBILITY_RING_COLOR: Record<AccessibilityType, string> = {\n wheelchair: '#3b82f6',\n companion: '#8b5cf6',\n 'semi-ambulatory': '#0ea5e9',\n hearing: '#14b8a6',\n cart: '#7c3aed',\n 'sign-language': '#f59e0b',\n 'plus-size': '#ec4899',\n 'lift-armrest': '#22c55e',\n};\n\n/** Ring colour for a seat's accessibility set (first-listed type wins). */\nexport function accessibilityRingColor(types: AccessibilityType[] | undefined): string {\n const primary = types?.[0];\n return (primary && ACCESSIBILITY_RING_COLOR[primary]) || '#3b82f6';\n}\n\nexport interface SeatOverride {\n /** 0-based seat index within the row. */\n index: number;\n /** Physical seat absent (pillar, sound desk) — numbering gap preserved. */\n skip?: boolean;\n /** Position nudge in chart units. */\n dx?: number;\n dy?: number;\n /** Replace the computed label entirely. */\n label?: string;\n /** Buyer-facing copy only. Booking/API identity remains row id + slot index\n * internally and the legacy `label` externally for backwards compatibility. */\n displayLabel?: string;\n categoryKey?: string;\n /** @deprecated legacy flag — read as `['wheelchair']`; write `accessibility`. */\n accessible?: boolean;\n /** Accessibility accommodations of this seat (empty/absent = none). */\n accessibility?: AccessibilityType[];\n /**\n * Physical wheelchair provision. Absent keeps legacy seat rendering;\n * `seat-present` is an explicit removable/fixed accessible chair, while\n * `no-seat` is an empty wheelchair bay that remains one sellable inventory\n * unit. This is deliberately distinct from `skip`, which removes inventory.\n */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n /** Commercial selling/view attributes are deliberately not accessibility. */\n commercial?: SeatCommercialAttributes;\n /** Seat-specific view photo; falls back to the row photo. */\n viewFromSeatUrl?: string;\n /** Per-seat label size/color override; falls back to the row/theme default.\n * Size is clamped to LABEL_STYLE_MIN_SIZE..MAX_SIZE; color is passed through\n * the shared auto-contrast rule at paint time (see {@link LabelStyle}). */\n labelStyle?: LabelStyle;\n}\n\nexport interface SeatCommercialAttributes {\n restrictedView?: boolean;\n obstructedView?: boolean;\n premium?: boolean;\n note?: string;\n}\n\n/**\n * Per-object label ink + size overrides layered on top of the chart-wide Theme\n * defaults (rowLabelColor / textColor for rows, the section-name ink for\n * sections). Both fields are optional: an absent field means \"inherit the theme\n * default\". `color` is a preferred hex — renderers still pass it through the\n * shared auto-contrast rule (`stateAwareBookableLabelInk`), so a choice that\n * would be illegible over the seat/section background is switched to black or\n * white at paint time. `size` is a font size in chart units, clamped to\n * LABEL_STYLE_MIN_SIZE..LABEL_STYLE_MAX_SIZE by the shared ops.\n */\nexport interface LabelStyle {\n size?: number;\n color?: string;\n}\n\n/** Clamp bounds for a per-object label `size`, shared by ops, MCP, and UI. */\nexport const LABEL_STYLE_MIN_SIZE = 8;\nexport const LABEL_STYLE_MAX_SIZE = 24;\n\nexport interface LabelPresentation {\n visible?: boolean;\n /** Exact Designer-owned label anchor; public semantic MCP schemas omit it. */\n position?: Point;\n rotation?: number;\n style?: 'plain' | 'pill';\n /** Per-object size/color override for this row's or section's label. */\n labelStyle?: LabelStyle;\n /**\n * End-position preset for a ROW label — which end(s) of the row show it:\n * - `start` (default/undefined) — the row's numbering-start end (legacy behaviour).\n * - `end` — the far end of the row.\n * - `both` — a label at BOTH ends.\n * - `none` — hidden (kept coherent with `visible: false`).\n * A free-drag `position` overrides the preset (the designer shows a 'custom'\n * state). Ignored for sections (they use `position`/`visible` only).\n */\n positionPreset?: 'start' | 'end' | 'both' | 'none';\n}\n\n/** Brand/venue theming — applied by the renderer in both designer and picker. */\nexport interface ChartTheme {\n /** Canvas background color (default dark: #0e1117-ish radial). */\n background?: string;\n /** Preferred text color for the numbers inside seat markers. */\n seatLabelColor?: string;\n /** Preferred color for row identifiers such as A, B, C. Falls back to textColor. */\n rowLabelColor?: string;\n /** Selection ring / accent color (default white ring + brand accent). */\n selectionColor?: string;\n /** Décor (stage/shape) default fill. */\n decorFill?: string;\n /** Free-text color default. */\n textColor?: string;\n /** Font family (CSS stack) for all rendered text — row labels, seat numbers, sections, décor text. */\n fontFamily?: string;\n /** Seat size multiplier on the base radius (0.7–1.6, default 1) — bigger seats fit longer labels. */\n seatScale?: number;\n // ---- White-label branding (applied by the buyer picker chrome) ----\n /** Brand accent color — recolors buttons, links, the hold pill, selection UI. */\n accent?: string;\n /** Ink color for text on the accent (e.g. button labels). Default light. */\n accentInk?: string;\n /** Organizer logo shown in the picker header (data/R2 URL). Falls back to the name. */\n logoUrl?: string;\n /** Brand/venue name shown in the picker header when no event name is set. */\n brandName?: string;\n /** Paid-tier flag: hide the \"Powered by SeatMap\" badge. */\n hideBadge?: boolean;\n}\n\nexport interface RowObject {\n type: 'row';\n id: string;\n /** Present when this row was materialized by the in-canvas reference scan.\n * A re-scan of the same asset replaces rows carrying this marker and NEVER\n * touches hand-authored rows — the same replace-generated-only invariant as\n * applyReferenceInventory. */\n referenceScan?: { assetId: string };\n /** Row label, e.g. \"A\". Seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing row name. `label` remains the legacy inventory prefix. */\n displayLabel?: string;\n /**\n * Buyer-facing type word override (seats.io \"Displayed type\"). Replaces the\n * hardcoded \"Row\" in the picker tooltip/confirm/cart, e.g. \"Table\", \"Bench\",\n * \"Aisle\". ≤24 chars; absent = the default \"Row\". Pure presentation.\n */\n displayType?: string;\n labelPresentation?: LabelPresentation;\n /** Position of the FIRST seat. */\n origin: Point;\n /** Degrees, clockwise. 0 = seats laid out along +x. */\n rotation: number;\n /**\n * Total arc sweep in degrees across the whole row. 0 = straight.\n * Positive bends away from +y (concave toward the focal point when the\n * row faces it). Typical theatre rows: 10–40.\n */\n curve: number;\n seatCount: number;\n /** Distance between adjacent seat centers, in chart units. */\n seatSpacing: number;\n /** Optional exact cubic centreline. Normal code owns these coordinates and\n * distributes seats by arc length; MCP/model inputs never submit them. */\n path?: CubicPath;\n categoryKey: string;\n /** Deterministic provenance for rows fitted from confirmed reference\n * inventory. It enables revision-safe replacement without touching manually\n * authored rows or accepting client coordinates. */\n referenceInventorySource?: ReferenceInventorySource;\n /** Semantic parameters for a row produced by the shared Arc/Fan operation.\n * Designer can reopen these parameters while every segment in the group\n * still carries the same generation signature. Public MCP tools never accept\n * the stored center/angles as arbitrary model-authored coordinates. */\n arcFanGeneration?: {\n kind: 'arc-fan-v1';\n groupId: string;\n center: Point;\n innerRadius: number;\n rowCount: number;\n rowGap: number;\n startAngle: number;\n endAngle: number;\n seatPitch: number;\n fit: 'seat-pitch' | 'fixed-count';\n seatsPerRow?: number;\n facing: 'inward' | 'outward';\n taperDegrees: number;\n skewDegrees: number;\n aisleGaps: { left: number; center: number; right: number };\n rowLabelStart: number;\n seatLabelStart: number;\n rowIndex: number;\n segmentIndex: number;\n };\n /**\n * Membership in one buyer-facing segmented row. Physical component rows and\n * their `${rowId}:${slotIndex}` inventory ids remain authoritative; this\n * metadata only supplies logical ordering/presentation and explicit aisle\n * continuity. The descriptor is repeated on every component so selecting any\n * one can resolve the complete logical row without a chart-level side table.\n */\n segmentedRow?: {\n kind: 'segmented-row-v1';\n groupId: string;\n componentIndex: number;\n componentCount: number;\n /** The first component must use `start`; later boundaries are explicit. */\n boundaryBefore: 'start' | 'continuous' | 'break';\n /** Buyer-facing row name; technical component `label` values never change. */\n displayLabel: string;\n displayType?: string;\n labelPresentation?: LabelPresentation;\n viewFromSeatUrl?: string;\n /** Presentation intent for a continuous node-defined centreline. */\n smoothing?: boolean;\n };\n /**\n * Versioned provenance for rows created by the multiple/intertwined block\n * generator. Manual geometry edits remove this marker rather than allowing a\n * later regeneration to overwrite hand-authored work.\n */\n rowBlockGeneration?: {\n kind: 'row-block-v1';\n groupId: string;\n style: 'multiple' | 'intertwined';\n rowIndex: number;\n rowCount: number;\n seatsPerRow: number;\n origin: Point;\n rotation: number;\n rowGap: number;\n seatSpacing: number;\n curve: number;\n /** Stable canonical generator signature shared by every intact member. */\n signature: string;\n };\n /** First seat number (default 1). Roman/letters read it as a 1-based ordinal\n * (start 1 → I / A). */\n seatLabelStart?: number;\n /** Seat numbering within the row (default decimal, ltr, step 1). */\n seatNumbering?: {\n /** ltr / rtl number from an end; `center` numbers outward from the middle\n * (centre seat lowest — the premium-centre theatre convention). */\n direction: 'ltr' | 'rtl' | 'center';\n /** 2 = odd/even numbering (1,3,5… — start at 2 for evens). */\n step?: 1 | 2;\n /**\n * Label scheme for the seat NUMBER part (the row prefix is separate).\n * Default `decimal`. Composition with `direction`/`step`/`seatLabelStart`:\n * - `decimal` 1,2,3 — honours direction + step + start.\n * - `odd` 1,3,5 — odd numbers from the first odd ≥ start.\n * - `even` 2,4,6 — even numbers from the first even ≥ start.\n * - `updown` 1,3,5,…,6,4,2 — odd-up-even-back; REPLACES direction (uses\n * physical left→right order); start shifts.\n * - `updown-descending` …5,3,1,2,4,6 — odd-back-even-up; the distinct\n * reverse up/down sequence. Also replaces\n * direction and uses physical order.\n * - `roman` I,II,III — honours direction + step + start (uppercase).\n * - `letters-upper` A,B,C…Z,AA — honours direction + step + start.\n * - `letters-lower` a,b,c…z,aa — honours direction + step + start.\n * Like `step`/`direction` today, the scheme changes the seat's inventory\n * label (its booking identity), by design.\n */\n scheme?: 'decimal' | 'odd' | 'even' | 'updown' | 'updown-descending' | 'roman' | 'letters-upper' | 'letters-lower';\n /** Optional prefix prepended to every seat number, e.g. 'R' → 'R1', 'R2'. */\n prefix?: string;\n /**\n * End-at preset (\"useEndAt\"): the row's numbering ENDS at this value instead\n * of starting at `seatLabelStart`. The start is derived so the last-numbered\n * seat (highest position rank) lands on `endAt`, respecting the scheme's step\n * (odd/even = 2). When set it WINS over the stored `seatLabelStart` (which is\n * left untouched). For letters it is a 1-based number index (26 → last seat\n * 'Z'); `updown` owns its own sequence and ignores `endAt`.\n */\n endAt?: number;\n };\n /**\n * Per-seat exceptions, keyed by seat index (0-based position in the row).\n * `skip` removes the physical seat but keeps the numbering gap (theatre\n * convention: a pillar eats A-3; A-4 stays A-4).\n */\n overrides?: SeatOverride[];\n /**\n * Organizer-supplied equirectangular 360 (or wide photo) shown as the\n * view-from-seat for every seat in this row. When absent, the picker\n * generates a synthetic panorama from chart geometry.\n */\n viewFromSeatUrl?: string;\n /** Default commercial attributes inherited by seats without an override. */\n commercial?: SeatCommercialAttributes;\n}\n\nexport interface GAAreaObject {\n type: 'gaArea';\n id: string;\n /** Stable technical/inventory label. */\n label: string;\n /** Buyer-facing area name; technical `label` and GA unit ids stay stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default type word. Pure presentation. */\n displayType?: string;\n /** Closed polygon, in chart units. */\n points: Point[];\n /** Explicit aisles/pillars/cutouts excluded from the sellable GA surface. */\n holes?: Point[][];\n capacity: number;\n categoryKey: string;\n /** Corner-rounding radius in chart units (default 0 = sharp corners). Pure\n * presentation — softens the polygon's corners in every renderer without\n * touching capacity, unit identities, or the stored points. Clamped per\n * corner to half the shorter adjacent edge at draw time. */\n cornerRadius?: number;\n /**\n * Durable inventory provenance for a surface produced by Join Areas.\n *\n * A GA unit is identified by the id and zero-based range of the area that\n * originally authored it, not by the current polygon which happens to own\n * it. Keeping those source ranges means a geometric join never renumbers an\n * already published/booked unit. Ordinary (never-joined) areas omit this\n * field and implicitly own `[0, capacity)` under their own id.\n *\n * The ranges must be non-overlapping, contain positive whole counts, and sum\n * exactly to `capacity`; validation rejects malformed metadata. Capacity\n * growth appends a new range under the surviving area id, while shrinking a\n * joined area is deliberately refused because it would silently destroy\n * stable inventory identities.\n */\n inventorySegments?: GAInventorySegment[];\n referenceInventorySource?: ReferenceInventorySource;\n}\n\nexport interface GAInventorySegment {\n sourceAreaId: string;\n startIndex: number;\n count: number;\n}\n\n/**\n * Durable evidence link for sellable objects generated from a private reference.\n * The client supplies facts and stable logical-section ids, never coordinates.\n */\nexport interface ReferenceAccessibilitySource {\n placementDerivation: 'server-synthesized-row-edges';\n groupLogicalSectionIds: string[];\n assignmentEvidence: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription: string;\n counts: Array<{\n type: AccessibilityType;\n count: number;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n }>;\n}\n\nexport interface ReferenceInventorySource {\n assetId: string;\n logicalSectionId: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n /** Distinguishes directly supplied inventory from a user-approved server\n * distribution based only on an aggregate capacity. */\n derivation?: 'explicit-inventory' | 'server-synthesized-from-aggregate';\n /** Evidence for the aggregate figure; synthesized rows remain\n * `user-confirmed` and are never mislabeled as source-extracted. */\n aggregateEvidence?: 'user-confirmed' | 'authoritative-source';\n /** Separate evidence for assigning standing inventory to this logical\n * section. Aggregate evidence alone cannot prove section placement. */\n sectionAssignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n sectionAssignmentSourceDescription?: string;\n /** Aggregate row synthesis may propose numbering, but persistence requires\n * the applying user/agent to confirm that policy explicitly. */\n numberingEvidence?: 'user-confirmed';\n numberingSourceDescription?: string;\n /** Evidence and deterministic placement contract for synthesized accessible\n * units in this logical section. */\n accessibility?: ReferenceAccessibilitySource;\n}\n\n/** Durable evidence that a visible source-backed section shell intentionally\n * carries no generated sellable inventory in this reference configuration. */\nexport interface ReferenceInventoryExclusionSource {\n assetId: string;\n logicalSectionId: string;\n reason: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n}\n\n/** Open-path stroke semantics. Optional ShapeObject fields retain the legacy\n * round/round/no-ending rendering when absent. */\nexport type ShapeLineCap = 'butt' | 'round' | 'square';\nexport type ShapeLineJoin = 'miter' | 'round' | 'bevel';\nexport type ShapeLineEnding = 'none' | 'arrow';\n\n/** Non-bookable décor: stage, walls, exits. */\nexport interface ShapeObject {\n type: 'shape';\n id: string;\n /**\n * Closed area shapes (`rect`/`ellipse`/`polygon`) take a `fill`; open path\n * primitives (`line` = two points, `polyline` = n points) are stroke-only and\n * never filled. All kinds honour the optional `stroke`.\n */\n kind: 'rect' | 'ellipse' | 'polygon' | 'line' | 'polyline';\n label?: string;\n /** For rect/ellipse: bounding box. For a stage polygon: the base (pre-shape) box, so its kind can be regenerated. */\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n /** For polygon/line/polyline. */\n points?: Point[];\n fill?: string;\n /** Optional outline. `width` is in chart units; both fields are required together. */\n stroke?: { color: string; width: number };\n /** Open line/polyline only. Absent fields preserve round/round/no-ending legacy rendering. */\n lineCap?: ShapeLineCap;\n /** Controls corners between open-path segments. */\n lineJoin?: ShapeLineJoin;\n /** Independent open-path start/end decorations. Closed outlines never use these fields. */\n startEnding?: ShapeLineEnding;\n endEnding?: ShapeLineEnding;\n /** Rect only — corner rounding radius in chart units, clamped to half the short side at edit time. */\n cornerRadius?: number;\n /** Whole-shape opacity 0.1–1 (default 1). */\n opacity?: number;\n /** Degrees clockwise about the shape's center (default 0). Applied at render time. */\n rotation?: number;\n /**\n * Semantic tag driving special rendering. `'stage'` gets the gradient +\n * prominent uppercase label treatment; a décor landmark role (bar, exit…)\n * gets a quieter label. Loose string to avoid a circular import with\n * stage.ts / decor.ts (see StageKind / DecorRole there).\n */\n role?: string;\n /** For a stage: which `StageKind` its polygon was generated from. */\n stageKind?: string;\n}\n\nexport type RectTableSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** Exact rectangular-table chair distribution. The four keys are deliberately\n * required: zero means that edge has no chair, while the sum is the authored\n * `seatCount`. Numeric chair identity remains `${table.id}:${index}` in the\n * canonical top, bottom, left, right expansion order. */\nexport interface RectTableSeatCounts {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\n/** Seats arranged around a table. Grouped selling is activated only by an\n * event's explicit inventory-model-2 snapshot; model-1 events continue to\n * treat every authored chair as an independent unit. */\nexport interface TableObject {\n type: 'table';\n id: string;\n /** e.g. \"T1\" — seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing table name; technical chair/group labels stay stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default \"Row\"/\"Table\" word. Pure presentation. */\n displayType?: string;\n center: Point;\n shape: 'round' | 'rect';\n /** Seats around the perimeter (round) or along the enabled edges (rect). */\n seatCount: number;\n /** Rect tables: which edges get seats (default ['top','bottom']). */\n sides?: RectTableSide[];\n /**\n * Rect tables only: exact chairs on every edge. Absent preserves the legacy\n * `seatCount` + `sides` round-robin distribution byte-for-byte. When present,\n * all four values are whole numbers >= 0 and their sum equals `seatCount`.\n */\n seatCountsBySide?: RectTableSeatCounts;\n /** Individual-chair semantic overrides. Grouped whole/variable tables cannot\n * author these because their only sellable identity is the table itself. */\n overrides?: SeatOverride[];\n rotation: number;\n /** Round tables. */\n radius?: number;\n /**\n * Round tables: the arc (in degrees) the seats occupy, default 360 (full\n * ring). Below 360 leaves an open side — e.g. a service gap for waiters, a\n * head table facing the room, or clearance against a wall. The opening is\n * centred on the `rotation` direction; seats spread across the rest.\n */\n seatArc?: number;\n /** Rect tables. */\n width?: number;\n height?: number;\n categoryKey: string;\n /** One buyer owns the complete table at exactly `seatCount` guests. */\n bookAsWhole?: boolean;\n /** One buyer owns the complete table and chooses a bounded guest quantity. */\n variableOccupancy?: boolean;\n /** Required inclusive guest bounds when `variableOccupancy` is true. */\n minOccupancy?: number;\n maxOccupancy?: number;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/** A booth: one bookable unit rendered as a block (trade shows, VIP boxes). */\nexport interface BoothObject {\n type: 'booth';\n id: string;\n /** Stable technical/inventory label. */\n label: string;\n /** Buyer-facing booth name; technical `label` stays stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default type word. Pure presentation. */\n displayType?: string;\n center: Point;\n width: number;\n height: number;\n rotation: number;\n /**\n * Optional custom outline (closed polygon, absolute chart coordinates) for\n * non-rectangular booths — L-shaped, corner, or island units on expo floors.\n * Absent = the default axis-aligned rectangle described by `width`/`height`/\n * `rotation`. A booth stays exactly ONE atomic sellable unit whatever its\n * outline; `points` is purely geometric. `width`/`height` are retained as the\n * last rectangular size so \"Back to rectangle\" can restore it. When `points`\n * is present, renderers draw the polygon and ignore `rotation`.\n */\n points?: Point[];\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * A named region of the venue (Balcony Left, Floor B…). Sections are outlines\n * only — objects belong to a section spatially (center inside the outline),\n * keeping the document flat (no nesting; simpler for tools and for AI edits).\n * Renderer: far zoom shows section shapes/labels instead of seats; clicking\n * a section zooms into it.\n */\nexport interface SectionObject {\n type: 'section';\n id: string;\n label: string;\n /** Buyer-facing section name; logical/id fields remain stable. */\n displayLabel?: string;\n /**\n * Buyer-facing entrance/door hint shown in the picker section card\n * (\"Entrance X\"). ≤40 chars; absent = no entrance line. Pure presentation.\n */\n entrance?: string;\n /**\n * Organizer-supplied view image inherited by buyer inventory whose owning\n * row/table/booth sits in this logical section. Seat and row photos take\n * precedence; multipart components are kept in sync by the shared section\n * metadata operation.\n */\n viewFromSeatUrl?: string;\n labelPresentation?: LabelPresentation;\n /**\n * Stable management/inventory identity shared by disconnected visual\n * components of one logical section. When absent, `id` is the logical id.\n * Each component keeps its own `id` and reference provenance so rendering,\n * editing, measured diffs, and source restoration remain exact.\n */\n logicalSectionId?: string;\n /** Shared semantic Arc/Fan group wrapped by this section. The section id is\n * preserved when the fan parameters are reopened and regenerated. */\n arcFanGroupId?: string;\n /** Closed polygon, chart units. */\n outline: Point[];\n /** Optional true line/arc/cubic boundary. `outline` is a deterministic sample\n * of this path and remains authoritative for membership, validation, and\n * clients that predate curved section rendering. */\n outlinePath?: SectionOutlinePath;\n /** Explicit aisle/cutout polygons excluded from rendering, hit-testing, and membership. */\n holes?: Point[][];\n /** Durable opaque link to the private reference component. Unlike generator\n * provenance, this survives manual geometry edits so a measured diff can\n * report drift and server-owned code can restore the source contour. */\n referenceSource?: {\n assetId: string;\n regionId: string;\n };\n /** Evidence-backed reason this source section remains a visible shell without\n * synthesized sellable inventory (press, closed technical zone, etc.). */\n referenceInventoryExclusion?: ReferenceInventoryExclusionSource;\n /** Deterministic generator provenance for editable reference/parametric shells. */\n geometry?: {\n kind: 'rectangle' | 'tapered' | 'bezier' | 'contour';\n sourceRegionId?: string;\n contourMethod?: 'pixel-edge-loops-rdp' | 'shared-edge-vector-fit-v1';\n simplificationTolerancePx?: number;\n vectorFitErrorPx?: number;\n sharedEdgeCount?: number;\n };\n /** Optional tint override (defaults to a neutral fill / dominant category mix). */\n color?: string;\n /** Zone this section belongs to (id into `ChartDoc.zones`). Far-zoom nav + pricing group. */\n zone?: string;\n /**\n * Tier height. 0 = floor (default). Higher values lift the section in the\n * picker's isometric (\"3D\") view, drawn on extruded side faces. Same field a\n * future multi-floor mode reuses — authored in 2D, never drawn by the user.\n *\n * This is the coarse, back-compat source for {@link height}/{@link rake}: when\n * those are absent, {@link sectionGeometry} derives real geometry from this\n * tier so legacy charts render pixel-identical.\n */\n elevation?: number;\n /**\n * 3D foundations (Phase A, additive — no migration; charts are JSON blobs).\n * Metres the section's **front edge** sits above floor 0 (a balcony/tier floor\n * height). Absent ⇒ derived from the coarse {@link elevation} tier via\n * {@link sectionGeometry}. Deliberately two scalars, not a foundation polygon:\n * front-height + {@link rake} fully determine a rectangular tier's back-height.\n *\n * NOTE: no consumer reads this raw field directly — all callers go through\n * {@link sectionGeometry}. Phase B consumers (iso view lift in\n * `SeatmapRenderer`, per-seat eye-height in the `generatePanorama` 360°\n * generator) are intentionally NOT wired in Phase A. Range 0–120 m.\n */\n height?: number;\n /**\n * Degrees of seating incline within the section (0 = flat; typical stalls\n * 5–15°, steep tiers 25–35°). Absent ⇒ 0. Consumed alongside {@link height}\n * by the future Phase B iso-lift shear and 360° sightline math — never in\n * Phase A. Range 0–45°.\n */\n rake?: number;\n /** Uniform scale about the outline centroid (1 = as drawn). Scales members too. */\n scale?: number;\n /** 0–100: reviewed strength last used to bend member rows toward a common fitted arc. */\n smoothing?: number;\n /** Degrees clockwise about the outline centroid (default 0). Rotates members too. */\n rotation?: number;\n}\n\n/**\n * A group of sections (Lower Bowl, Upper Bowl, Floor…). One concept, three jobs:\n * the farthest-zoom navigation unit, a pricing group, and (Batch 3) a timed-\n * release unit. Kept as a flat list on the doc; sections point back by `zone` id.\n */\nexport interface ZoneDef {\n id: string;\n label: string;\n color?: string;\n /**\n * Authored point this zone faces. Optional only for legacy documents: runtime\n * consumers fall back to the active floor/chart focal, while publication of\n * a zone-mode draft requires every used zone to carry an explicit point.\n */\n focalPoint?: Point;\n}\n\n/**\n * Selection layer — a hit-test/dim filter in the designer, NOT z-order management.\n * Fixed set of four; derived from object type via `layerOf()` (no per-object field yet).\n */\nexport type SelectionLayer = 'interactive' | 'background' | 'foreground' | 'surroundings';\n\n/** Shape roles emitted by the curated venue-landmark palette. Keep this list in\n * lockstep with `DECOR_PRESETS`; the selection-layer unit test fails if either\n * vocabulary changes without an explicit routing decision. `reference-focal`\n * is source-backed venue context rather than an authoring-palette preset. */\nexport const SURROUNDINGS_SHAPE_ROLES = [\n 'reference-focal',\n 'bar',\n 'entrance',\n 'exit',\n 'restroom',\n 'screen',\n 'sound',\n 'concession',\n 'coat',\n 'wall',\n] as const;\n\nconst SURROUNDINGS_SHAPE_ROLE_SET: ReadonlySet<string> = new Set(SURROUNDINGS_SHAPE_ROLES);\n\n/** Derive an object's selection layer from its type. */\nexport function layerOf(obj: ChartObject): SelectionLayer {\n switch (obj.type) {\n case 'row':\n case 'table':\n case 'gaArea':\n case 'booth':\n case 'section':\n return 'interactive';\n // Raster décor follows its explicit authored z-layer. Absence retains the\n // legacy Background default; bitmap content is never guessed semantically.\n case 'decorImage':\n return obj.layer === 'foreground' ? 'foreground' : 'background';\n // Source-backed focal geometry and curated venue landmarks help an author\n // orient around the sellable plan. A stage and an ordinary authored shape\n // remain Background even when they carry an arbitrary/custom role.\n case 'shape':\n return obj.role && SURROUNDINGS_SHAPE_ROLE_SET.has(obj.role)\n ? 'surroundings'\n : 'background';\n // Free text — including semantic icon text — is background furniture.\n case 'text':\n return 'background';\n default:\n return 'interactive';\n }\n}\n\n/** Free-standing text on the chart (aisle names, door labels…). */\nexport interface TextObject {\n type: 'text';\n id: string;\n /** Persisted provenance for objects created from the venue-icon palette. */\n semanticKind?: 'icon';\n /**\n * Registry key for a vector wayfinding icon (see src/core/icons.ts). Present\n * on modern icon placements; the object then renders as a single-color vector\n * Path instead of `text`. Absent on legacy emoji icons, which keep rendering\n * `text` through the shared glyph path — old charts are never rewritten.\n */\n iconKey?: string;\n text: string;\n position: Point;\n fontSize: number;\n /** Optional CSS family stack for this annotation; absent inherits ChartTheme.fontFamily. */\n fontFamily?: string;\n rotation: number;\n color?: string;\n /** Render weight (default false). Maps to Konva fontStyle bold. */\n bold?: boolean;\n /** Render slant (default false). Maps to Konva fontStyle italic. */\n italic?: boolean;\n}\n\n/**\n * A raster/vector decor graphic drawn IN the chart, beneath the seats and\n * sections (ice rink, basketball court, stage art, pitch markings). Purely\n * visual venue context — never bookable, never hit-tested, so it never steals a\n * seat click. `href` is a self-contained data URL (image or SVG) produced by the\n * same client-side downscale used for row photos, so it travels with the doc and\n * caches as a single bitmap blit (zero per-frame cost). Placed by top-left\n * (x,y) + size, rotated about its centre — the same handles a shape rect uses.\n */\nexport interface DecorImageObject {\n type: 'decorImage';\n id: string;\n /** Image or SVG data URL. */\n href: string;\n x: number;\n y: number;\n width: number;\n height: number;\n /** Degrees clockwise about the image centre (default 0). */\n rotation?: number;\n /** 0–1 (default 1). Multiplied by any chart-theme dimming at render time. */\n opacity?: number;\n /**\n * Z-layer relative to the interactive seat layer. `background` (default)\n * draws beneath the seats/sections; `foreground` draws above them (a roof\n * canopy, an overlay graphic). Absent = background — no migration needed.\n */\n layer?: 'background' | 'foreground';\n /** Optional caption for the designer inspector / accessibility (not drawn). */\n label?: string;\n}\n\nexport type ChartObject =\n | RowObject\n | GAAreaObject\n | ShapeObject\n | TableObject\n | BoothObject\n | TextObject\n | SectionObject\n | DecorImageObject;\n\n/**\n * One floor / level of a multi-floor venue (Batch 5). Each floor owns its own\n * geometry, stage focal point, and trace image; categories/zones/tiers stay\n * chart-global (one event, one inventory). A single-floor chart has NO `floors`\n * — its `objects[]` is the whole venue — so all existing charts are untouched.\n */\nexport interface Floor {\n id: string;\n name: string;\n /**\n * Absolute physical deck height in metres above the venue/stage datum.\n * Optional for backwards compatibility; an absent value resolves to ground\n * level (0 m). Section tiers and rakes are separate, section-local metadata.\n * Range 0–120 m.\n */\n baseHeightM?: number;\n objects: ChartObject[];\n focalPoint: Point;\n /**\n * Private organizer trace/calibration layer. This is authoring evidence and\n * must never be served to, or rendered by, a buyer surface.\n */\n referenceImage?: ChartReferenceImage;\n /**\n * Buyer-visible aesthetic background. Canonical documents store URL-only\n * images here. Historical `assetId` values are interpreted as a trace layer\n * by the background compatibility helpers.\n */\n backgroundImage?: ChartDoc['backgroundImage'];\n}\n\nexport interface ReferenceCalibration {\n type: 'two-point';\n /** Points in immutable source-image pixels, selected by a human or trusted detector. */\n sourceA: Point;\n sourceB: Point;\n /** Verified real-world distance between the two source points. */\n distance: number;\n unit: 'm' | 'ft' | 'chart-unit';\n /** Derived and stored for deterministic geometry compilers. */\n pixelsPerUnit: number;\n}\n\n/**\n * A single human-placed seat probe: the author clicks one seat on the reference\n * image and the server reads the surrounding seat lattice from it.\n *\n * COORDINATE-POLICY CARVE-OUT (owner decision 2026-07-21). The reference\n * blueprint pipeline runs `coordinatePolicy: 'opaque-region-ids-only'` — the\n * server is the sole source of chart coordinates and MCP clients select opaque\n * `reg_*` ids, never points. This type is a deliberate, narrow exception on the\n * same grounds as `ReferenceCalibration`: the point is placed by a human in the\n * designer canvas, not proposed by a model.\n *\n * Therefore this is DESIGNER-ONLY and is intentionally NOT exposed over MCP.\n * That is an accepted, documented exception to the MCP-parity rule — the\n * server-is-sole-source guarantee for model-driven edits is worth more than\n * parity here. Do not \"fix\" it by adding a seed point to an MCP tool schema.\n */\nexport interface ReferenceSeatSeed {\n /** Seed centre in immutable source-image pixels (never chart coordinates). */\n source: Point;\n /** Half-width of the author's sizing ring, in source pixels — the \"this is how\n * big one seat is\" hint that replaces seats.io's zoom-until-it-matches step. */\n radius: number;\n /** Whether `radius` was fitted from image pixels or set by hand. Detection\n * weights an author-set radius more heavily than one we guessed. */\n origin: 'auto-fit' | 'manual';\n}\n\n/** One detected row in a scan proposal — a straight seat run in CHART\n * coordinates (the server maps source pixels through referencePixelToChart;\n * clients never see source-pixel geometry back). */\nexport interface ReferenceScanRowProposal {\n start: Point;\n end: Point;\n seatCount: number;\n}\n\n/** Detected rows attributed to one compiled section (or unattributed when the\n * lattice extends outside every compiled polygon). */\nexport interface ReferenceScanSectionProposal {\n /** Id of the compiled SectionObject the rows landed in; null = unattributed. */\n sectionId: string | null;\n name: string;\n rows: ReferenceScanRowProposal[];\n seatCount: number;\n /** 0..1 — how well this section's lattice agreed with the probe's pitch. */\n confidence: number;\n /** Index of the seed (multi-probe) whose pitch produced these rows. */\n seedIndex: number;\n}\n\n/** Server response for an in-canvas reference scan. A PROPOSAL — nothing is\n * committed until the author applies it in the designer (chartOps + undo). */\nexport interface ReferenceScanProposal {\n assetId: string;\n /** Measured seat diameter / centre-to-centre pitch, in chart units. */\n seatDiameter: number;\n seatPitch: number;\n totalSeats: number;\n totalRows: number;\n sections: ReferenceScanSectionProposal[];\n}\n\n/** Coordinate-free physical scale derived by server code from a confirmed\n * semantic feature. Unlike manual two-point calibration, no source points pass\n * through an MCP client or language model. */\nexport interface ReferenceDerivedScale {\n method: 'confirmed-focal-axis-v1';\n feature: 'focal-long-axis' | 'focal-short-axis';\n distance: number;\n unit: 'm' | 'ft';\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n chartUnitsPerUnit: number;\n}\n\nexport interface ChartReferenceImage {\n /** Stable private reference asset. New cloud-authored charts use this. */\n assetId?: string;\n /** Legacy/self-contained source. Optional when assetId is present. */\n url?: string;\n center: Point;\n /** Rendered width in chart units (height follows the cropped image aspect). */\n width: number;\n opacity: number;\n rotation?: number;\n visible?: boolean;\n layer?: 'below' | 'above';\n locked?: boolean;\n /** Normalized source crop; defaults to the full image. */\n crop?: { x: number; y: number; width: number; height: number };\n calibration?: ReferenceCalibration;\n /** Server-derived semantic calibration without source-image coordinates. */\n derivedScale?: ReferenceDerivedScale;\n}\n\nexport interface ChartDoc {\n version: 1;\n name: string;\n venueType: 'SIMPLE' | 'MIXED';\n /** The stage / point every seat looks at. Anchors seat-view + sightlines.\n * Multi-floor: mirrors floor 0; each floor also carries its own focalPoint. */\n focalPoint: Point;\n categories: Category[];\n /** Section groupings for far-zoom navigation + pricing (optional; sections reference by id). */\n zones?: ZoneDef[];\n /** Multi-floor venues (Batch 5): present ⇒ floors[] is the source of truth;\n * absent ⇒ single-floor and `objects` below is the whole chart. `objects`\n * is kept mirroring floor 0 so single-floor readers never branch. */\n floors?: Floor[];\n objects: ChartObject[];\n /**\n * Private floor-plan source used for tracing, calibration, scanning and\n * reference-backed generation. Buyer projections always remove this field.\n */\n referenceImage?: ChartReferenceImage;\n /**\n * Buyer-visible aesthetic background. Canonical values are URL-only.\n * Compatibility: a historical value containing `assetId` is trace-only and\n * is never rendered or exposed to buyers.\n */\n backgroundImage?: ChartReferenceImage;\n /** Brand/venue theming (colors); categories carry their own colors separately. */\n theme?: ChartTheme;\n /** Parametric-template provenance: present ⇒ the chart came from a capacity-\n * adjustable template family, and the designer offers a capacity control that\n * regenerates it at a new target seat count (Batch 4 \"curated singles + resize\"). */\n template?: { family: string; targetSeats: number };\n}\n\n// ---------------------------------------------------------------------------\n// Expanded (render-time) model — produced by layout.ts, consumed by the engine\n// ---------------------------------------------------------------------------\n\nexport interface ExpandedSeat {\n /** Stable id: `${rowId}:${index}` */\n id: string;\n /** Public label: `${rowLabel}-${seatNumber}` */\n label: string;\n /** Buyer-facing copy; absent on legacy charts, where `label` is displayed. */\n displayLabel?: string;\n x: number;\n y: number;\n rowId: string;\n /** Owning logical section and navigation zone, resolved once at expand time. */\n sectionId?: string;\n zoneId?: string;\n /** Zone focal when authored, otherwise the active floor/chart legacy fallback. */\n focalPoint?: Point;\n /** Buyer-facing segmented-row identity. `rowId` stays the physical owner id. */\n logicalRowId?: string;\n /**\n * Seat order inside the logical row. A deliberate missing integer is inserted\n * at every aisle boundary, so numerical adjacency cannot bridge a gap.\n */\n logicalSeatIndex?: number;\n categoryKey: string;\n /** 'booth' units render as blocks (dimensions looked up via rowId = booth id). */\n kind?: 'seat' | 'booth';\n /** True when the seat has any accessibility accommodation — renderer rings/dims these. */\n accessible?: boolean;\n /** Specific accessibility accommodations (absent = none) — picker badges/filters these. */\n accessibility?: AccessibilityType[];\n /** Physical wheelchair provision resolved from the seat override. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n commercial?: SeatCommercialAttributes;\n /** Organizer-supplied view-from-seat image (inherited from the row). */\n viewUrl?: string;\n /** Per-seat label size/color override; absent = inherit the row/theme default. */\n labelStyle?: LabelStyle;\n /**\n * Real-world eye height in metres above the focal/stage datum, resolved at\n * expand time from the owning section's `{height, rake}` + drawn depth (Phase B2).\n * Feeds the auto-360° generator's stage-pitch math. Absent ⇒ flat seated eye\n * height (legacy / seats in no section) — so old charts stay pixel-identical.\n */\n eyeHeightM?: number;\n}\n\nexport type SeatStatus = 'free' | 'held' | 'booked' | 'not_for_sale';\n\n/** Buyer canvas projection. Perspective is a view-only projected-2.5D lane. */\nexport type RendererViewMode = 'flat' | 'isometric' | 'perspective';\n\n// ---------------------------------------------------------------------------\n// Renderer engine public API — implemented in src/engine/SeatmapRenderer.ts\n// ---------------------------------------------------------------------------\n\nexport interface RendererCallbacks {\n onSelect?: (seat: ExpandedSeat) => void;\n onDeselect?: (seat: ExpandedSeat) => void;\n /** Buyer tried to add a seat after the active selection cap was reached. */\n onSelectionLimit?: (maxSelection: number) => void;\n /** seat is null when the pointer leaves any seat. */\n onHover?: (seat: ExpandedSeat | null) => void;\n /** Keyboard focus moved to a seat (arrow-key navigation) — for screen-reader announcements. */\n onFocusSeat?: (seat: ExpandedSeat | null) => void;\n /** Called ~1×/sec with the measured frames-per-second. */\n onFps?: (fps: number) => void;\n /** Fired when a GA area is clicked (quantity picking is UI-side). */\n onGAClick?: (areaId: string) => void;\n /**\n * Fired when a tap lands on a section outline while seats are NOT the active\n * rung (i.e. zoomed out, section/zone LOD). The host glides in + shows a\n * section-summary card instead of trying to select a 4px seat (Slice 5).\n */\n onSectionTap?: (sectionId: string) => void;\n /**\n * Fired when a seat/deck is tapped in the 3D all-floors stacked overview — the\n * host drops back to the flat 2D map on that floor (\"tap a deck to enter\").\n */\n onDeckTap?: (floorId: string) => void;\n /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */\n onViewChange?: () => void;\n /**\n * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on\n * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,\n * with the FULL current selection (selectable seats only). The host toolbar\n * reads this to drive bulk block/unblock. Never fires when manageMode is off.\n */\n onMarquee?: (seats: ExpandedSeat[]) => void;\n}\n\n/** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */\nexport type LodRung = 'zones' | 'sections' | 'seats';\n\nexport interface RendererOptions extends RendererCallbacks {\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** Only these statuses are clickable (default ['free']). */\n selectableStatuses?: SeatStatus[];\n /**\n * Opt-in host behaviour flag — the renderer's own click/selection logic is\n * unchanged (it still selects + fires `onSelect` immediately, so the seat\n * highlights right away). When true, the host (e.g. PublicEventPage) treats\n * that `onSelect` as a pending candidate and shows a confirm card instead of\n * pushing straight into the cart; `deselect([seat.id])` on Cancel un-highlights.\n */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (\"FROM …\"); defaults to money.DEFAULT_CURRENCY.\n * Locale for grouping/symbol placement comes from the active i18n locale. */\n currency?: string;\n /**\n * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode\n * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /\n * pinch / tap and every existing code path are byte-identical when this is\n * false (every manage branch is gated on it). Default false.\n */\n manageMode?: boolean;\n /**\n * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung\n * draws a rubber-band marquee that bulk-selects the seats it covers (emitting\n * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger\n * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below\n * the seats rung (zoom in first). No effect unless `manageMode` is also set.\n */\n marqueeSelect?: boolean;\n}\n\nexport type RenderedLabelHiddenReason =\n | 'below-minimum-size'\n | 'outside-viewport'\n | 'dimmed-or-unavailable'\n | 'clutter-or-fit'\n | 'renderer-hidden';\n\n/** Browser-renderer evidence used by visual QA and catalog release gates. */\nexport interface RenderedBookableLabelEvidence {\n seatId: string;\n label: string;\n kind: 'seat' | 'booth';\n /** Painted inventory silhouette. Empty wheelchair bays are deliberately\n * square, while physical seats retain the ordinary circular marker. */\n markerShape: 'circle' | 'square' | 'booth';\n /** Physical wheelchair provision represented by this inventory unit. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n categoryKey: string;\n sectionId?: string;\n zoneId?: string;\n status: SeatStatus;\n selected: boolean;\n visible: boolean;\n renderedFontPx: number;\n fill: string;\n ink: string;\n opacity: number;\n /** Buyer-visible accessibility glyph evidence. Filter emphasis uses a\n * screen-space minimum so wheelchair provision remains recognizable at fit. */\n accessibilityMarker?: {\n glyphVisible: boolean;\n glyphWidthPx: number;\n emphasizedByFilter: boolean;\n };\n /** Direct Konva shape bounds and the production near-miss rescue combined. */\n pointerTarget: {\n active: boolean;\n directWidthPx: number;\n directHeightPx: number;\n effectiveMinimumPx: number;\n };\n /** Centre of the painted unit, even when its text is intentionally hidden. */\n screenCenter: { x: number; y: number };\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: RenderedLabelHiddenReason;\n}\n\nexport interface RenderedHierarchyLabelEvidence {\n id: string;\n kind: 'section' | 'zone';\n role: 'name' | 'availability' | 'price';\n label: string;\n visible: boolean;\n renderedFontPx: number;\n opacity: number;\n fill: string;\n ink: string;\n /** Independent geometric containment check for section-owned text. */\n fitsContainer?: boolean;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RenderedFreeTextEvidence {\n objectId: string;\n kind: 'free-text' | 'stage' | 'table' | 'decor' | 'ga-label' | 'ga-capacity';\n text: string;\n visible: boolean;\n renderedFontPx: number;\n ink: string;\n background: string;\n opacity: number;\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden';\n}\n\nexport interface RenderedGAAreaEvidence {\n areaId: string;\n label: string;\n capacity: number;\n categoryKey: string;\n /** Owning logical section when the rendered GA surface is section-contained. */\n sectionId?: string;\n visible: boolean;\n interactive: boolean;\n opacity: number;\n fill: string;\n effectiveBackground: string;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RendererQualityEvidence {\n viewport: { width: number; height: number };\n /** Runtime projection actually used for the pixels and hit graph below. */\n projection: RendererViewMode;\n /** Phase-C proof metadata. Present only in the projected-2.5D lane. */\n perspective?: {\n model: 'pinhole-exact-seat-anchors';\n sectionSurfaceModel: 'tangent-plane';\n exactSeatAnchorCount: number;\n depthSorted: true;\n };\n canvasBackground: string;\n effectiveScale: number;\n rung: LodRung;\n minimumVisibleLabelPx: number;\n totalLabelledBookableUnits: number;\n visibleLabels: number;\n hiddenLabels: number;\n /** Seats/table-seats/booths plus the full GA capacity. */\n totalBookableUnits: number;\n selectionRingSeatIds: string[];\n selectionRingColor: string;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n /** Exact scene-graph proof for the clean section-first overview contract. */\n overviewStyle: {\n visibleSectionShells: number;\n categoryPaintedSectionShells: number;\n visibleCategoryDetailOutlines: number;\n visibleSectionRowHints: number;\n visibleSectionAvailabilityLabels: number;\n visibleSectionGADetails: number;\n };\n labels: RenderedBookableLabelEvidence[];\n gaAreas: RenderedGAAreaEvidence[];\n hierarchyLabels: RenderedHierarchyLabelEvidence[];\n freeTextLabels: RenderedFreeTextEvidence[];\n}\n\nexport interface ISeatmapRenderer {\n /** Replace the chart. Resets selection and statuses, zooms to fit.\n * `opts.floorId` picks which floor to render on a multi-floor chart (Batch 5). */\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void;\n /** Bulk status update; re-renders affected seats only. */\n setStatus(seatIds: string[], status: SeatStatus): void;\n /**\n * Mark the active buyer's own held seats. They remain server-status `held`,\n * but render with the buyer selection treatment instead of the anonymous\n * unavailable treatment used for another buyer's hold.\n */\n setOwnedHold?(seatIds: string[] | null): void;\n /**\n * Mark one selected seat as the buyer's pending confirmation candidate.\n * The candidate receives a strong focus halo while unrelated seats recede;\n * pass null after Select/Cancel. This is visual only and never mutates the\n * renderer selection.\n */\n setSelectionFocus?(seatId: string | null): void;\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()\n * (used by setStatus and friends) schedules the actual paint on the next rAF\n * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded\n * tabs — so a seat-status delta updates the scene graph but the pixels never\n * change until the tab is foregrounded again. forceDraw() paints the affected\n * layers immediately (Layer.draw() is synchronous) and flushes any pending\n * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in\n * always-live board) can guarantee the canvas reflects current state\n * regardless of tab visibility. No-op difference in the foreground.\n */\n forceDraw(): void;\n getStatus(seatId: string): SeatStatus;\n getSelection(): ExpandedSeat[];\n clearSelection(): void;\n /** Update the buyer selection cap without rebuilding the chart or camera. */\n setMaxSelection?(maxSelection: number): void;\n /**\n * Programmatically restore free seats (for example an Undo action). Added\n * seats respect the active cap and do not reopen a confirmation popover.\n */\n select?(seatIds: string[]): ExpandedSeat[];\n /**\n * Dynamically update organizer-only interaction without rebuilding the\n * renderer. No buyer surface calls this; every behavior remains gated by\n * `manageMode` exactly as it is at construction time.\n */\n setManageInteraction?(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void;\n /** Organizer-only section heat overlay. Values are normalized 0..1. */\n setSectionHeat?(scores: Record<string, number> | null): void;\n /**\n * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).\n * They select the matching SELECTABLE seats (respecting `selectableStatuses`\n * + closed sections), union with the current selection, and return the seats\n * they added — the SDK SeatManager expands category/row/section picks to\n * labels and drives one batched block/unblock from them.\n */\n selectAllSelectable?(): ExpandedSeat[];\n selectByLabels?(labels: string[]): ExpandedSeat[];\n /** Exact-render QA only: select one server-chosen unit without label ambiguity. */\n setEvidenceSelection?(seatId: string): boolean;\n /** Selectable seats belonging to a section OR zone id (no selection side-effect). */\n getSelectableInSection?(sectionId: string): ExpandedSeat[];\n /** Programmatic deselect of specific seats (e.g. chip × in the cart). */\n deselect(seatIds: string[]): void;\n /**\n * Brief attention pulse on a seat (a ring that expands + fades once) — used to\n * signal live activity, e.g. a seat \"just taken\" by another buyer via a WS\n * delta. Purely visual; no state change. `color` overrides the default.\n */\n flashSeat(seatId: string, color?: string): void;\n /**\n * Brief organizer attention pulse around a whole section. This is a visual\n * overlay only: it never changes section geometry, hit targets, selection, or\n * the active camera. Useful for grouped realtime operations at venue overview.\n */\n flashSection?(sectionId: string, color?: string): void;\n zoomToFit(): void;\n /** Zoom in one step about the viewport center, clamped to the usual zoom bounds. */\n zoomIn(): void;\n /** Zoom out one step about the viewport center, clamped to the usual zoom bounds. */\n zoomOut(): void;\n /** Individually status-managed seats/table-seats/booths; excludes GA capacity. */\n seatCount(): number;\n /** Seats/table-seats/booths plus the full capacity of rendered GA areas. */\n bookableCount(): number;\n /**\n * Maps a chart-space point (or a seat, by its x/y) to container-relative\n * screen pixels, using the current stage scale/position. Lets host UI anchor\n * DOM overlays (confirm card, tooltip) over a live seat and re-anchor them\n * on `onViewChange`.\n */\n worldToScreen(point: Point): { x: number; y: number };\n /** When on, dim non-accessible free seats so accessible seats stand out. */\n setAccessibleFilter(on: boolean): void;\n /**\n * Dim free seats that lack ANY of these accessibility types. `null` clears the\n * filter; `[]` means \"any accessible seat\" (same as setAccessibleFilter(true)).\n */\n setAccessibilityFilter(types: AccessibilityType[] | null): void;\n /** Legend hover-highlight: dim free seats of other categories (null clears). */\n setCategoryHighlight?(key: string | null): void;\n /** Price-band filter (F4): dim free seats whose category is NOT in `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter?(keys: string[] | null): void;\n /** Smoothly frame the currently available seats in these categories. `null`\n * returns to the full chart. Used after an explicit buyer price-filter action. */\n focusCategories?(keys: string[] | null): void;\n /** Dim the seats of these section/zone ids (organizer manager: held-back inventory). */\n setDimmedSections?(ids: string[] | null): void;\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, section stays rendered.\n * `null`/empty clears. (Distinct from the buyer's applyHidden seat-strip.)\n */\n setClosedSections?(ids: string[] | null): void;\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * behind this section, and glide the camera to frame it. Seat-picking is gated\n * until seats are large enough on screen (≥ LABEL_SCALE). Slice 5 / Phase 2 §4.\n */\n focusSection?(id: string): void;\n /** Clear an AXS section focus (restore full-bowl brightness + drop backdrop). */\n clearSectionFocus?(): void;\n /** The currently AXS-focused section id, or null. */\n getFocusedSection?(): string | null;\n /** World-space rect currently visible in the viewport (minimap viewport frame). */\n getVisibleWorldRect?(): { x: number; y: number; width: number; height: number };\n /** Axis-aligned world bounds of all seats + section outlines (minimap frame). */\n getWorldBounds?(): { x: number; y: number; width: number; height: number };\n /**\n * Colorblind-safe mode: category hues switch to an Okabe-Ito palette and\n * booked seats render hollow (a non-color cue), so seat state never relies\n * on hue alone. Off (the default) renders exactly as before.\n */\n setColorblindSafe?(on: boolean): void;\n /**\n * Switch the projection. `'flat'` = normal top-down; `'isometric'` = the\n * legacy affine preview; `'perspective'` = projected 2.5D with exact pinhole\n * seat anchors/native hit shapes and bounded per-section tangent surfaces.\n * Purely visual — the chart is authored flat.\n */\n setViewMode?(mode: RendererViewMode): void;\n /** Current projection (defaults to 'flat' when unimplemented). */\n getViewMode?(): RendererViewMode;\n /** Multi-floor (Batch 5): switch the shown floor; list floors; read the active id. */\n setActiveFloor?(floorId: string): void;\n getFloors?(): { id: string; name: string }[];\n getActiveFloorId?(): string;\n /** Render all floors stacked (3D overview) vs the active floor. No-op single-floor. */\n setStacked?(on: boolean): void;\n isStacked?(): boolean;\n /**\n * Section id whose outline contains a container-relative screen point (or null).\n * Feeds the far-zoom \"tap a section to zoom in\" flow (Slice 5).\n */\n sectionAt?(clientPoint: Point): string | null;\n /** Seat ids belonging to a section — for the section-summary card (Slice 5). */\n sectionMembers?(id: string): string[];\n /**\n * Smoothly glide (pan+zoom) the camera to frame a section (by id) or a world-\n * space bounds rect over a calm easeInOutCubic glide. `prefers-reduced-motion` snaps.\n * A pointer-down (grab/pan) cancels an in-flight glide. Slice 5 \"glide in\".\n */\n focusRegion?(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void;\n /** Current LOD rung derived from zoom (for the ZONES/SECTIONS/SEATS pill). */\n getRung?(): LodRung;\n /** Jump the camera to a rung's zoom band, centred on the chart (glided). */\n setRung?(rung: LodRung): void;\n /** Read actual browser-rendered label visibility, size, fill, ink and state.\n * Pure diagnostic: it never changes chart or renderer state. */\n getRenderedQualityEvidence(): RendererQualityEvidence;\n destroy(): void;\n}\n\n/** localStorage key the Designer writes and the Picker reads. */\nexport const CHART_STORAGE_KEY = 'seatmap.chart';\n","import type { CubicPath, Point } from './types';\n\nexport type SectionShellMode = 'auto' | 'rectangle' | 'tapered' | 'bezier';\n\nexport function cubicPoint(path: CubicPath, t: number): Point {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n return {\n x: a * path.start.x + b * path.control1.x + c * path.control2.x + d * path.end.x,\n y: a * path.start.y + b * path.control1.y + c * path.control2.y + d * path.end.y,\n };\n}\n\n/** Equal-arc-length points on a cubic path, including both endpoints. */\nexport function distributeAlongCubic(path: CubicPath, count: number, resolution = 192): Point[] {\n if (!Number.isInteger(count) || count < 1) throw new Error('Path point count must be a positive integer');\n if (count === 1) return [cubicPoint(path, 0.5)];\n const samples = Array.from({ length: resolution + 1 }, (_, index) => cubicPoint(path, index / resolution));\n const lengths = new Float64Array(samples.length);\n for (let index = 1; index < samples.length; index += 1) {\n const dx = samples[index].x - samples[index - 1].x;\n const dy = samples[index].y - samples[index - 1].y;\n lengths[index] = lengths[index - 1] + Math.hypot(dx, dy);\n }\n const total = lengths[lengths.length - 1];\n if (total <= 1e-9) return Array.from({ length: count }, () => ({ ...path.start }));\n const output: Point[] = [];\n let segment = 1;\n for (let index = 0; index < count; index += 1) {\n const target = (total * index) / (count - 1);\n while (segment < lengths.length - 1 && lengths[segment] < target) segment += 1;\n const before = lengths[segment - 1];\n const after = lengths[segment];\n const ratio = after === before ? 0 : (target - before) / (after - before);\n output.push({\n x: samples[segment - 1].x + (samples[segment].x - samples[segment - 1].x) * ratio,\n y: samples[segment - 1].y + (samples[segment].y - samples[segment - 1].y) * ratio,\n });\n }\n return output;\n}\n\nfunction add(a: Point, b: Point): Point { return { x: a.x + b.x, y: a.y + b.y }; }\nfunction sub(a: Point, b: Point): Point { return { x: a.x - b.x, y: a.y - b.y }; }\nfunction mul(a: Point, scale: number): Point { return { x: a.x * scale, y: a.y * scale }; }\nfunction distance(a: Point, b: Point): number { return Math.hypot(a.x - b.x, a.y - b.y); }\nfunction lerp(a: Point, b: Point, t: number): Point { return add(a, mul(sub(b, a), t)); }\n\nfunction sample(path: CubicPath, count = 13): Point[] {\n return Array.from({ length: count }, (_, index) => cubicPoint(path, index / (count - 1)));\n}\n\nfunction pointOnSampledPath(points: Point[], t: number): Point {\n const scaled = Math.max(0, Math.min(1, t)) * (points.length - 1);\n const index = Math.min(points.length - 2, Math.floor(scaled));\n return lerp(points[index], points[index + 1], scaled - index);\n}\n\nfunction sampledPathSegment(points: Point[], from: number, to: number): Point[] {\n const start = Math.max(0, Math.min(1, from));\n const end = Math.max(start, Math.min(1, to));\n const output = [pointOnSampledPath(points, start)];\n for (let index = 1; index < points.length - 1; index += 1) {\n const t = index / (points.length - 1);\n if (t > start + 1e-9 && t < end - 1e-9) output.push(points[index]);\n }\n output.push(pointOnSampledPath(points, end));\n return output;\n}\n\ninterface SectionFrame {\n p0: Point;\n p1: Point;\n p2: Point;\n p3: Point;\n normal: Point;\n depth: number;\n}\n\nfunction orientSectionFrame(corners: Point[], focal: Point): SectionFrame {\n const edges: Array<[number, number]> = [[0, 1], [1, 2], [2, 3], [3, 0]];\n let nearEdge = 0;\n let nearDistance = Number.POSITIVE_INFINITY;\n edges.forEach(([a, b], index) => {\n const d = distance(lerp(corners[a], corners[b], 0.5), focal);\n if (d < nearDistance) {\n nearDistance = d;\n nearEdge = index;\n }\n });\n const p0 = corners[nearEdge];\n const p1 = corners[(nearEdge + 1) % 4];\n const p2 = corners[(nearEdge + 2) % 4];\n const p3 = corners[(nearEdge + 3) % 4];\n const nearMid = lerp(p0, p1, 0.5);\n const inward = sub(focal, nearMid);\n const inwardLength = Math.max(1e-9, Math.hypot(inward.x, inward.y));\n return {\n p0,\n p1,\n p2,\n p3,\n normal: mul(inward, 1 / inwardLength),\n depth: (distance(p0, p3) + distance(p1, p2)) / 2,\n };\n}\n\nfunction bezierSectionPaths(frame: SectionFrame): { nearPath: CubicPath; farPath: CubicPath } {\n const { p0, p1, p2, p3, normal, depth } = frame;\n const nearSpan = sub(p1, p0);\n const farSpan = sub(p2, p3);\n const nearCurve = depth * 0.22;\n const farCurve = depth * 0.12;\n return {\n nearPath: {\n start: p0,\n control1: add(add(p0, mul(nearSpan, 1 / 3)), mul(normal, nearCurve)),\n control2: add(add(p0, mul(nearSpan, 2 / 3)), mul(normal, nearCurve)),\n end: p1,\n },\n farPath: {\n start: p2,\n control1: add(add(p3, mul(farSpan, 2 / 3)), mul(normal, farCurve)),\n control2: add(add(p3, mul(farSpan, 1 / 3)), mul(normal, farCurve)),\n end: p3,\n },\n };\n}\n\n/**\n * Convert a server-mapped rectangle into an editable complex shell. The four\n * corners must be clockwise. No caller-supplied control points are accepted.\n */\nexport function buildSectionShell(corners: Point[], focal: Point, requested: SectionShellMode): {\n mode: Exclude<SectionShellMode, 'auto'>;\n outline: Point[];\n} {\n if (corners.length !== 4) throw new Error('A section shell requires four mapped bounds corners');\n const center = corners.reduce((sum, point) => add(sum, point), { x: 0, y: 0 });\n center.x /= 4;\n center.y /= 4;\n const width = distance(corners[0], corners[1]);\n const height = distance(corners[0], corners[3]);\n const mode = requested === 'auto'\n ? (width > height * 1.25 && distance(center, focal) > height ? 'bezier' : 'tapered')\n : requested;\n if (mode === 'rectangle') return { mode, outline: corners.map((point) => ({ ...point })) };\n\n // Rotate corners so local p0→p1 is the edge nearest the focal point and\n // p3→p2 is the far edge, while preserving clockwise winding.\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n\n if (mode === 'tapered') {\n const inset = 0.14;\n return {\n mode,\n outline: [\n add(p0, mul(sub(p1, p0), inset)),\n add(p0, mul(sub(p1, p0), 1 - inset)),\n p2,\n p3,\n ],\n };\n }\n\n const { nearPath, farPath } = bezierSectionPaths(frame);\n return { mode, outline: [...sample(nearPath), ...sample(farPath).slice(1)] };\n}\n\n/** Server-owned straight aisle cutouts spanning the near/far edges. */\nexport function buildAisleHoles(\n corners: Point[],\n focal: Point,\n count: number,\n mode: Exclude<SectionShellMode, 'auto'>,\n): Point[][] {\n if (corners.length !== 4) throw new Error('Aisle generation requires four mapped bounds corners');\n if (!Number.isInteger(count) || count < 0 || count > 3) throw new Error('Aisle count must be an integer from 0 to 3');\n if (count === 0) return [];\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n const paths = mode === 'bezier' ? bezierSectionPaths(frame) : null;\n // For curved shells, interpolate the same sampled polylines stored in the\n // document. Exact cubic points between samples can sit fractionally outside\n // their chord approximation and fail topology validation/hit clipping.\n const nearSamples = paths ? sample(paths.nearPath) : null;\n const farLateralSamples = paths ? sample(paths.farPath).reverse() : null;\n const widthFraction = Math.min(0.055, 0.18 / (count + 1));\n return Array.from({ length: count }, (_, index) => {\n const t = (index + 1) / (count + 1);\n const left = t - widthFraction / 2;\n const right = t + widthFraction / 2;\n if (nearSamples && farLateralSamples) {\n return [\n ...sampledPathSegment(nearSamples, left, right),\n ...sampledPathSegment(farLateralSamples, left, right).reverse(),\n ];\n }\n return [lerp(p0, p1, left), lerp(p0, p1, right), lerp(p3, p2, right), lerp(p3, p2, left)];\n });\n}\n","import type { Point, SectionOutlinePath, SectionPathSegment } from './types';\n\nconst TAU = Math.PI * 2;\n\nfunction finitePoint(point: Point): boolean {\n return Number.isFinite(point.x) && Number.isFinite(point.y);\n}\n\nfunction distance(left: Point, right: Point): number {\n return Math.hypot(left.x - right.x, left.y - right.y);\n}\n\nfunction arcSweep(start: number, end: number, clockwise: boolean): number {\n let delta = end - start;\n if (clockwise) {\n while (delta < 0) delta += TAU;\n while (delta >= TAU) delta -= TAU;\n } else {\n while (delta > 0) delta -= TAU;\n while (delta <= -TAU) delta += TAU;\n }\n return delta;\n}\n\nexport function sectionPathSegmentEnd(segment: SectionPathSegment): Point {\n return segment.end;\n}\n\n/** Validate finite, continuous closed-path geometry without trusting renderer\n * behaviour. Arc endpoints must lie on their declared circle. */\nexport function validSectionOutlinePath(path: SectionOutlinePath): boolean {\n if (path.version !== 1 || path.closed !== true || !finitePoint(path.start)\n || !Array.isArray(path.segments) || path.segments.length < 2 || path.segments.length > 512) return false;\n let current = path.start;\n for (const segment of path.segments) {\n if (!segment || !finitePoint(segment.end)) return false;\n if (segment.kind === 'line') {\n if (distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'bezier') {\n if (!finitePoint(segment.control1) || !finitePoint(segment.control2)\n || distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'arc') {\n if (!finitePoint(segment.center) || !Number.isFinite(segment.radius) || segment.radius <= 1e-6\n || Math.abs(distance(current, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || Math.abs(distance(segment.end, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || distance(current, segment.end) <= 1e-9) return false;\n } else return false;\n current = segment.end;\n }\n return distance(current, path.start) <= 1e-4;\n}\n\nfunction cubicPoint(start: Point, segment: Extract<SectionPathSegment, { kind: 'bezier' }>, t: number): Point {\n const mt = 1 - t;\n return {\n x: mt ** 3 * start.x + 3 * mt ** 2 * t * segment.control1.x\n + 3 * mt * t ** 2 * segment.control2.x + t ** 3 * segment.end.x,\n y: mt ** 3 * start.y + 3 * mt ** 2 * t * segment.control1.y\n + 3 * mt * t ** 2 * segment.control2.y + t ** 3 * segment.end.y,\n };\n}\n\n/** Deterministic polygon sample used by validation, hit testing, diff, and old\n * clients. The returned loop omits the duplicate closing point. */\nexport function sampleSectionOutlinePath(path: SectionOutlinePath, maxStep = 2): Point[] {\n if (!validSectionOutlinePath(path)) throw new Error('Section outline path is invalid');\n const step = Math.max(0.25, maxStep);\n const points: Point[] = [{ ...path.start }];\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') {\n points.push({ ...segment.end });\n } else if (segment.kind === 'arc') {\n const startAngle = Math.atan2(current.y - segment.center.y, current.x - segment.center.x);\n const endAngle = Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x);\n const sweep = arcSweep(startAngle, endAngle, segment.clockwise);\n const count = Math.max(2, Math.ceil(Math.abs(sweep) * segment.radius / step));\n for (let index = 1; index <= count; index += 1) {\n const angle = startAngle + sweep * index / count;\n points.push({\n x: segment.center.x + Math.cos(angle) * segment.radius,\n y: segment.center.y + Math.sin(angle) * segment.radius,\n });\n }\n } else {\n const controlLength = distance(current, segment.control1)\n + distance(segment.control1, segment.control2)\n + distance(segment.control2, segment.end);\n const count = Math.max(2, Math.ceil(controlLength / step));\n for (let index = 1; index <= count; index += 1) points.push(cubicPoint(current, segment, index / count));\n }\n current = segment.end;\n }\n if (distance(points[points.length - 1], points[0]) <= 1e-4) points.pop();\n return points;\n}\n\nexport function translateSectionOutlinePath(path: SectionOutlinePath, dx: number, dy: number): SectionOutlinePath {\n const translate = (point: Point): Point => ({ x: point.x + dx, y: point.y + dy });\n return transformSectionOutlinePath(path, translate);\n}\n\n/** Apply a similarity transform. Callers provide the point transform and the\n * absolute radius scale; reflections toggle arc direction. */\nexport function transformSectionOutlinePath(\n path: SectionOutlinePath,\n transform: (point: Point) => Point,\n radiusScale = 1,\n reflected = false,\n): SectionOutlinePath {\n return {\n ...path,\n start: transform(path.start),\n segments: path.segments.map((segment) => segment.kind === 'line'\n ? { ...segment, end: transform(segment.end) }\n : segment.kind === 'arc'\n ? {\n ...segment,\n center: transform(segment.center),\n radius: segment.radius * Math.abs(radiusScale),\n clockwise: reflected ? !segment.clockwise : segment.clockwise,\n end: transform(segment.end),\n }\n : {\n ...segment,\n control1: transform(segment.control1),\n control2: transform(segment.control2),\n end: transform(segment.end),\n }),\n };\n}\n\n/** Reverse a closed path without changing its painted boundary. */\nexport function reverseSectionOutlinePath(path: SectionOutlinePath): SectionOutlinePath {\n const starts: Point[] = [];\n let current = path.start;\n for (const segment of path.segments) {\n starts.push(current);\n current = segment.end;\n }\n const segments: SectionPathSegment[] = [];\n for (let index = path.segments.length - 1; index >= 0; index -= 1) {\n const segment = path.segments[index];\n const end = starts[index];\n if (segment.kind === 'line') segments.push({ kind: 'line', end: { ...end } });\n else if (segment.kind === 'arc') segments.push({\n kind: 'arc', center: { ...segment.center }, radius: segment.radius,\n clockwise: !segment.clockwise, end: { ...end },\n });\n else segments.push({\n kind: 'bezier', control1: { ...segment.control2 }, control2: { ...segment.control1 }, end: { ...end },\n });\n }\n return { version: 1, closed: true, start: { ...path.start }, segments };\n}\n","/**\n * Pure row/seat labeling helpers used by the designer's \"relabel\" tools\n * (e.g. bulk-renumber rows A, B, C… or 1, 2, 3…). No dependencies.\n */\n\nexport interface RelabelOptions {\n scheme: 'letters' | 'numbers';\n /** 1-based start: letters 1=A; numbers 1=1. */\n startAt: number;\n /** Letters only: skip I and O (common theatre convention). */\n skipAmbiguous?: boolean;\n /** Apply labels in reverse order over the given array. */\n reverse?: boolean;\n}\n\nconst FULL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst SAFE_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // no I, no O\n\nconst LOWER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz';\n\n/**\n * Bijective base-N conversion: 0 -> first letter, N -> second letter's\n * first repeat cycle (e.g. base26: 25 -> 'Z', 26 -> 'AA').\n */\nexport function toBijectiveBase(index: number, alphabet: string): string {\n const base = alphabet.length;\n let n = index + 1; // bijective numeration is 1-based\n let out = '';\n while (n > 0) {\n n -= 1;\n const rem = n % base;\n out = alphabet[rem] + out;\n n = Math.floor(n / base);\n }\n return out;\n}\n\nexport function indexLabel(i: number, opts: RelabelOptions): string {\n const start = opts.startAt - 1; // convert 1-based startAt to 0-based offset\n const idx = i + start;\n if (opts.scheme === 'numbers') {\n return String(idx + 1);\n }\n const alphabet = opts.skipAmbiguous ? SAFE_ALPHABET : FULL_ALPHABET;\n return toBijectiveBase(idx, alphabet);\n}\n\n/**\n * Alphabetic label for a 1-based value (1 -> 'A', 26 -> 'Z', 27 -> 'AA').\n * Uppercase by default; `lower` gives the a,b,c… variant. Values ≤ 0 clamp to 'A'.\n */\nexport function toLetters(value: number, lower = false): string {\n const alphabet = lower ? LOWER_ALPHABET : FULL_ALPHABET;\n return toBijectiveBase(Math.max(0, Math.floor(value) - 1), alphabet);\n}\n\nconst ROMAN_TABLE: Array<[number, string]> = [\n [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], [100, 'C'], [90, 'XC'],\n [50, 'L'], [40, 'XL'], [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'],\n];\n\n/** Uppercase Roman numeral for a positive integer (1 -> 'I', 4 -> 'IV', 9 -> 'IX').\n * Non-positive / non-finite inputs fall back to their decimal string. */\nexport function toRoman(value: number): string {\n if (!Number.isFinite(value) || value <= 0) return String(value);\n let remaining = Math.floor(value);\n let out = '';\n for (const [n, sym] of ROMAN_TABLE) {\n while (remaining >= n) {\n out += sym;\n remaining -= n;\n }\n }\n return out;\n}\n\nexport function relabelRows<T extends { label: string }>(rows: T[], opts: RelabelOptions): T[] {\n const n = rows.length;\n return rows.map((row, i) => {\n const assignIndex = opts.reverse ? n - 1 - i : i;\n return { ...row, label: indexLabel(assignIndex, opts) };\n });\n}\n","/**\n * Real-world scale primitives — the ONE place the app fixes chart-unit ↔ metre ↔\n * renderer-world scale, and the section 3D-geometry resolver that rides on it.\n *\n * Everything that converts between chart units, metres, and renderer \"world\"\n * units derives from {@link METRES_PER_CHART_UNIT}. Renderer world units and\n * chart units are 1:1, so metres → world is exactly {@link CHART_UNITS_PER_METRE}\n * (the single m→world conversion constant Phase B consumers use).\n *\n * This is a leaf module (types only) so both `layout.ts` and `sections.ts` can\n * import it without the two forming an import cycle.\n */\nimport type { SectionObject } from './types';\n\n/**\n * Chart units → metres. seatSpacing 24 ≈ 0.55 m (a real seat pitch). This single\n * constant anchors every real-world scale in the app; `generatePanorama` and the\n * iso lift both derive from it instead of re-declaring their own 0.55/24.\n */\nexport const METRES_PER_CHART_UNIT = 0.55 / 24;\n\n/**\n * Metres → chart units, i.e. metres → renderer world units (world == chart units\n * in the engine). THE single m→world conversion constant: the iso view lifts an\n * elevated section by `sectionGeometry(section).height × CHART_UNITS_PER_METRE`.\n */\nexport const CHART_UNITS_PER_METRE = 1 / METRES_PER_CHART_UNIT;\n\n/**\n * Renderer world units a section lifts per {@link SectionObject.elevation} tier in\n * the legacy iso view (mirror of `SeatmapRenderer`'s old `LIFT_PER_STEP`). Kept so\n * the tier→metres fallback below reproduces today's iso look byte-for-byte.\n */\nexport const LIFT_PER_STEP_WORLD = 58;\n\n/**\n * Metres of front-edge height one elevation tier represents. Chosen (not guessed)\n * so `elevation × TIER_HEIGHT_M` metres, scaled back through\n * {@link CHART_UNITS_PER_METRE}, equals the legacy `elevation × LIFT_PER_STEP`\n * world lift exactly — an un-authored chart stays pixel-identical. ≈ 1.329 m/tier.\n */\nexport const TIER_HEIGHT_M = LIFT_PER_STEP_WORLD * METRES_PER_CHART_UNIT;\n\n/** Canonical authored section-geometry bounds. Keep every UI/API/renderer on\n * these constants so a producer cannot silently invent a second unit system. */\nexport const SECTION_ELEVATION_TIER_MIN = 0;\nexport const SECTION_ELEVATION_TIER_MAX = 3;\nexport const SECTION_HEIGHT_MIN_M = 0;\nexport const SECTION_HEIGHT_MAX_M = 120;\nexport const SECTION_RAKE_MIN_DEG = 0;\nexport const SECTION_RAKE_MAX_DEG = 45;\n\n/** Curated charts released before the height field used coarse levels 4–7.\n * Preserve their established lift while drafts/templates migrate to an explicit\n * height. Values above 7 came from broken compiler multipliers and must never be\n * interpreted as physical tiers. */\nexport const LEGACY_SECTION_ELEVATION_TIER_MAX = 7;\n\n/**\n * Seated spectator eye height above the tier floor (arena ≈ 1.20 m; theatre refs\n * use 1.15 m). Also the flat-ground baseline eye height, so a flat, ground-level\n * seat produces zero elevation offset in the 360° stage-pitch math (back-compat).\n */\nexport const SEATED_EYE_HEIGHT_M = 1.2;\n\n/**\n * Resolve a section's real 3D geometry, applying the legacy-elevation fallback so\n * old charts and new charts share ONE code path. Every consumer (iso lift, 360°\n * eye-height, author lint, any 2D depth cue) must call this and never read the raw\n * {@link SectionObject.height}/{@link SectionObject.rake} fields — that is what\n * keeps un-authored charts rendering identically to today.\n *\n * - `height`: authored absolute metres if present, else owning-floor base height\n * plus `elevation × TIER_HEIGHT_M`.\n * - `rake`: authored degrees if present, else 0 (flat).\n *\n * Malformed values are bounded here as a last defensive barrier. Structural\n * validation still reports them so drafts can be repaired instead of silently\n * persisting a renderer-only interpretation.\n *\n * Pure — no document mutation, no side effects.\n */\nexport interface SectionGeometryContext {\n /** Absolute physical height of the owning floor above the venue datum. */\n floorBaseHeightM?: number;\n}\n\nfunction finiteClamped(value: number | undefined, min: number, max: number, fallback: number): number {\n return Number.isFinite(value) ? Math.max(min, Math.min(max, value as number)) : fallback;\n}\n\n/** Canonical 0–3 tier exposed by Designer/shared operations. */\nexport function sectionElevationTier(value: number | undefined): number {\n if (!Number.isFinite(value)) return SECTION_ELEVATION_TIER_MIN;\n return Math.max(\n SECTION_ELEVATION_TIER_MIN,\n Math.min(SECTION_ELEVATION_TIER_MAX, Math.round(value as number)),\n );\n}\n\n/** Runtime-only compatibility tier. Released curated charts used integers 4–7;\n * preserve those while bounding compiler mistakes such as 12/55/220 to the\n * canonical maximum. New documents must store only {@link sectionElevationTier}. */\nfunction compatibleAutomaticTier(value: number | undefined): number {\n if (!Number.isFinite(value) || !Number.isInteger(value) || (value as number) < 0) return 0;\n if ((value as number) <= LEGACY_SECTION_ELEVATION_TIER_MAX) return value as number;\n return SECTION_ELEVATION_TIER_MAX;\n}\n\nexport function sectionGeometry(\n section: Pick<SectionObject, 'elevation' | 'height' | 'rake'>,\n context: SectionGeometryContext = {},\n): {\n height: number;\n rake: number;\n} {\n const floorBaseHeightM = finiteClamped(\n context.floorBaseHeightM,\n SECTION_HEIGHT_MIN_M,\n SECTION_HEIGHT_MAX_M,\n 0,\n );\n const automaticHeight = Math.min(\n SECTION_HEIGHT_MAX_M,\n floorBaseHeightM + compatibleAutomaticTier(section.elevation) * TIER_HEIGHT_M,\n );\n const height = section.height === undefined\n ? automaticHeight\n : finiteClamped(section.height, SECTION_HEIGHT_MIN_M, SECTION_HEIGHT_MAX_M, automaticHeight);\n const rake = finiteClamped(section.rake, SECTION_RAKE_MIN_DEG, SECTION_RAKE_MAX_DEG, 0);\n return { height, rake };\n}\n","/**\n * Pure geometry helpers — no Konva, no DOM. Turns the parametric chart\n * document into concrete seat coordinates and computes bounding boxes.\n */\n\nimport type {\n AccessibilityType,\n BoothObject,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n Floor,\n LabelStyle,\n Point,\n RowObject,\n RectTableSeatCounts,\n RectTableSide,\n SeatOverride,\n SectionObject,\n TableObject,\n} from './types';\nimport { distributeAlongCubic } from './complexGeometry';\nimport { translateSectionOutlinePath } from './sectionPath';\nimport { toLetters, toRoman } from './labeling';\nimport { METRES_PER_CHART_UNIT, SEATED_EYE_HEIGHT_M, sectionGeometry } from './units';\n\n/** Resolve a seat override's accessibility, honouring the legacy boolean flag. */\nfunction overrideAccessibility(o: SeatOverride | undefined): AccessibilityType[] {\n if (!o) return [];\n if (o.accessibility && o.accessibility.length) {\n return o.wheelchairSpaceType && !o.accessibility.includes('wheelchair')\n ? ['wheelchair', ...o.accessibility]\n : o.accessibility;\n }\n if (o.wheelchairSpaceType) return ['wheelchair'];\n return o.accessible ? ['wheelchair'] : [];\n}\n\nconst DEG = Math.PI / 180;\n/** Seat visual radius (mirrors the renderer) — used only for bounds padding. */\nconst SEAT_R = 9;\n/** How far outside a table's body its seats sit. */\nconst TABLE_SEAT_OFFSET = 16;\n\n/** Rotate a local point clockwise by `deg` (screen coords, +y down) then translate. */\nfunction place(lx: number, ly: number, deg: number, origin: Point): { x: number; y: number } {\n const a = deg * DEG;\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n return {\n x: origin.x + lx * cos - ly * sin,\n y: origin.y + lx * sin + ly * cos,\n };\n}\n\n/**\n * Expand a parametric row into seat positions.\n *\n * Straight (curve === 0): seat i sits at local (i·spacing, 0).\n *\n * Curved: seats lie on a circular arc. Per-seat angular step is\n * `curve/(seatCount-1)`; radius is derived so the chord between neighbours\n * equals seatSpacing → radius = spacing / (2·sin(step/2)). Seat 0 sits at the\n * bottom of the arc (local origin) with the circle centre directly above it at\n * (0,-radius); increasing index sweeps toward +x while the ends rise toward -y,\n * i.e. positive curve is concave toward -y (a row wrapping a stage above it).\n * Local points are then rotated by `rotation` and translated to `origin`.\n *\n * Numbering (labels only, never geometry): `seatNumbering.direction === 'rtl'`\n * numbers from the far physical end; `step === 2` produces odd/even numbering\n * (start at 1 → 1,3,5…; start at 2 → 2,4,6…).\n */\n/** Base (pre-override) seat centre per index — shared by expandRow + designer edit mode. */\nexport function rowSeatPositions(row: RowObject): Point[] {\n const { seatCount, seatSpacing, curve, rotation, origin } = row;\n const out: Point[] = [];\n if (row.path) return distributeAlongCubic(row.path, seatCount);\n if (seatCount <= 1) {\n if (seatCount === 1) out.push({ x: origin.x, y: origin.y });\n return out;\n }\n if (curve === 0) {\n for (let i = 0; i < seatCount; i++) out.push(place(i * seatSpacing, 0, rotation, origin));\n return out;\n }\n const arcStep = (curve / (seatCount - 1)) * DEG; // radians per seat\n const radius = seatSpacing / (2 * Math.sin(Math.abs(arcStep) / 2));\n // Centre above seat 0. φ measured from the downward vertical, growing with index.\n for (let i = 0; i < seatCount; i++) {\n const phi = i * arcStep;\n const lx = radius * Math.sin(phi);\n const ly = -radius + radius * Math.cos(phi); // ≤ 0 → ends rise toward -y\n out.push(place(lx, ly, rotation, origin));\n }\n return out;\n}\n\nfunction overrideMap(row: RowObject): Map<number, SeatOverride> {\n const m = new Map<number, SeatOverride>();\n if (row.overrides) for (const o of row.overrides) m.set(o.index, o);\n return m;\n}\n\n/** Sellable row slots: skipped slots are absent; empty wheelchair bays remain. */\nexport function rowInventoryCount(row: RowObject): number {\n const skipped = new Set((row.overrides ?? [])\n .filter((override) => override.skip && Number.isInteger(override.index)\n && override.index >= 0 && override.index < row.seatCount)\n .map((override) => override.index));\n return Math.max(0, row.seatCount - skipped.size);\n}\n\n/**\n * Every seat slot of a row INCLUDING skipped ones (designer seat-edit mode uses\n * this to draw un-skip handles). Overrides (dx/dy/label/categoryKey) are applied\n * but a skipped slot is flagged, not omitted.\n */\nexport interface RowSeatSlot {\n index: number;\n x: number;\n y: number;\n label: string;\n displayLabel: string;\n categoryKey: string;\n skipped: boolean;\n accessible: boolean;\n accessibility: AccessibilityType[];\n wheelchairSpaceType?: SeatOverride['wheelchairSpaceType'];\n commercial?: RowObject['commercial'];\n viewUrl?: string;\n labelStyle?: LabelStyle;\n}\n\n/** Every authored table-chair slot, including skipped inventory. This mirrors\n * row seat slots so Designer, MCP and buyer/event expansion share one semantic\n * source while retaining the table's stable numeric slot identity. */\nexport interface TableSeatSlot extends RowSeatSlot {\n side?: RectTableSide;\n}\n\n/**\n * Number outward from the middle: rank seats by distance from centre (inner-left\n * wins ties), so the centre seat gets rank 0 (the lowest number). Shared by the\n * `center` direction across every scheme.\n */\nfunction centerRank(n: number): number[] {\n const rank = new Array<number>(n);\n Array.from({ length: n }, (_, i) => i)\n .sort((a, b) => Math.abs(2 * a - (n - 1)) - Math.abs(2 * b - (n - 1)) || a - b)\n .forEach((idx, k) => (rank[idx] = k));\n return rank;\n}\n\n/**\n * The seat NUMBER part of a row seat's label (the row prefix is prepended by the\n * caller). Applies the row's numbering scheme, direction, step, start and label\n * prefix. Labels only — never geometry. See `RowObject.seatNumbering.scheme`.\n */\nexport function seatLabelPart(row: RowObject, i: number): string {\n const rawStart = row.seatLabelStart ?? 1;\n const dir = row.seatNumbering?.direction ?? 'ltr';\n const step = row.seatNumbering?.step ?? 1;\n const scheme = row.seatNumbering?.scheme ?? 'decimal';\n const prefix = row.seatNumbering?.prefix ?? '';\n const endAt = row.seatNumbering?.endAt;\n const n = row.seatCount;\n\n // Both up/down variants replace direction and number by physical left→right\n // order. `updown` is odd-up-even-back (1,3,5,…,6,4,2); the distinct reverse\n // variant is odd-back-even-up (…5,3,1,2,4,6). `start` shifts either sequence.\n // They own their sequence, so both ignore `endAt`.\n if (scheme === 'updown' || scheme === 'updown-descending') {\n const half = Math.ceil(n / 2);\n const core = scheme === 'updown'\n ? (i < half ? rawStart + 2 * i : rawStart - 1 + 2 * (n - i))\n : (i < half ? rawStart + 2 * (half - 1 - i) : rawStart + 1 + 2 * (i - half));\n return `${prefix}${core}`;\n }\n\n // End-at preset (\"useEndAt\"): derive `start` so the LAST-numbered seat\n // (position rank n-1) lands on `endAt`, honouring the scheme's effective step\n // (odd/even = 2). `endAt` wins over the stored `seatLabelStart`.\n const effStep = scheme === 'odd' || scheme === 'even' ? 2 : step;\n const start = endAt != null && Number.isFinite(endAt) ? endAt - (n - 1) * effStep : rawStart;\n\n // Position rank p ∈ [0, n-1]: the 0-based ordinal along the numbering\n // direction. Every remaining scheme is a formatting of `start + p*step`.\n const p = dir === 'center' ? centerRank(n)[i] : dir === 'rtl' ? n - 1 - i : i;\n\n let core: string;\n switch (scheme) {\n case 'odd': {\n const firstOdd = start % 2 === 1 ? start : start + 1;\n core = String(firstOdd + p * 2);\n break;\n }\n case 'even': {\n const firstEven = start % 2 === 0 ? start : start + 1;\n core = String(firstEven + p * 2);\n break;\n }\n case 'roman':\n core = toRoman(start + p * step);\n break;\n case 'letters-upper':\n core = toLetters(start + p * step, false);\n break;\n case 'letters-lower':\n core = toLetters(start + p * step, true);\n break;\n case 'decimal':\n default:\n core = String(start + p * step);\n break;\n }\n return `${prefix}${core}`;\n}\n\nexport function expandRowSlots(row: RowObject): RowSeatSlot[] {\n const ov = overrideMap(row);\n return rowSeatPositions(row).map((p, i) => {\n const o = ov.get(i);\n const accessibility = overrideAccessibility(o);\n const part = seatLabelPart(row, i);\n const inventoryLabel = o?.label ?? `${row.label}-${part}`;\n const displayPrefix = row.displayLabel ?? row.label;\n const commercial = { ...row.commercial, ...o?.commercial };\n return {\n index: i,\n x: p.x + (o?.dx ?? 0),\n y: p.y + (o?.dy ?? 0),\n label: inventoryLabel,\n displayLabel: o?.displayLabel ?? `${displayPrefix}-${part}`,\n categoryKey: o?.categoryKey ?? row.categoryKey,\n skipped: !!o?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n wheelchairSpaceType: o?.wheelchairSpaceType,\n commercial: Object.values(commercial).some((value) => value !== undefined && value !== false && value !== '') ? commercial : undefined,\n viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl,\n labelStyle: o?.labelStyle,\n };\n });\n}\n\nexport function expandRow(row: RowObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n for (const slot of expandRowSlots(row)) {\n if (slot.skipped) continue; // physical seat absent; numbering gap preserved\n seats.push({\n id: `${row.id}:${slot.index}`,\n label: slot.label,\n displayLabel: slot.displayLabel === slot.label ? undefined : slot.displayLabel,\n x: slot.x,\n y: slot.y,\n rowId: row.id,\n categoryKey: slot.categoryKey,\n accessible: slot.accessible || undefined,\n accessibility: slot.accessibility.length ? slot.accessibility : undefined,\n wheelchairSpaceType: slot.wheelchairSpaceType,\n commercial: slot.commercial,\n viewUrl: slot.viewUrl,\n labelStyle: slot.labelStyle,\n });\n }\n return seats;\n}\n\n/**\n * Expand a table into its perimeter seats.\n *\n * Round: seats spread evenly on a circle of radius `radius + 16`, the first at\n * angle `rotation` (degrees, clockwise from +x). Rect: seats line the top and\n * bottom edges (split evenly, any remainder to the top), 16u outside the edge,\n * the whole set rotated about the table centre.\n */\n/** Legacy rect tables distribute aggregate capacity round-robin across enabled\n * sides, then emit chairs in canonical top/bottom/left/right order. */\nexport function tableSeatCountsBySide(t: TableObject): RectTableSeatCounts {\n if (t.seatCountsBySide) return { ...t.seatCountsBySide };\n const enabled = t.sides && t.sides.length ? t.sides : ['top', 'bottom'];\n const order = (['top', 'bottom', 'left', 'right'] as const).filter((side) => enabled.includes(side));\n const counts: RectTableSeatCounts = { top: 0, bottom: 0, left: 0, right: 0 };\n if (!order.length) return counts;\n const n = Math.max(0, Math.round(t.seatCount));\n for (let index = 0; index < n; index++) counts[order[index % order.length]] += 1;\n return counts;\n}\n\n/** Expand every authored table chair, including skipped slots needed by the\n * Designer to restore inventory. */\nexport function expandTableSlots(t: TableObject): TableSeatSlot[] {\n const seats: TableSeatSlot[] = [];\n const n = Math.max(0, Math.round(t.seatCount));\n if (n === 0) return seats;\n const overrides = new Map((t.overrides ?? []).map((override) => [override.index, override]));\n const mk = (index: number, x: number, y: number, side?: RectTableSide): TableSeatSlot => {\n const override = overrides.get(index);\n const accessibility = overrideAccessibility(override);\n const label = override?.label ?? `${t.label}-${index + 1}`;\n const displayPrefix = t.displayLabel ?? t.label;\n return {\n index,\n label,\n displayLabel: override?.displayLabel ?? `${displayPrefix}-${index + 1}`,\n x: x + (override?.dx ?? 0),\n y: y + (override?.dy ?? 0),\n categoryKey: override?.categoryKey ?? t.categoryKey,\n skipped: !!override?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n wheelchairSpaceType: override?.wheelchairSpaceType,\n commercial: override?.commercial,\n viewUrl: override?.viewFromSeatUrl,\n labelStyle: override?.labelStyle,\n ...(side ? { side } : {}),\n };\n };\n\n if (t.shape === 'round') {\n const R = (t.radius ?? 40) + TABLE_SEAT_OFFSET;\n const base = t.rotation * DEG;\n const arc = Math.max(0, Math.min(360, t.seatArc ?? 360));\n if (arc >= 360 || n === 1) {\n for (let i = 0; i < n; i++) {\n const a = base + (i / n) * 2 * Math.PI;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n const arcRad = arc * DEG;\n const halfGap = (2 * Math.PI - arcRad) / 2;\n const start = base + halfGap;\n for (let i = 0; i < n; i++) {\n const a = start + (i / (n - 1)) * arcRad;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n\n const w = t.width ?? 80;\n const h = t.height ?? 50;\n const counts = tableSeatCountsBySide(t);\n const order = ['top', 'bottom', 'left', 'right'] as const;\n let idx = 0;\n for (const side of order) {\n const count = counts[side];\n for (let j = 0; j < count; j++) {\n let localX: number;\n let localY: number;\n if (side === 'top') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = -h / 2 - TABLE_SEAT_OFFSET;\n } else if (side === 'bottom') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = h / 2 + TABLE_SEAT_OFFSET;\n } else if (side === 'left') {\n localX = -w / 2 - TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n } else {\n localX = w / 2 + TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n }\n const point = place(localX, localY, t.rotation, t.center);\n seats.push(mk(idx++, point.x, point.y, side));\n }\n }\n return seats;\n}\n\n/** Sellable individual table chairs. Grouped tables own one atomic inventory\n * unit elsewhere and therefore retain their full authored chair capacity. */\nexport function tableInventoryCount(t: TableObject): number {\n if (t.bookAsWhole || t.variableOccupancy) return Math.max(0, Math.round(t.seatCount));\n return expandTableSlots(t).filter((slot) => !slot.skipped).length;\n}\n\nexport function expandTable(t: TableObject): ExpandedSeat[] {\n return expandTableSlots(t).filter((slot) => !slot.skipped).map((slot) => ({\n id: `${t.id}:${slot.index}`,\n label: slot.label,\n ...(slot.displayLabel !== slot.label ? { displayLabel: slot.displayLabel } : {}),\n x: slot.x,\n y: slot.y,\n rowId: t.id,\n categoryKey: slot.categoryKey,\n ...(slot.accessible ? { accessible: true } : {}),\n ...(slot.accessibility.length ? { accessibility: slot.accessibility } : {}),\n ...(slot.wheelchairSpaceType ? { wheelchairSpaceType: slot.wheelchairSpaceType } : {}),\n ...(slot.commercial ? { commercial: slot.commercial } : {}),\n ...(slot.viewUrl ? { viewUrl: slot.viewUrl } : {}),\n ...(slot.labelStyle ? { labelStyle: slot.labelStyle } : {}),\n }));\n}\n\n/** Expand a booth into its single bookable block unit. */\nexport function expandBooth(b: BoothObject): ExpandedSeat[] {\n return [\n {\n id: `${b.id}:0`,\n label: b.label,\n ...(b.displayLabel && b.displayLabel !== b.label ? { displayLabel: b.displayLabel } : {}),\n x: b.center.x,\n y: b.center.y,\n rowId: b.id,\n categoryKey: b.categoryKey,\n kind: 'booth',\n },\n ];\n}\n\n/** Ray-cast point-in-polygon test — odd crossings ⇒ inside. */\nexport function pointInPolygon(p: Point, poly: Point[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x;\n const yi = poly[i].y;\n const xj = poly[j].x;\n const yj = poly[j].y;\n const hit = yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;\n if (hit) inside = !inside;\n }\n return inside;\n}\n\nfunction pointOnPolygonBoundary(p: Point, poly: Point[]): boolean {\n return poly.some((start, index) => {\n const end = poly[(index + 1) % poly.length];\n const cross = (p.y - start.y) * (end.x - start.x) - (p.x - start.x) * (end.y - start.y);\n if (Math.abs(cross) > 1e-7) return false;\n const dot = (p.x - start.x) * (end.x - start.x) + (p.y - start.y) * (end.y - start.y);\n const lengthSquared = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;\n return dot >= -1e-7 && dot <= lengthSquared + 1e-7;\n });\n}\n\nexport function pointInPolygonWithHoles(p: Point, outer: Point[], holes: Point[][] | undefined): boolean {\n return pointInPolygon(p, outer)\n && !(holes ?? []).some((hole) => pointInPolygon(p, hole) || pointOnPolygonBoundary(p, hole));\n}\n\n/** Stable interior label anchor that cannot land inside a polygon cutout. */\nexport function polygonLabelPoint(outer: Point[], holes: Point[][] | undefined): Point {\n if (!outer.length) return { x: 0, y: 0 };\n const xs = outer.map((point) => point.x);\n const ys = outer.map((point) => point.y);\n const bounds = { minX: Math.min(...xs), maxX: Math.max(...xs), minY: Math.min(...ys), maxY: Math.max(...ys) };\n const centroid = polygonCentroid(outer);\n if (pointInPolygonWithHoles(centroid, outer, holes)) return centroid;\n let best = outer[0];\n let bestScore = -Infinity;\n const rings = [outer, ...(holes ?? [])];\n for (let row = 1; row < 24; row += 1) {\n for (let column = 1; column < 24; column += 1) {\n const point = {\n x: bounds.minX + ((bounds.maxX - bounds.minX) * column) / 24,\n y: bounds.minY + ((bounds.maxY - bounds.minY) * row) / 24,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) continue;\n const score = Math.min(...rings.flatMap((ring) => ring.map((start, index) => {\n const end = ring[(index + 1) % ring.length];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const denominator = dx * dx + dy * dy;\n const projection = denominator\n ? ((point.x - start.x) * dx + (point.y - start.y) * dy) / denominator\n : 0;\n const t = Math.max(0, Math.min(1, projection));\n return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));\n })));\n if (score > bestScore) { best = point; bestScore = score; }\n }\n }\n return best;\n}\n\n/** Average of polygon vertices (v1 centroid — good enough for labels/membership). */\nfunction polygonCentroid(pts: Point[]): Point {\n if (!pts.length) return { x: 0, y: 0 };\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p.x;\n y += p.y;\n }\n return { x: x / pts.length, y: y / pts.length };\n}\n\n/**\n * Visual centre of any object — used for spatial section membership and for\n * rotating an object about its centre. Rows: centroid of expanded seats (or\n * origin when empty); tables/booths: centre; GA/section: polygon centroid;\n * shape: bbox centre; text: its position.\n */\nexport function objectCenter(o: ChartObject): Point {\n switch (o.type) {\n case 'row': {\n const seats = expandRow(o);\n if (!seats.length) return { x: o.origin.x, y: o.origin.y };\n let x = 0;\n let y = 0;\n for (const s of seats) {\n x += s.x;\n y += s.y;\n }\n return { x: x / seats.length, y: y / seats.length };\n }\n case 'table':\n case 'booth':\n return { x: o.center.x, y: o.center.y };\n case 'gaArea':\n return polygonCentroid(o.points);\n case 'section':\n return polygonCentroid(o.outline);\n case 'text':\n return { x: o.position.x, y: o.position.y };\n case 'shape':\n if (o.points && o.points.length) return polygonCentroid(o.points);\n if (o.x != null && o.y != null && o.width != null && o.height != null) {\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n return { x: o.x ?? 0, y: o.y ?? 0 };\n case 'decorImage':\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n}\n\nfunction samePoints(left: Point[], right: Point[]): boolean {\n return left.length === right.length\n && left.every((point, index) => point.x === right[index].x && point.y === right[index].y);\n}\n\nfunction sameGASurfaceAsSection(object: ChartObject, section: SectionObject): boolean {\n if (object.type !== 'gaArea' || !samePoints(object.points, section.outline)) return false;\n const objectHoles = object.holes ?? [];\n const sectionHoles = section.holes ?? [];\n return objectHoles.length === sectionHoles.length\n && objectHoles.every((hole, index) => samePoints(hole, sectionHoles[index]));\n}\n\n/**\n * Resolve one bookable object's owning physical section using the canonical\n * first-match rule. Generated reference inventory may name a logical section,\n * but that provenance is trusted only when the stored geometry confirms it.\n * Keeping this primitive in layout lets section inventory, category painting,\n * and buyer view inheritance share one ownership decision.\n */\nexport function owningSectionForObject(\n objects: ChartObject[],\n object: ChartObject,\n): SectionObject | undefined {\n const sections = objects.filter((candidate): candidate is SectionObject => candidate.type === 'section');\n const referencedLogicalId = 'referenceInventorySource' in object\n ? object.referenceInventorySource?.logicalSectionId\n : undefined;\n const center = objectCenter(object);\n const referencedOwner = referencedLogicalId\n ? sections.find((section) => (\n (section.logicalSectionId ?? section.id) === referencedLogicalId\n && (sameGASurfaceAsSection(object, section)\n || pointInPolygonWithHoles(center, section.outline, section.holes))\n ))\n : undefined;\n return referencedOwner\n ?? sections.find((section) => pointInPolygonWithHoles(center, section.outline, section.holes));\n}\n\n/**\n * Normalized floor list (Batch 5): a multi-floor chart's `floors`, or a synthetic\n * single floor wrapping a single-floor chart's `objects`. Every consumer that needs\n * to reason about floors goes through this so single-floor charts stay untouched.\n */\nexport function floorsOf(doc: ChartDoc): Floor[] {\n if (doc.floors && doc.floors.length) return doc.floors;\n return [{\n id: 'floor-0',\n name: 'Main',\n objects: doc.objects,\n focalPoint: doc.focalPoint,\n referenceImage: doc.referenceImage,\n backgroundImage: doc.backgroundImage,\n }];\n}\n\n/** Objects of one floor by id (defaults to the first floor). */\nexport function floorObjects(doc: ChartDoc, floorId?: string): ChartObject[] {\n const floors = floorsOf(doc);\n return (floorId ? floors.find((f) => f.id === floorId) : floors[0])?.objects ?? [];\n}\n\n/** Every object across ALL floors — the whole venue (single-floor = `doc.objects`). */\nexport function allObjects(doc: ChartDoc): ChartObject[] {\n return doc.floors && doc.floors.length ? doc.floors.flatMap((f) => f.objects) : doc.objects;\n}\n\n/** A copy of an object translated by (dx, dy) — every coordinate field shifted. */\nfunction translateObject(o: ChartObject, dx: number, dy: number): ChartObject {\n const p = (pt: Point): Point => ({ x: pt.x + dx, y: pt.y + dy });\n const pts = (a: Point[]): Point[] => a.map(p);\n switch (o.type) {\n case 'row':\n return { ...o, origin: p(o.origin) };\n case 'table':\n case 'booth':\n return { ...o, center: p(o.center) };\n case 'gaArea':\n return { ...o, points: pts(o.points), ...(o.holes ? { holes: o.holes.map(pts) } : {}) };\n case 'section':\n return {\n ...o,\n outline: pts(o.outline),\n ...(o.outlinePath ? { outlinePath: translateSectionOutlinePath(o.outlinePath, dx, dy) } : {}),\n ...(o.holes ? { holes: o.holes.map(pts) } : {}),\n };\n case 'text':\n return { ...o, position: p(o.position) };\n case 'shape':\n return {\n ...o,\n ...(o.points ? { points: pts(o.points) } : {}),\n ...(o.x != null ? { x: o.x + dx } : {}),\n ...(o.y != null ? { y: o.y + dy } : {}),\n };\n case 'decorImage':\n return { ...o, x: o.x + dx, y: o.y + dy };\n }\n}\n\n/**\n * Multi-floor 3D stack (Batch 5): flatten every floor into ONE doc with floor `i`\n * lifted by `i * spread` in −y, so the isometric view shows the floors as stacked\n * decks (ground at the bottom). Returns a single-floor doc (no `floors`). Meant\n * only for the 3D overview render — 2D still shows one floor via `floorObjects`.\n */\nexport function stackFloors(doc: ChartDoc, spread = 900): ChartDoc {\n if (!doc.floors || doc.floors.length < 2) return doc;\n const objects: ChartObject[] = [];\n doc.floors.forEach((f, i) => {\n const dy = -i * spread;\n for (const o of f.objects) objects.push(dy === 0 ? o : translateObject(o, 0, dy));\n });\n return { ...doc, objects, floors: undefined };\n}\n\nexport interface ExpandChartOptions {\n /** Physical height for a single-floor projection extracted from a multi-floor\n * document. Full multi-floor documents resolve each floor directly. */\n floorBaseHeightM?: number;\n}\n\nfunction expandFloorObjects(\n objects: ChartObject[],\n zones: ChartDoc['zones'],\n fallbackFocal: Point | undefined,\n): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n const segmented = new Map<string, {\n groupId: string;\n adjacencyOffset: number;\n displayOffset: number;\n displayLabel: string;\n totalSeats: number;\n canonical: RowObject;\n viewFromSeatUrl?: string;\n }>();\n\n // Resolve only complete, internally coherent groups. Malformed metadata is\n // surfaced by validation and deliberately falls back to physical-row\n // semantics here, so a corrupt document can never make buyer adjacency more\n // permissive than the legacy model.\n const grouped = new Map<string, RowObject[]>();\n for (const object of objects) {\n if (object.type !== 'row' || !object.segmentedRow) continue;\n const list = grouped.get(object.segmentedRow.groupId) ?? [];\n list.push(object);\n grouped.set(object.segmentedRow.groupId, list);\n }\n for (const [groupId, members] of grouped) {\n const ordered = members.slice().sort((left, right) => (\n left.segmentedRow!.componentIndex - right.segmentedRow!.componentIndex\n ));\n const expectedCount = ordered[0]?.segmentedRow?.componentCount ?? 0;\n const first = ordered[0]?.segmentedRow;\n if (!first) continue;\n const valid = expectedCount >= 2\n && ordered.length === expectedCount\n && first?.boundaryBefore === 'start'\n && ordered.every((row, index) => (\n row.segmentedRow?.kind === 'segmented-row-v1'\n && row.segmentedRow.groupId === groupId\n && row.segmentedRow.componentCount === expectedCount\n && row.segmentedRow.componentIndex === index\n && (index === 0\n ? row.segmentedRow.boundaryBefore === 'start'\n : row.segmentedRow.boundaryBefore !== 'start')\n && row.segmentedRow.displayLabel === first.displayLabel\n ));\n if (!valid) continue;\n const totalSeats = ordered.reduce((sum, row) => sum + row.seatCount, 0);\n let adjacencyOffset = 0;\n let displayOffset = 0;\n for (const row of ordered) {\n if (row.segmentedRow!.boundaryBefore === 'break') adjacencyOffset += 1;\n segmented.set(row.id, {\n groupId,\n adjacencyOffset,\n displayOffset,\n displayLabel: first.displayLabel,\n totalSeats,\n canonical: ordered[0],\n viewFromSeatUrl: first.viewFromSeatUrl,\n });\n adjacencyOffset += row.seatCount;\n displayOffset += row.seatCount;\n }\n }\n\n for (const obj of objects) {\n let seats: ExpandedSeat[] = [];\n if (obj.type === 'row') seats = expandRow(obj);\n else if (obj.type === 'table') seats = expandTable(obj);\n else if (obj.type === 'booth') seats = expandBooth(obj);\n if (!seats.length) continue;\n if (obj.type === 'row') {\n const logical = segmented.get(obj.id);\n if (logical) {\n const overrides = new Map((obj.overrides ?? []).map((override) => [override.index, override]));\n for (const seat of seats) {\n const physicalIndex = Number(seat.id.slice(seat.id.lastIndexOf(':') + 1));\n if (!Number.isInteger(physicalIndex)) continue;\n const displayOrdinal = logical.displayOffset + physicalIndex;\n seat.logicalRowId = logical.groupId;\n seat.logicalSeatIndex = logical.adjacencyOffset + physicalIndex;\n // A seat-level display override remains the highest-precedence copy.\n if (!overrides.get(physicalIndex)?.displayLabel) {\n const numberingRow: RowObject = {\n ...logical.canonical,\n seatCount: logical.totalSeats,\n label: logical.displayLabel,\n displayLabel: logical.displayLabel,\n };\n seat.displayLabel = `${logical.displayLabel}-${seatLabelPart(numberingRow, displayOrdinal)}`;\n }\n seat.viewUrl ??= logical.viewFromSeatUrl;\n }\n }\n }\n const owner = owningSectionForObject(objects, obj);\n const inheritedView = owner?.viewFromSeatUrl;\n const zone = owner?.zone ? zones?.find((candidate) => candidate.id === owner.zone) : undefined;\n const resolvedFocal = zone?.focalPoint ?? fallbackFocal;\n for (const seat of seats) {\n if (inheritedView) seat.viewUrl ??= inheritedView;\n if (owner) seat.sectionId = owner.logicalSectionId ?? owner.id;\n if (owner?.zone) seat.zoneId = owner.zone;\n if (resolvedFocal) seat.focalPoint = { ...resolvedFocal };\n }\n out.push(...seats);\n }\n return out;\n}\n\n/** Expand every seat-bearing object across all floors (rows, tables, booths).\n * Multi-floor ownership is resolved one floor at a time: local coordinates may\n * overlap between floors and must never assign a seat to another floor's section. */\nexport function expandChart(doc: ChartDoc, options: ExpandChartOptions = {}): ExpandedSeat[] {\n if (doc.floors?.length) {\n const out: ExpandedSeat[] = [];\n for (const floor of doc.floors) {\n const floorFocal = floor.focalPoint ?? doc.focalPoint;\n const seats = expandFloorObjects(floor.objects, doc.zones, floorFocal);\n assignEyeHeights(floor.objects, floor.focalPoint ?? doc.focalPoint, floor.baseHeightM ?? 0, seats);\n out.push(...seats);\n }\n return out;\n }\n const out = expandFloorObjects(doc.objects, doc.zones, doc.focalPoint);\n assignEyeHeights(doc.objects, doc.focalPoint, options.floorBaseHeightM ?? 0, out);\n return out;\n}\n\n/**\n * Phase B2: annotate each expanded seat with a real-world eye height (metres above\n * the focal/stage datum) for the auto-360° generator. Resolved once at expand time\n * — never per render frame — so the 13k-seat render path pays no cost.\n *\n * `eyeHeightM = section front-edge height + row rise + seated eye height`, where\n * the ROW RISE is derived from the seat's DRAWN radial depth into its section\n * (chart units → metres × tan(rake)), NOT a hard-coded row pitch. Deriving rise\n * from drawn geometry (the same distances the panorama already uses horizontally)\n * is the binding fix for the 30–40% under-rise the sightline de-risk study flagged\n * (docs/3d-sightline-derisk-2026-07-21.md §7).\n *\n * A chart with no elevated/raked/height-authored section skips the spatial pass\n * entirely and every seat resolves to the flat seated-eye baseline — so legacy\n * charts stay pixel-identical and `expandChart`'s other callers pay nothing.\n */\nfunction assignEyeHeights(\n objects: ChartObject[],\n focal: Point | undefined,\n floorBaseHeightM: number,\n seats: ExpandedSeat[],\n): void {\n const sections = objects.filter((o): o is SectionObject => o.type === 'section');\n const hasGeometry = floorBaseHeightM > 0\n || sections.some((s) => s.height !== undefined || s.rake !== undefined || (s.elevation ?? 0) > 0);\n if (!sections.length || !hasGeometry || !focal) {\n for (const seat of seats) seat.eyeHeightM = floorBaseHeightM + SEATED_EYE_HEIGHT_M;\n return;\n }\n // Pass 1: owning section (first drawn section containing the seat) + the drawn\n // distance of the section's front edge (nearest member to the focal point).\n const owner = new Array<SectionObject | null>(seats.length);\n const geo = new Map<string, { height: number; rake: number }>();\n const frontDistU = new Map<string, number>();\n for (let i = 0; i < seats.length; i++) {\n const seat = seats[i];\n const sec = sections.find((s) => pointInPolygonWithHoles({ x: seat.x, y: seat.y }, s.outline, s.holes)) ?? null;\n owner[i] = sec;\n if (!sec) continue;\n if (!geo.has(sec.id)) geo.set(sec.id, sectionGeometry(sec, { floorBaseHeightM }));\n const seatFocal = seat.focalPoint ?? focal;\n const d = Math.hypot(seat.x - seatFocal.x, seat.y - seatFocal.y);\n const cur = frontDistU.get(sec.id);\n if (cur === undefined || d < cur) frontDistU.set(sec.id, d);\n }\n // Pass 2: front-edge height + drawn-depth rise + seated eye.\n for (let i = 0; i < seats.length; i++) {\n const seat = seats[i];\n const sec = owner[i];\n if (!sec) { seat.eyeHeightM = floorBaseHeightM + SEATED_EYE_HEIGHT_M; continue; }\n const g = geo.get(sec.id)!;\n let riseM = 0;\n if (g.rake > 0) {\n const seatFocal = seat.focalPoint ?? focal;\n const d = Math.hypot(seat.x - seatFocal.x, seat.y - seatFocal.y);\n const depthU = Math.max(0, d - (frontDistU.get(sec.id) ?? d));\n riseM = depthU * METRES_PER_CHART_UNIT * Math.tan((g.rake * Math.PI) / 180);\n }\n seat.eyeHeightM = g.height + riseM + SEATED_EYE_HEIGHT_M;\n }\n}\n\nconst PAD = 40;\n\n/** Axis-aligned bounds over every object plus the background image, with padding. */\nexport function chartBounds(doc: ChartDoc): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n const acc = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n\n for (const s of expandChart(doc)) acc(s.x, s.y);\n\n for (const obj of allObjects(doc)) {\n if (obj.type === 'gaArea') {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.type === 'section') {\n for (const p of obj.outline) acc(p.x, p.y);\n } else if (obj.type === 'decorImage') {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n } else if (obj.type === 'shape') {\n if (obj.points && obj.points.length) {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n }\n } else if (obj.type === 'table') {\n const off = TABLE_SEAT_OFFSET + SEAT_R;\n const ext =\n obj.shape === 'round'\n ? (obj.radius ?? 40) + off\n : Math.max((obj.width ?? 80) / 2, (obj.height ?? 50) / 2) + off; // rotation-agnostic over-approximation\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'booth') {\n const ext = Math.max(obj.width, obj.height) / 2;\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'text') {\n const w = obj.fontSize * obj.text.length * 0.6; // approximate glyph advance\n acc(obj.position.x, obj.position.y);\n acc(obj.position.x + w, obj.position.y + obj.fontSize);\n }\n }\n\n for (const image of [doc.referenceImage, doc.backgroundImage]) {\n if (!image) continue;\n const { center, width } = image;\n const bh = (width * 3) / 4; // assume 4:3 when the true aspect is unknown at bounds-time\n acc(center.x - width / 2, center.y - bh / 2);\n acc(center.x + width / 2, center.y + bh / 2);\n }\n\n // Empty document → a sane default box around the focal point.\n if (!isFinite(minX)) {\n const f = doc.focalPoint ?? { x: 0, y: 0 };\n return { x: f.x - 200, y: f.y - 200, width: 400, height: 400 };\n }\n\n return {\n x: minX - PAD,\n y: minY - PAD,\n width: maxX - minX + PAD * 2,\n height: maxY - minY + PAD * 2,\n };\n}\n","import type { ChartDoc, GAAreaObject, 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\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 the {@link ACCESS_GLYPH_PATH} coordinates live in. */\nexport const ACCESS_GLYPH_VIEWBOX = 24;\n/**\n * Accessibility pictogram drawn centred on accessible seats — the widely\n * recognised \"person\" access symbol, as a single filled vector path. A vector\n * path renders crisply at small sizes on every platform, unlike the ♿ colour\n * emoji whose canvas metrics/alignment are inconsistent cross-browser. The\n * coloured ring around the seat still encodes the specific accommodation type,\n * so buyer and designer show the same marker (shared via this constant).\n */\nexport const ACCESS_GLYPH_PATH =\n 'M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z';\n\n/**\n * Keep the public seat label as the inventory identity while rendering only\n * its terminal seat number inside the physical marker. Generated row seats use\n * `<row label>-<number>`; a custom label without that suffix remains unchanged.\n */\nexport function bookableMarkerLabel(publicLabel: string): string {\n return /-(\\d{1,5})$/.exec(publicLabel)?.[1] ?? publicLabel;\n}\n\nfunction luminance(value: string): number | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const channel = (offset: number) => {\n const encoded = Number.parseInt(match[1].slice(offset, offset + 2), 16) / 255;\n return encoded <= 0.04045 ? encoded / 12.92 : ((encoded + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4);\n}\n\n/** WCAG contrast for the actual opaque hex paints used by bookable labels. */\nexport function renderedTextContrast(ink: string, fill: string): number | null {\n const inkLuminance = luminance(ink);\n const fillLuminance = luminance(fill);\n if (inkLuminance == null || fillLuminance == null) return null;\n return (Math.max(inkLuminance, fillLuminance) + 0.05)\n / (Math.min(inkLuminance, fillLuminance) + 0.05);\n}\n\nfunction rgb(value: string): [number, number, number] | null {\n const match = /^#([0-9a-f]{6})$/i.exec(value.trim());\n if (!match) return null;\n const packed = Number.parseInt(match[1], 16);\n return [(packed >> 16) & 255, (packed >> 8) & 255, packed & 255];\n}\n\n/**\n * Resolve the opaque pixel under text painted over a translucent category\n * shape. Quality evidence must compare against this composite—not the raw\n * category colour or the canvas alone.\n */\nexport function compositeHexOver(\n foreground: string,\n background: string,\n opacity: number,\n): string {\n const front = rgb(foreground);\n const back = rgb(background);\n if (!front || !back) return background;\n const alpha = Math.max(0, Math.min(1, opacity));\n const channels = front.map((value, index) => Math.round(value * alpha + back[index] * (1 - alpha)));\n return `#${channels.map((value) => value.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Bookable fills can vary per category and per transient state, while a chart\n * exposes only one preferred label token. Preserve that preference whenever it\n * passes, then deterministically choose the strongest normal-text candidate.\n */\nexport function stateAwareBookableLabelInk(fill: string, preferred: string): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= SMALL_TEXT_CONTRAST) return preferred;\n const darkContrast = renderedTextContrast(DARK_BOOKABLE_LABEL_INK, fill) ?? 0;\n const lightContrast = renderedTextContrast(LIGHT_BOOKABLE_LABEL_INK, fill) ?? 0;\n if (darkContrast === 0 && lightContrast === 0) return preferred;\n return darkContrast >= lightContrast ? DARK_BOOKABLE_LABEL_INK : LIGHT_BOOKABLE_LABEL_INK;\n}\n\nconst OPAQUE_HEX = /^#[0-9a-f]{6}$/i;\n\n/** Is a solid hex fill light enough to read as a light surface? Feedback helpers\n * use this to pick the neutral section shell a label sits on. */\nexport function isLightFill(fill: string): boolean {\n const value = luminance(fill);\n return value != null && value > 0.5;\n}\n\n/**\n * Neutral section shell fills the renderer paints when a section has no custom\n * colour, mirrored here so contrast feedback can evaluate uncoloured sections.\n */\nexport const LIGHT_NEUTRAL_SECTION_FILL = '#e5e7eb';\nexport const DARK_NEUTRAL_SECTION_FILL = '#273142';\nexport function neutralSectionFill(canvasBackground: string): string {\n return isLightFill(canvasBackground) ? LIGHT_NEUTRAL_SECTION_FILL : DARK_NEUTRAL_SECTION_FILL;\n}\n\nexport interface LabelInkContrastSummary {\n /** Backgrounds that could be evaluated (valid preferred + valid fill hex). */\n total: number;\n /** Backgrounds where the preferred ink is auto-swapped for legibility. */\n overridden: number;\n /** `applies` = preferred survives everywhere; `overridden` = swapped\n * everywhere; `mixed` = some of each; `none` = nothing evaluable. */\n status: 'applies' | 'overridden' | 'mixed' | 'none';\n /** Fallback ink chosen where the preferred was overridden (black/white), or\n * null when nothing was overridden — names the swap in user-facing copy. */\n overrideInk: string | null;\n}\n\n/**\n * Feedback-only companion to {@link stateAwareBookableLabelInk}: does a preferred\n * label ink survive across a set of backgrounds, or does the shared auto-contrast\n * rule silently swap it for black/white on some of them? Reuses the exact same\n * per-fill decision so a report can never disagree with what the renderer paints.\n */\nexport function summarizeLabelInkContrast(\n preferred: string,\n backgrounds: Iterable<string>,\n): LabelInkContrastSummary {\n const preferredValid = OPAQUE_HEX.test(preferred.trim());\n const preferredHex = preferred.trim().toLowerCase();\n let total = 0;\n let overridden = 0;\n let overrideInk: string | null = null;\n for (const fill of backgrounds) {\n if (!preferredValid || !OPAQUE_HEX.test(fill.trim())) continue;\n total += 1;\n const ink = stateAwareBookableLabelInk(fill, preferred);\n if (ink.toLowerCase() !== preferredHex) {\n overridden += 1;\n overrideInk = ink;\n }\n }\n const status = total === 0 ? 'none'\n : overridden === 0 ? 'applies'\n : overridden === total ? 'overridden'\n : 'mixed';\n return { total, overridden, status, overrideInk };\n}\n","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 { 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_PATH,\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 bookableMarkerLabel,\n compositeHexOver,\n isBookableLabelLegibleAtScale,\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/**\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;\nconst SECTION_STROKE_PX = 2;\nconst LIGHT_OVERVIEW_SECTION_FILL = '#e5e7eb';\nconst LIGHT_OVERVIEW_SECTION_STROKE = '#c7cbd1';\nconst LIGHT_OVERVIEW_SECTION_INK = '#595f69';\nconst LIGHT_OVERVIEW_FOCAL_FILL = '#d1d5db';\nconst LIGHT_OVERVIEW_FOCAL_STROKE = '#b8bdc4';\nconst DARK_OVERVIEW_SECTION_FILL = '#273142';\nconst DARK_OVERVIEW_SECTION_STROKE = '#526078';\nconst DARK_OVERVIEW_SECTION_INK = '#f1f5f9';\nconst DARK_OVERVIEW_FOCAL_FILL = '#374151';\nconst DARK_OVERVIEW_FOCAL_STROKE = '#64748b';\n/** Screen-space target sizes (px) for scale-compensated section/zone labels. */\nconst SECTION_LABEL_PX = 20;\nconst MIN_SECTION_LABEL_PX = 12;\nconst ZONE_LABEL_PX = 18;\nconst ZONE_SUB_PX = 12;\nconst HIERARCHY_PILL_BACKGROUND = '#111827';\n\nconst HELD_FILL = '#6b7280';\nconst TAKEN_FILL = '#374151';\nconst NFS_STROKE = '#4b5563';\n/** Phase 2 event-level `closed` section: a flat desaturated slate block (label\n * kept), distinct from the per-seat availability-grey. Seats inside read grey\n * at 40% and are not pickable (per chart-design-standards §3). */\nconst CLOSED_SEAT_FILL = '#4b5563';\nconst CLOSED_SEAT_OPACITY = 0.4;\n/** AXS section-focus: non-focused sections dim to this opacity. */\nconst FOCUS_DIM_OPACITY = 0.16;\n/** Light/neutral backdrop panel drawn behind the focused section's seats. */\nconst FOCUS_BACKDROP_FILL = 'rgba(244,246,248,0.06)';\n/** Okabe-Ito colorblind-safe hues (black dropped — unreadable on dark charts).\n * Categories 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\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/** Centre-first interior anchors used when a hole/concavity occupies the shell centre. */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\n const centre = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n const points: Point[] = [preferred];\n for (let row = 1; row < 12; row += 1) {\n for (let column = 1; column < 12; column += 1) {\n const point = {\n x: bounds.x + bounds.width * column / 12,\n y: bounds.y + bounds.height * row / 12,\n };\n if (pointInPolygonWithHoles(point, outer, holes)) points.push(point);\n }\n }\n return points\n .sort((left, right) => Math.hypot(left.x - centre.x, left.y - centre.y)\n - Math.hypot(right.x - centre.x, right.y - centre.y))\n .filter((point, index, all) => index === all.findIndex((other) => (\n Math.abs(other.x - point.x) < 1e-6 && Math.abs(other.y - point.y) < 1e-6\n )));\n}\n\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 centre-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n zone?: string;\n /** Seats whose centre falls inside the outline (first-match, doc order). */\n memberIds: string[];\n total: number;\n free: number;\n /** Category-mix (or explicit override) fill BEFORE the availability tint. */\n baseFill: string;\n outlineTint: string;\n /** Faint outline drawn under seats — the existing near-zoom look, untouched. */\n outlinePoly: Shape;\n /** Solid block fill that melts in at the block rung. */\n blockPoly: Shape;\n /** Section name (always drawn; brightens at the block rung, hides at zone rung). */\n nameLabel: Text;\n /** Availability retained for focused/detail UI, never painted on the overview shell. */\n subLabel: Text;\n /** Preferred name ink (labelStyle.color or the overview default) fed through\n * auto-contrast each frame so an authored colour survives the block melt. */\n preferredInk: string;\n /** labelStyle.size relative to the default (1 = default), scaling the fitted\n * screen-px band so a larger authored label reads larger in the overview. */\n labelScale: number;\n /** Responsive fit decisions for the current stage scale and local polygon span. */\n nameLabelFits: boolean;\n subLabelFits: boolean;\n /** Tier height (0 = floor). Lifts the section + members in iso (\"3D\") view. */\n elevation: number;\n /**\n * 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\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: Array<{ text: string; x: number; y: number; rotation: number; fontSize: number; ink: string; opacity: number }> = [];\n /** Category order from the doc — the stable index into the CB palette. */\n private catOrder: string[] = [];\n\n private selection = new Set<string>();\n /** Whole-seat/block selection markers: outline + non-colour check cue. */\n private selectionMarkers = new Map<string, Group>();\n /** Held by this picker instance, not by another buyer. */\n private ownedHold = new Set<string>();\n /** One selected seat being inspected before it is committed to the cart. */\n private selectionFocusId: string | null = null;\n private hoverRing: Circle;\n /** 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\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.currency = options.currency;\n\n Konva.pixelRatio = this.dpr;\n\n this.stage = new Stage({\n container,\n width: container.clientWidth || 1,\n height: container.clientHeight || 1,\n draggable: false, // pan/pinch are ours, via pointer events\n });\n\n container.style.touchAction = 'none';\n container.addEventListener('pointerdown', this.onPointerDown, { passive: false });\n container.addEventListener('pointermove', this.onPointerMove, { passive: false });\n container.addEventListener('pointerup', this.onPointerEnd, { passive: false });\n container.addEventListener('pointercancel', this.onPointerEnd, { passive: false });\n\n // Keyboard accessibility: the canvas is focusable and navigable seat-by-seat.\n if (container.tabIndex < 0) container.tabIndex = 0;\n container.setAttribute('role', 'application');\n if (!container.getAttribute('aria-label')) {\n container.setAttribute('aria-label', t('map.aria'));\n }\n container.addEventListener('keydown', this.onKeyDown);\n\n this.bgLayer = new Layer({ listening: true });\n this.seatLayer = new Layer({ listening: true });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n // 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\n this.wireInteraction();\n this.startFpsLoop();\n\n if (import.meta.env.DEV) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObs = new ResizeObserver(() => this.handleResize());\n this.resizeObs.observe(container);\n }\n }\n\n // ---- ISeatmapRenderer -----------------------------------------------------\n\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void {\n // Multi-floor: render the active floor (2D) or all floors stacked (3D). `view`\n // scopes the chart accordingly — single-floor charts pass through (=== doc).\n // A fresh chart (new ref) resets to 2D; a re-render (same ref) preserves the mode.\n if (doc !== this.chartDoc) this.stacked = false;\n this.chartDoc = doc;\n this.activeFloorId = opts?.floorId ?? floorsOf(doc)[0].id;\n // Object id → floor id, for resolving which deck a tap hit in the 3D stack\n // (stackFloors keeps object ids, so the map holds across the flatten).\n this.objectFloor.clear();\n if (doc.floors && doc.floors.length > 1) {\n for (const f of doc.floors) for (const o of f.objects) this.objectFloor.set(o.id, f.id);\n }\n const view = this.floorView(doc);\n this.focusedId = null;\n this.focusRing.visible(false);\n this.bgLayer.destroyChildren();\n this.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(true);\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: true });\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 = ga.sectionId != null && this.effScale() < CACHE_THRESHOLD;\n ga.polygon.opacity(overviewHidden\n ? 0\n : this.gaCategoryDimmed(ga.categoryKey)\n ? GA_FILL_OPACITY * 0.08\n : GA_FILL_OPACITY);\n // A legend hover is only visual; a price-filter exclusion is not sellable\n // from the map until the filter is cleared.\n ga.polygon.listening(!overviewHidden && !filteredOut);\n }\n }\n\n /** Frame the currently available inventory that survived a buyer price\n * filter. Clearing the filter glides back to the full venue. */\n focusCategories(keys: string[] | null): void {\n if (!keys?.length) {\n this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });\n return;\n }\n const wanted = new Set(keys);\n const matching = this.seats.filter((seat) => {\n if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;\n const status = this.statusById.get(seat.id) ?? 'free';\n return status === 'free' || this.ownedHold.has(seat.id);\n });\n if (!matching.length) return;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const seat of matching) {\n 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 if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.isoRaf) cancelAnimationFrame(this.isoRaf);\n if (this.glideRaf) cancelAnimationFrame(this.glideRaf);\n if (this.viewChangeRaf) cancelAnimationFrame(this.viewChangeRaf);\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.resizeObs?.disconnect();\n this.container.removeEventListener('pointerdown', this.onPointerDown);\n this.container.removeEventListener('pointermove', this.onPointerMove);\n this.container.removeEventListener('pointerup', this.onPointerEnd);\n this.container.removeEventListener('pointercancel', this.onPointerEnd);\n this.container.removeEventListener('keydown', this.onKeyDown);\n this.stage.destroy();\n }\n\n // ---- rendering ------------------------------------------------------------\n\n /** Theme font stack for all rendered text (falls back to Inter). */\n private labelFont(): string {\n return this.theme.fontFamily || 'Inter, sans-serif';\n }\n\n /**\n * Where a seat's nodes live: an elevated section's lift group (so the whole\n * tier shifts with one offset in iso view) or the seat layer directly.\n */\n private seatContainer(id: string): Group | Layer {\n return this.seatSection.get(id)?.liftGroupSeat ?? this.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.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')) {\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 data: ACCESS_GLYPH_PATH,\n offsetX: ACCESS_GLYPH_VIEWBOX / 2,\n offsetY: ACCESS_GLYPH_VIEWBOX / 2,\n scaleX: k,\n scaleY: k,\n fill: stateAwareBookableLabelInk(seatFill, '#ffffff'),\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));\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(stateAwareBookableLabelInk(typeof fill === 'string' ? fill : '', '#ffffff'));\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 /** Organizer floor-plan photo, dimmed, at the very bottom of the bg layer. */\n private renderBackgroundImage(bg: NonNullable<ChartDoc['backgroundImage']>): void {\n if (!bg.url || bg.visible === false) return;\n const img = new window.Image();\n img.onload = () => {\n const natW = img.naturalWidth || 4;\n const natH = img.naturalHeight || 3;\n const rawCrop = bg.crop ?? { x: 0, y: 0, width: 1, height: 1 };\n const cropX = Math.max(0, Math.min(0.99, rawCrop.x));\n const cropY = Math.max(0, Math.min(0.99, rawCrop.y));\n const crop = {\n x: cropX,\n y: cropY,\n width: Math.max(0.01, Math.min(1 - cropX, rawCrop.width)),\n height: Math.max(0.01, Math.min(1 - cropY, rawCrop.height)),\n };\n const w = bg.width;\n const h = w * ((natH * crop.height) / (natW * crop.width));\n const node = new KImage({\n image: img,\n x: bg.center.x,\n y: bg.center.y,\n offsetX: w / 2,\n offsetY: h / 2,\n width: w,\n height: h,\n rotation: bg.rotation ?? 0,\n crop: {\n x: crop.x * natW,\n y: crop.y * natH,\n width: crop.width * natW,\n height: crop.height * natH,\n },\n opacity: bg.opacity,\n listening: false,\n });\n this.bgLayer.add(node);\n node.moveToBottom();\n this.bgLayer.batchDraw();\n };\n img.src = bg.url;\n }\n\n /**\n * A decor graphic (rink / court / stage art). The KImage node is added to the\n * bgLayer synchronously so it keeps its z-slot beneath the sections drawn right\n * after; the bitmap is decoded async and pasted in on load. A single node = a\n * single drawImage per frame, and it rides the same layer cache — effectively\n * zero per-frame cost. Never listens, so it can't intercept a seat click.\n */\n private renderDecorImage(obj: Extract<ChartDoc['objects'][number], { type: 'decorImage' }>): void {\n // Pass the (not-yet-loaded) Image element as the node's image: Konva draws\n // nothing until it decodes, then onload triggers a repaint. Keeps the node's\n // z-slot fixed beneath the sections drawn immediately after.\n const img = new window.Image();\n const node = new KImage({\n image: img,\n x: obj.x + obj.width / 2,\n y: obj.y + obj.height / 2,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation ?? 0,\n opacity: clamp(obj.opacity ?? 1, 0, 1),\n listening: false,\n perfectDrawEnabled: false,\n });\n // 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 img.onload = () => {\n const layer = node.getLayer();\n if (!layer) return; // chart swapped out before the image loaded\n layer.batchDraw();\n };\n img.src = obj.href;\n }\n\n private renderTable(obj: Extract<ChartDoc['objects'][number], { type: 'table' }>): void {\n if (obj.shape === 'round') {\n this.bgLayer.add(\n new Circle({\n x: obj.center.x,\n y: obj.center.y,\n radius: obj.radius ?? 40,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n listening: false,\n }),\n );\n } else {\n const w = obj.width ?? 80;\n const h = obj.height ?? 50;\n this.bgLayer.add(\n new Rect({\n x: obj.center.x,\n y: obj.center.y,\n width: w,\n height: h,\n offsetX: w / 2,\n offsetY: h / 2,\n rotation: obj.rotation,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n cornerRadius: 4,\n listening: false,\n }),\n );\n }\n const label = this.addCentredLabel(this.bgLayer, obj.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.75,\n fill: rgba(outlineTint, 0.08),\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(outlinePoly);\n\n // Neutral overview shell — category paint is intentionally deferred until\n // focus/seat detail so the venue hierarchy remains legible at first glance.\n const blockPoly = polygonWithHolesShape(obj.outline, obj.holes, {\n fill: palette.sectionFill,\n stroke: palette.sectionStroke,\n strokeWidth: SECTION_STROKE_PX,\n opacity: 0,\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(blockPoly);\n\n // Per-section label overrides (size/color) layered on the overview defaults.\n // color becomes the preferred ink the block-melt loop auto-contrasts each\n // frame; size scales the fitted screen-px band (default section size = 18).\n const labelStyle = obj.labelPresentation?.labelStyle;\n const preferredInk = labelStyle?.color ?? palette.sectionInk;\n const labelScale = (labelStyle?.size ?? 18) / 18;\n const nameLabel = new Text({\n x: obj.labelPresentation?.position?.x ?? centroid.x,\n y: obj.labelPresentation?.position?.y ?? centroid.y,\n text: obj.displayLabel ?? obj.label,\n rotation: obj.labelPresentation?.rotation ?? 0,\n visible: obj.labelPresentation?.visible !== false,\n fontSize: 22 * labelScale,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: stateAwareBookableLabelInk(palette.sectionFill, preferredInk),\n listening: false,\n perfectDrawEnabled: false,\n });\n nameLabel.offsetX(nameLabel.width() / 2);\n nameLabel.offsetY(nameLabel.height() / 2);\n bgTarget.add(nameLabel);\n\n const subLabel = new Text({\n x: centroid.x,\n y: centroid.y,\n text: t('map.seatsLeft', { count: free }),\n fontSize: 12,\n fontStyle: '700',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: palette.sectionInk,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n subLabel.offsetX(subLabel.width() / 2);\n bgTarget.add(subLabel);\n\n const sec: SectionRender = {\n id: obj.id,\n logicalId: obj.logicalSectionId ?? obj.id,\n label: obj.displayLabel ?? obj.label,\n outline: obj.outline,\n ...(obj.outlinePath ? { outlinePath: obj.outlinePath } : {}),\n holes: obj.holes ?? [],\n centroid,\n labelAnchors: polygonLabelCandidates(obj.outline, obj.holes ?? [], centroid),\n zone: obj.zone,\n memberIds,\n total: memberIds.length,\n free,\n baseFill,\n outlineTint,\n outlinePoly,\n blockPoly,\n nameLabel,\n subLabel,\n preferredInk,\n labelScale,\n nameLabelFits: true,\n subLabelFits: true,\n elevation,\n 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. Section names\n * are already proven inside disjoint shells, so they must not cull each other.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; box: { x: number; y: number; w: number; h: number } }\n const cands: Cand[] = [];\n const boxOf = (t: Text): { x: number; y: number; w: number; h: number } => {\n const p = this.worldToScreen({ x: t.x(), y: t.y() });\n const rotated = pointsBounds(rotatedRectPoints(\n { x: 0, y: 0 },\n t.width() * sx,\n t.height() * sx,\n t.rotation(),\n ));\n const w = rotated.width;\n const h = rotated.height;\n return { x: p.x - w / 2, y: p.y - h / 2, w, h };\n };\n for (const zone of this.zones) {\n if (zone.label.opacity() > 0.05) {\n const p = this.worldToScreen(zone.anchor);\n const w = zone.back.width() * sx;\n const h = zone.back.height() * sx;\n cands.push({ node: zone.label, tier: 0, section: false, box: { x: p.x - w / 2, y: p.y - h / 2, w, h } });\n }\n }\n for (const sec of this.sections) {\n if (sec.nameLabel.opacity() > 0.05) cands.push({ node: sec.nameLabel, tier: 1, section: true, box: boxOf(sec.nameLabel) });\n }\n if (cands.length < 2) return;\n cands.sort((a, b) => a.tier - b.tier || a.box.y - b.box.y || a.box.x - b.box.x);\n const kept: Cand['box'][] = [];\n const collides = (b: Cand['box']): boolean =>\n kept.some((k) =>\n b.x < k.x + k.w + GAP && k.x < b.x + b.w + GAP &&\n b.y < k.y + k.h + GAP && k.y < b.y + b.h + GAP,\n );\n for (const c of cands) {\n if (collides(c.box)) {\n c.node.opacity(0);\n } else if (!c.section) {\n // Section shells do not collide by construction; only zone pills form\n // blockers for later transitional labels.\n kept.push(c.box);\n }\n }\n }\n\n /** Set a centred label's world fontSize (for a target screen px) and re-anchor it. */\n private sizeLabel(t: Text, fontSize: number, y: number): void {\n t.fontSize(Math.max(1, fontSize));\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.y(y);\n }\n\n /** Fit one centred section name, rotating narrow shells like the target chart. */\n private fitSectionRungLabels(sec: SectionRender, sx: number): void {\n const paddingPx = 8;\n sec.subLabelFits = false;\n // Scale the fitted screen-px band by the section's authored label size so a\n // larger override reads larger; the step still shrinks to fit the polygon.\n const maxPx = SECTION_LABEL_PX * sec.labelScale;\n const minPx = MIN_SECTION_LABEL_PX * sec.labelScale;\n for (let fontPx = maxPx; fontPx >= minPx; fontPx -= 1) {\n for (const rotation of [0, -90]) {\n sec.nameLabel.rotation(rotation);\n this.sizeLabel(sec.nameLabel, fontPx / sx, sec.nameLabel.y());\n for (const anchor of sec.labelAnchors) {\n sec.nameLabel.position(anchor);\n const paddingWorld = paddingPx / sx;\n if (rotatedRectFitsPolygon(\n anchor,\n sec.nameLabel.width() + paddingWorld,\n sec.nameLabel.height() + paddingWorld,\n rotation,\n sec.outline,\n sec.holes,\n )) {\n sec.nameLabelFits = true;\n return;\n }\n }\n }\n }\n sec.nameLabel.position(sec.centroid);\n sec.nameLabel.rotation(0);\n sec.nameLabelFits = false;\n }\n\n /** Size one screen-constant zone name/price pill around its shared anchor. */\n private sizeZonePill(zone: ZoneRender, sx: number): void {\n const padX = 10 / sx;\n const padY = 6 / sx;\n const gap = zone.sub ? 3 / sx : 0;\n this.sizeLabel(zone.label, ZONE_LABEL_PX / sx, zone.anchor.y);\n if (zone.sub) this.sizeLabel(zone.sub, ZONE_SUB_PX / sx, zone.anchor.y);\n const width = Math.max(zone.label.width(), zone.sub?.width() ?? 0) + padX * 2;\n const height = zone.label.height() + (zone.sub ? gap + zone.sub.height() : 0) + padY * 2;\n zone.label.y(zone.anchor.y - (zone.sub ? (gap + zone.sub.height()) / 2 : 0));\n if (zone.sub) zone.sub.y(zone.anchor.y + (zone.label.height() + gap) / 2);\n zone.back.position(zone.anchor);\n zone.back.size({ width, height });\n zone.back.offset({ x: width / 2, y: height / 2 });\n zone.back.cornerRadius(7 / sx);\n zone.back.strokeWidth(1 / sx);\n }\n\n /**\n * Map a container-relative screen point back to world coords. Inverts the\n * stage (scale/pos) and, in iso view, the iso affine — so screen-space taps\n * test against the flat world outlines/geometry. Identity-equivalent at isoT=0.\n */\n private screenToWorld(clientPoint: { x: number; y: number }): { x: number; y: number } {\n const s = this.stage.scaleX();\n const iso = { x: (clientPoint.x - this.stage.x()) / s, y: (clientPoint.y - this.stage.y()) / s };\n 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 marker.add(new Circle({ ...common, radius: this.seatR + (candidate ? 4.5 : 2.5), strokeWidth: candidate ? 3.5 : 2.5 }));\n if (candidate) {\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 8,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n marker.add(new Line({\n points: [-this.seatR * 0.52, 0, -this.seatR * 0.12, this.seatR * 0.4, this.seatR * 0.6, -this.seatR * 0.46],\n stroke: '#ffffff',\n strokeWidth: Math.max(2.6, this.seatR * 0.34),\n lineCap: 'round',\n lineJoin: 'round',\n shadowColor: '#0b1220',\n shadowBlur: 1.5,\n shadowOpacity: 0.55,\n listening: false,\n }));\n }\n }\n\n this.selectionMarkers.set(id, marker);\n this.overlayLayer.add(marker);\n }\n\n // ---- interaction ----------------------------------------------------------\n\n /**\n * The stage scale `focusRegion(id)` would settle at — i.e. the zoom that\n * frames this section in the current viewport. Used to decide whether\n * redirecting a seat tap to section-focus would actually zoom in FURTHER, or\n * whether the section already fills the viewport (small container) so the tap\n * must fall through and pick.\n */\n private sectionBounds(id: string): { x: number; y: number; width: number; height: number } | null {\n const bounds = this.sections\n .filter((section) => section.id === id || section.logicalId === id)\n .map((section) => {\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 ink: typeof ink === 'string' ? ink : (this.theme.seatLabelColor ?? DEF_SEAT_LABEL),\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.viewChangeRaf) return;\n this.viewChangeRaf = requestAnimationFrame(() => {\n this.viewChangeRaf = 0;\n this.opts.onViewChange?.();\n });\n }\n\n private updateLOD(): void {\n // Effective scale folds in the iso y-squash (smaller ⇒ seats read smaller),\n // so LOD/melt thresholds trip correctly in 3D view. Equals the raw stage\n // scale at isoT=0 → flat behaviour is unchanged.\n const scale = this.effScale();\n const focalScale = Math.max(scale, 0.0001);\n for (const [label, targetPx] of this.primaryFocalLabels) {\n this.sizeLabel(label, targetPx / focalScale, label.y());\n }\n if (this.hasSections) this.applySectionLod(scale);\n else if (this.primaryFocalLabels.size) this.bgLayer.batchDraw();\n this.paintGAStateForView();\n // 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 = 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 if (this.cached) this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the\n * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */\n private rebuildSeatCache(): void {\n // 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 * SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the\n * ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore\n * Konva's batchDraw) on hidden/backgrounded/occluded tabs, so seat-status\n * deltas applied via setStatus() mutate the scene graph but never reach the\n * canvas until the tab is foregrounded. This flushes the cache-debounce and\n * paints every layer setStatus() can touch, immediately.\n *\n * Additive: the foreground path never calls this, so foreground behaviour is\n * byte-identical.\n */\n forceDraw(): void {\n // Flush any pending cache-debounce (setStatus coalesces bursts behind a\n // 150ms setTimeout) so a returning tab isn't left showing a stale bitmap.\n if (this.recacheTimer) {\n clearTimeout(this.recacheTimer);\n this.recacheTimer = null;\n // Fold coalesced deltas into a bitmap only if the CURRENT camera is still\n // on the cached overview rung. A status update can queue this timer and a\n // subsequent detail zoom can uncache the layer before forceDraw(); blindly\n // rebuilding here would disable pointer listening on live detail seats.\n if (this.effScale() < CACHE_THRESHOLD) {\n this.rebuildSeatCache();\n } else if (this.cached) {\n this.seatLayer.clearCache();\n this.seatLayer.listening(true);\n this.cached = false;\n }\n }\n // Synchronous paint of every layer setStatus() may repaint. Layer.draw()\n // renders on the calling thread, unlike batchDraw()'s rAF schedule.\n this.bgLayer.draw();\n this.seatLayer.draw();\n this.overlayLayer.draw();\n }\n\n private updateFreeTextVisibility(): void {\n const effectiveScale = this.effScale();\n for (const { objectId, node, categoryKey, kind } of this.freeTextById.values()) {\n const gaDimmed = categoryKey != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaCategoryDimmed(categoryKey);\n const gaOverviewHidden = objectId != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaById.get(objectId)?.sectionId != null\n && effectiveScale < CACHE_THRESHOLD;\n node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));\n }\n // 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 );\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) => this.rowLabelPlan.push({ text, x, y, rotation, fontSize, ink, opacity });\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 radians = (obj.rotation * Math.PI) / 180;\n const along = { x: Math.cos(radians), y: Math.sin(radians) };\n const gap = this.seatR + 12;\n const preset = presentation?.positionPreset ?? 'start';\n if (preset === 'start' || preset === 'both') push(first.x - along.x * gap, first.y - along.y * gap);\n if (preset === 'end' || preset === 'both') push(last.x + along.x * gap, last.y + along.y * gap);\n }\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.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 // Wheelchair places show the ♿ glyph in place of the seat number. Other\n // accommodations retain their seat number plus their 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 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 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: '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 // ---- 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\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/** 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 (the 150KB-gzipped complete CDN budget is a\n * product contract).\n *\n * Scope: the buyer surface (picker, public event\n * page, SDK) ships fully translated in en/es/de/fr; dashboard pages route\n * their strings through t() as they are rebuilt but ship English this round.\n *\n * Keys are flat dot-namespaced strings (\"picker.holdSeats\"). Interpolation\n * uses {name} placeholders. Missing keys fall back to English, then to the\n * key itself — a page never crashes over a translation.\n */\n\nimport { setMoneyLocale } from '../lib/money';\nimport { en } from './locales/en';\n\nexport type Locale = 'en' | 'es' | 'de' | 'fr';\nexport const SUPPORTED_LOCALES: Locale[] = ['en', 'es', 'de', 'fr'];\n\nexport type Dict = Record<string, string>;\n\nconst bundles: Partial<Record<Locale, Dict>> = { en };\n\n/** Extra strings layered over the active bundle (SDK white-label overrides). */\nlet overrides: Dict = {};\n\nlet active: Locale = 'en';\n\n/** explicit setting → stored preference → browser language → en */\nexport function resolveLocale(explicit?: string | null, stored?: string | null): Locale {\n for (const candidate of [explicit, stored, typeof navigator !== 'undefined' ? navigator.language : null]) {\n if (!candidate) continue;\n const base = candidate.toLowerCase().split('-')[0] as Locale;\n if (SUPPORTED_LOCALES.includes(base)) return base;\n }\n return 'en';\n}\n\nexport function getLocale(): Locale {\n return active;\n}\n\n/**\n * Set the active locale. Locale bundles other than English are registered by\n * the surface that needs them (the picker imports its own es/de/fr bundles;\n * the dashboard stays English until its translations ship).\n */\nexport function setLocale(locale: Locale, bundle?: Dict): void {\n if (bundle) bundles[locale] = { ...bundles[locale], ...bundle };\n active = bundles[locale] ? locale : 'en';\n setMoneyLocale(active);\n if (typeof document !== 'undefined') document.documentElement.lang = active;\n}\n\nexport function setStringOverrides(next: Dict): void {\n overrides = next;\n}\n\nconst PLACEHOLDER = /\\{(\\w+)\\}/g;\n\nexport function t(key: string, vars?: Record<string, string | number>): string {\n const raw = overrides[key] ?? bundles[active]?.[key] ?? en[key] ?? key;\n if (!vars) return raw;\n return raw.replace(PLACEHOLDER, (_, name: string) => String(vars[name] ?? `{${name}}`));\n}\n\n/** \"1 seat\" / \"3 seats\" without hand-rolled concatenation. */\nexport function tCount(key: string, count: number, vars?: Record<string, string | number>): string {\n const rule = new Intl.PluralRules(active).select(count);\n const exact = overrides[`${key}.${rule}`] ?? bundles[active]?.[`${key}.${rule}`] ?? en[`${key}.${rule}`];\n const raw = exact ?? overrides[`${key}.other`] ?? bundles[active]?.[`${key}.other`] ?? en[`${key}.other`] ?? key;\n return raw.replace(PLACEHOLDER, (_, name: string) => String({ count, ...vars }[name] ?? `{${name}}`));\n}\n\nexport function formatDate(value: number | Date, opts?: Intl.DateTimeFormatOptions): string {\n return new Intl.DateTimeFormat(active, opts ?? { dateStyle: 'medium', timeStyle: 'short' }).format(value);\n}\n","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\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/** 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): Promise<BestAvailableResponse>;\n release(key: string, labels: string[], holdId: string): Promise<unknown>;\n /** Optional capability-style lookup used to restore an active browser hold. */\n resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;\n /** Optional — the SDK omits booking (it hands the holdId to the host page). */\n book?(key: string, labels: string[], holdId: string, bookingRef: string): Promise<unknown>;\n /** Optional (P4) — push an active hold's expiry out (\"need more time?\"). */\n extend?(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends?: number }>;\n socketUrl(key: string): string;\n}\n\nexport interface PickerCallbacks extends RendererCallbacks {\n /** Selection changed (manual clicks or a server best-available pick). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /** A 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 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 /** 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 /** Atomically replace an active variable-table hold with a new guest count. */\n async replaceTableQuantity(label: string, quantity: 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, undefined, 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 async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: { preferPremium?: boolean; zoneId?: string } = {},\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);\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);\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 */\n async book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null> {\n const r = this.renderer;\n if (!r) return null;\n if (!this.api.book) throw new Error('picker: transport has no book() — hold-only mode');\n const labels = labelsArg ?? 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 undefined,\n replaceHoldId,\n );\n holdId = h.holdId;\n this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });\n }\n await this.api.book(this.key, labels, holdId, bookingRef);\n } catch (err) {\n const { status, conflicts, reason } = errInfo(err);\n this.clearHold();\n if (status === 409 && reason === 'event_closed') {\n this.opts.onSalesClosed?.();\n } else if (status === 409 && conflicts?.length) {\n // Paint the taken seats, deselect them, release the still-free remainder.\n const takenLabels = new Set(conflicts.map((c) => c.label));\n const takenIds = 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.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 this.opts.onStatusChange?.();\n this.clearBookedHoldIfSettled();\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 private connect(): void {\n if (this.closed) return;\n // A transport may be fully local (demo/mock) — an empty socketUrl means\n // \"no live feed\"; skip the connection instead of retrying forever.\n const url = this.api.socketUrl(this.key);\n if (!url) return;\n let ws: WebSocket;\n try {\n ws = new WebSocket(url);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n this.attempt = 0;\n void this.resnapshot();\n };\n ws.onmessage = (e) => {\n let msg: unknown;\n try {\n msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n } catch {\n return;\n }\n const r = this.renderer;\n if (!r || !msg || typeof msg !== 'object') return;\n const m = msg as { type?: string; hidden?: string[]; closed?: string[]; seats?: Record<string, string>; changes?: { label: string; status: string }[] };\n // Reconcile hidden sections whenever they arrive (dedicated 'hidden' message\n // OR a snapshot that carries them). Only rebuilds the chart when it changed.\n if (Array.isArray(m.hidden) && this.syncHidden(m.hidden)) {\n void this.resnapshot(); // repaint statuses onto the rebuilt chart\n this.opts.onStatusChange?.();\n }\n // Reconcile closed sections (Phase 2). Cheap grey restyle, no chart rebuild —\n // so flipping a section open/closed mid-sale repaints for connected buyers.\n if (Array.isArray(m.closed) && this.syncClosed(m.closed)) {\n this.opts.onStatusChange?.();\n }\n if (m.type === 'hidden') return; // dedicated hidden message carries no seats\n if (m.seats && typeof m.seats === 'object') {\n this.applySeatsMap(m.seats);\n } else if (Array.isArray(m.changes)) {\n for (const ch of m.changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const 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 ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.scheduleReconnect();\n };\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives reconnect */\n }\n };\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n}\n","/**\n * 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 a dark hall with the stage\n * placed at the correct bearing and angular size for THIS seat — closer seats\n * see a bigger stage, off-center seats see it at an angle. Used whenever the\n * organizer hasn't uploaded a real photo/360 for the seat; both go through the\n * same viewer.\n *\n * Equirectangular mapping: x = (yaw + 180°)/360° · W, y = (90° − pitch)/180° · H,\n * where yaw 0 = the direction the camera faces by default.\n */\n\nimport type { ExpandedSeat, Point } from '../core/types';\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;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\nexport interface PanoramaResult {\n url: string;\n /** Meters from the stage, for the caption. */\n distanceM: number;\n}\n\nexport function generateSeatPanorama(\n seat: ExpandedSeat,\n focalPoint: Point,\n neighborSeats: ExpandedSeat[],\n): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distU = Math.hypot(dx, dy);\n const distM = Math.max(2, distU * UNIT);\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.42, '#11172a');\n sky.addColorStop(0.5, '#1a2238');\n sky.addColorStop(0.56, '#10141f');\n sky.addColorStop(1, '#07090f');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // ---- stage, centered at yaw 0 (the viewer opens facing it) -------------\n // Angular size from real proportions: stage ~8m wide, ~1m platform + 6m set.\n // Pitch is eye-height-aware (Phase B2): a raised/raked seat looks down at it.\n const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageTopPitch = Math.min(45, sightline.topPitch);\n const stageBasePitch = sightline.basePitch;\n\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n\n // glow behind the stage\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 10, W / 2, (sy0 + sy1) / 2, (sx1 - sx0) * 1.1);\n glow.addColorStop(0, 'rgba(129, 140, 248, 0.5)');\n glow.addColorStop(0.5, 'rgba(99, 102, 241, 0.16)');\n glow.addColorStop(1, 'rgba(99, 102, 241, 0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - (sx1 - sx0) * 0.6, sy0 - (sy1 - sy0) * 1.2, (sx1 - sx0) * 2.2, (sy1 - sy0) * 3.4);\n\n // stage box + lit backdrop\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.75;\n ctx.fillStyle = backdrop;\n const inset = (sx1 - sx0) * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + (sy1 - sy0) * 0.12, sx1 - sx0 - inset * 2, (sy1 - sy0) * 0.62);\n ctx.globalAlpha = 1;\n // stage lip\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - (sy1 - sy0) * 0.1, sx1 - sx0, (sy1 - sy0) * 0.1);\n\n // performer silhouettes, scaled by distance\n const performerH = (sy1 - sy0) * 0.45;\n ctx.fillStyle = 'rgba(8, 10, 16, 0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + (sx1 - sx0) * fx;\n const py = sy1 - (sy1 - sy0) * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - performerH * 0.82, performerH * 0.16, 0, Math.PI * 2); // head\n ctx.fill();\n ctx.fillRect(px - performerH * 0.14, py - performerH * 0.68, performerH * 0.28, performerH * 0.68); // body\n }\n\n // spotlight beams from above the stage\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + (sx1 - sx0) * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.lineTo(bx - (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // ---- rig lights along the ceiling all around ---------------------------\n ctx.fillStyle = 'rgba(199, 210, 254, 0.8)';\n for (let i = 0; i < 26; i++) {\n const x = (i / 26) * W;\n const y = pitchToY(55 + (i % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, 3.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // ---- audience: heads of nearby seats, at their true bearings -----------\n // Bearing relative to the stage direction so yaw 0 keeps facing the stage.\n const stageBearing = Math.atan2(dx, -dy); // screen coords, -y is \"up\" the hall\n ctx.fillStyle = 'rgba(16, 20, 30, 0.95)';\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const d = Math.hypot(ox, oy) * UNIT;\n if (d < 0.3 || d > 14) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const headPitch = (-Math.atan2(0.35, d) * 180) / Math.PI; // heads slightly below eye level\n const headR = Math.min(46, 260 / (d / UNIT / 24 + 1.2) / 4);\n const hx = yawToX(yaw);\n const hy = pitchToY(headPitch);\n ctx.beginPath();\n ctx.arc(hx, hy, headR, 0, Math.PI * 2);\n ctx.fill();\n ctx.beginPath(); // shoulders\n ctx.ellipse(hx, hy + headR * 1.4, headR * 1.7, headR * 0.9, 0, Math.PI, 0, true);\n ctx.fill();\n }\n\n // subtle vignette at the poles (hides equirect pinching)\n const poleFade = ctx.createLinearGradient(0, 0, 0, H);\n poleFade.addColorStop(0, 'rgba(0,0,0,0.85)');\n poleFade.addColorStop(0.12, 'rgba(0,0,0,0)');\n poleFade.addColorStop(0.88, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.85)');\n ctx.fillStyle = poleFade;\n ctx.fillRect(0, 0, W, H);\n\n return { url: canvas.toDataURL('image/jpeg', 0.82), distanceM: Math.round(distM) };\n}\n\n// ---------------------------------------------------------------------------\n// Compact forward-view thumbnail — a cheap (480×270) rectilinear preview of\n// what this seat faces, for inline display inside the buyer's confirm card.\n// Unlike the full equirectangular panorama it maps a ~100°×60° forward field\n// of view directly (no 360 squish), so it reads as a real POV at a glance and\n// costs a fraction of the full render. Same geometry → the two stay consistent.\n// ---------------------------------------------------------------------------\n\nconst TW = 480;\nconst TH = 270;\nconst HALF_HFOV = 50; // degrees left/right of the stage direction\nconst HALF_VFOV = 30; // degrees up/down of the horizon\n\nconst yawToTX = (yawDeg: number) => ((yawDeg + HALF_HFOV) / (2 * HALF_HFOV)) * TW;\nconst pitchToTY = (pitchDeg: number) => ((HALF_VFOV - pitchDeg) / (2 * HALF_VFOV)) * TH;\n\nexport function generateSeatThumb(seat: ExpandedSeat, focalPoint: Point, _neighborSeats?: ExpandedSeat[]): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = TW;\n canvas.height = TH;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distM = Math.max(2, Math.hypot(dx, dy) * UNIT);\n\n // hall shell (ceiling → wall → floor), horizon at mid-height\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.44, '#141b30');\n sky.addColorStop(0.5, '#1b2440');\n sky.addColorStop(0.58, '#10141f');\n sky.addColorStop(1, '#070910');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n // stage geometry (identical formulas to the full panorama, eye-height-aware)\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\n // glow\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.1);\n glow.addColorStop(0, 'rgba(129,140,248,0.5)');\n glow.addColorStop(0.5, 'rgba(99,102,241,0.15)');\n glow.addColorStop(1, 'rgba(99,102,241,0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - sw * 0.6, sy0 - sh * 1.2, sw * 2.2, sh * 3.4);\n\n // stage box + lit backdrop + lip\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sw, sh);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.78;\n ctx.fillStyle = backdrop;\n const inset = sw * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + sh * 0.12, sw - inset * 2, sh * 0.62);\n ctx.globalAlpha = 1;\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - sh * 0.1, sw, sh * 0.1);\n\n // performer silhouettes\n const ph = sh * 0.45;\n ctx.fillStyle = 'rgba(8,10,16,0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + sw * fx;\n const py = sy1 - sh * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - ph * 0.82, ph * 0.16, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillRect(px - ph * 0.14, py - ph * 0.68, ph * 0.28, ph * 0.68);\n }\n\n // spotlight beams\n ctx.globalAlpha = 0.15;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + sw * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.lineTo(bx - sw * 0.09, sy1);\n ctx.lineTo(bx + sw * 0.09, sy1);\n ctx.lineTo(bx + 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // a few rig lights across the ceiling\n ctx.fillStyle = 'rgba(199,210,254,0.75)';\n for (let i = 0; i < 8; i++) {\n ctx.beginPath();\n ctx.arc(((i + 0.5) / 8) * TW, pitchToTY(HALF_VFOV - 4 - (i % 2) * 3), 2.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // seat-back rows in the foreground for depth\n ctx.fillStyle = 'rgba(10,13,20,0.9)';\n ctx.fillRect(0, TH - 26, TW, 26);\n ctx.fillStyle = 'rgba(30,37,54,0.9)';\n for (let i = 0; i < 9; i++) ctx.fillRect(i * (TW / 9) + 6, TH - 22, TW / 9 - 12, 14);\n\n return { url: canvas.toDataURL('image/jpeg', 0.8), distanceM: Math.round(distM) };\n}\n","/**\n * Locale bundle loader — keeps non-English translations OUT of the initial\n * bundle (the 150 KB complete CDN budget is a product contract) and code-splits each\n * locale so a page/SDK only downloads the language it actually uses.\n *\n * `loadLocale('de')` dynamic-imports the German dictionary, registers it via\n * setLocale(), and resolves once it's active. English is built in, so\n * `loadLocale('en')` is synchronous and never fetches. Unknown/unsupported\n * codes fall back to English without throwing.\n */\nimport { setLocale, resolveLocale, type Dict, type Locale } from './index';\n\n/** Dynamic importers per non-English locale (English ships in the core). */\nconst LOADERS: Record<Exclude<Locale, 'en'>, () => Promise<{ default: Dict }>> = {\n es: () => import('./locales/es').then((m) => ({ default: m.es })),\n de: () => import('./locales/de').then((m) => ({ default: m.de })),\n fr: () => import('./locales/fr').then((m) => ({ default: m.fr })),\n};\n\nconst loaded = new Set<Locale>(['en']);\n\n/**\n * Resolve `code` to a supported locale, load its bundle if needed, and make it\n * active. Returns the locale that ended up active (English on any failure).\n */\nexport async function loadLocale(code?: string | null): Promise<Locale> {\n const locale = resolveLocale(code);\n if (locale === 'en' || loaded.has(locale)) {\n setLocale(locale);\n return locale;\n }\n try {\n const mod = await LOADERS[locale]();\n setLocale(locale, mod.default);\n loaded.add(locale);\n return locale;\n } catch {\n setLocale('en');\n return 'en';\n }\n}\n"],"mappings":"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","names":["t","core","t","overrides","bounds","centroid","out","objects","bounds","t","rgb","bounds","scale","stageX","stageY","centroid","seatIndex","active","t"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/types.ts","../src/core/complexGeometry.ts","../src/core/sectionPath.ts","../src/core/labeling.ts","../src/core/units.ts","../src/core/layout.ts","../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":["/**\n * SeatMap chart document — the single source of truth shared by the\n * Designer (authoring) and the Renderer (buyer picker).\n *\n * Coordinates are abstract units (roughly \"pixels at scale 1\"); the renderer\n * fits the chart to its container.\n * Rows are PARAMETRIC (origin + count + spacing + curve + rotation) — never\n * store per-seat coordinates in the document; expansion happens in layout.ts.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface CubicPath {\n start: Point;\n control1: Point;\n control2: Point;\n end: Point;\n}\n\n/** A real closed section boundary. `outline` remains its sampled collision and\n * persistence fallback; this path is the smooth authoring/buyer paint source. */\nexport type SectionPathSegment =\n | { kind: 'line'; end: Point }\n | { kind: 'arc'; center: Point; radius: number; clockwise: boolean; end: Point }\n | { kind: 'bezier'; control1: Point; control2: Point; end: Point };\n\nexport interface SectionOutlinePath {\n version: 1;\n closed: true;\n start: Point;\n segments: SectionPathSegment[];\n}\n\nexport interface Category {\n key: string;\n label: string;\n color: string;\n /** Base price — used when the category has no explicit tiers. */\n price?: number;\n /** Durable evidence for semantic/display facts proposed while converting a\n * private reference into sellable inventory. */\n referenceCategorySource?: ReferenceCategorySource;\n /**\n * Ticket tiers (Adult / Child / Senior…). When present, a buyer picks a tier\n * per seat in this category and the tier's price applies; the first tier is the\n * default. Per-category (not per-seat) pricing — see Batch 3.5. Empty/absent =\n * a single price (the `price` above).\n */\n tiers?: CategoryTier[];\n}\n\nexport interface ReferenceCategorySource {\n assetId: string;\n /** Original sampled section color. `Category.color` is the approved output\n * color and may differ only with separately recorded evidence. */\n sourceColor: string;\n /** Every exact sampled color normalized into the same original 4-bit/channel\n * segmentation class. Older documents may contain only `sourceColor`. */\n sourceColors?: string[];\n /** Logical sections whose generated inventory uses this category. */\n logicalSectionIds?: string[];\n /** Source-color grouping is deterministic; a semantic regrouping needs its\n * own confirmed assignment evidence. */\n assignmentDerivation?: 'source-color-class' | 'confirmed-logical-sections';\n assignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription?: string;\n /** Optional legend/commercial swatch stated by the source. This remains\n * immutable provenance when the approved accessible output color differs. */\n sourcePaletteColor?: string;\n sourcePaletteColorEvidence?: 'user-confirmed' | 'authoritative-source';\n sourcePaletteColorSourceDescription?: string;\n labelEvidence: 'user-confirmed' | 'authoritative-source';\n labelSourceDescription: string;\n priceEvidence: 'user-confirmed' | 'authoritative-source';\n priceSourceDescription: string;\n outputColorEvidence?: 'user-confirmed' | 'authoritative-source';\n outputColorSourceDescription?: string;\n}\n\n/** One ticket tier within a category: a named price (Adult, Child, Senior…). */\nexport interface CategoryTier {\n id: string;\n name: string;\n price: number;\n}\n\n/**\n * Accessibility accommodations a seat can carry. Mirrors the taxonomy real\n * venues (and seats.io) expose so buyers can filter for exactly what they need\n * and organizers can mark seats precisely. `wheelchair` is the legacy default.\n */\nexport type AccessibilityType =\n | 'wheelchair'\n | 'companion'\n | 'semi-ambulatory'\n | 'hearing'\n | 'cart'\n | 'sign-language'\n | 'plus-size'\n | 'lift-armrest';\n\nexport interface AccessibilityMeta {\n key: AccessibilityType;\n /** Full descriptive label (designer checkbox, picker legend). */\n label: string;\n /** Compact label for chips/badges. */\n short: string;\n /** Single-glyph badge shown on seat chips + filter chips. */\n icon: string;\n}\n\n/** Ordered taxonomy — drives the designer seat panel and the picker filters. */\nexport const ACCESSIBILITY_TYPES: AccessibilityMeta[] = [\n { key: 'wheelchair', label: 'Wheelchair space', short: 'Wheelchair', icon: '♿' },\n { key: 'companion', label: 'Companion seat', short: 'Companion', icon: '🧑🤝🧑' },\n { key: 'semi-ambulatory', label: 'Semi-ambulatory (limited mobility)', short: 'Limited mobility', icon: '🦯' },\n { key: 'hearing', label: 'Assistive listening', short: 'Hearing', icon: '🦻' },\n { key: 'cart', label: 'CART live-caption view', short: 'CART captions', icon: 'CC' },\n { key: 'sign-language', label: 'Sign-language view', short: 'Sign language', icon: '🤟' },\n { key: 'plus-size', label: 'Plus-size seat', short: 'Plus-size', icon: '💺' },\n { key: 'lift-armrest', label: 'Lift-up armrest', short: 'Lift armrest', icon: '↕️' },\n];\n\nconst ACCESSIBILITY_LABEL = new Map(ACCESSIBILITY_TYPES.map((a) => [a.key, a]));\n\n/** Metadata for one accessibility key (undefined for unknown keys). */\nexport function accessibilityMeta(key: AccessibilityType): AccessibilityMeta | undefined {\n return ACCESSIBILITY_LABEL.get(key);\n}\n\n/**\n * Outer-ring colour per accommodation. Shared by the buyer picker and the\n * designer canvas so an accessible seat reads with the same hue in both — the\n * seat's first-listed type wins. `wheelchair` blue is the default fallback.\n */\nexport const ACCESSIBILITY_RING_COLOR: Record<AccessibilityType, string> = {\n wheelchair: '#3b82f6',\n companion: '#8b5cf6',\n 'semi-ambulatory': '#0ea5e9',\n hearing: '#14b8a6',\n cart: '#7c3aed',\n 'sign-language': '#f59e0b',\n 'plus-size': '#ec4899',\n 'lift-armrest': '#22c55e',\n};\n\n/** Ring colour for a seat's accessibility set (first-listed type wins). */\nexport function accessibilityRingColor(types: AccessibilityType[] | undefined): string {\n const primary = types?.[0];\n return (primary && ACCESSIBILITY_RING_COLOR[primary]) || '#3b82f6';\n}\n\nexport interface SeatOverride {\n /** 0-based seat index within the row. */\n index: number;\n /** Physical seat absent (pillar, sound desk) — numbering gap preserved. */\n skip?: boolean;\n /** Position nudge in chart units. */\n dx?: number;\n dy?: number;\n /** Replace the computed label entirely. */\n label?: string;\n /** Buyer-facing copy only. Booking/API identity remains row id + slot index\n * internally and the legacy `label` externally for backwards compatibility. */\n displayLabel?: string;\n categoryKey?: string;\n /** @deprecated legacy flag — read as `['wheelchair']`; write `accessibility`. */\n accessible?: boolean;\n /** Accessibility accommodations of this seat (empty/absent = none). */\n accessibility?: AccessibilityType[];\n /**\n * Physical wheelchair provision. Absent keeps legacy seat rendering;\n * `seat-present` is an explicit removable/fixed accessible chair, while\n * `no-seat` is an empty wheelchair bay that remains one sellable inventory\n * unit. This is deliberately distinct from `skip`, which removes inventory.\n */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n /** Commercial selling/view attributes are deliberately not accessibility. */\n commercial?: SeatCommercialAttributes;\n /** Seat-specific view photo; falls back to the row photo. */\n viewFromSeatUrl?: string;\n /** Per-seat label size/color override; falls back to the row/theme default.\n * Size is clamped to LABEL_STYLE_MIN_SIZE..MAX_SIZE; color is passed through\n * the shared auto-contrast rule at paint time (see {@link LabelStyle}). */\n labelStyle?: LabelStyle;\n}\n\nexport interface SeatCommercialAttributes {\n restrictedView?: boolean;\n obstructedView?: boolean;\n premium?: boolean;\n note?: string;\n}\n\n/**\n * Per-object label ink + size overrides layered on top of the chart-wide Theme\n * defaults (rowLabelColor / textColor for rows, the section-name ink for\n * sections). Both fields are optional: an absent field means \"inherit the theme\n * default\". `color` is a preferred hex — renderers still pass it through the\n * shared auto-contrast rule (`stateAwareBookableLabelInk`), so a choice that\n * would be illegible over the seat/section background is switched to black or\n * white at paint time. `size` is a font size in chart units, clamped to\n * LABEL_STYLE_MIN_SIZE..LABEL_STYLE_MAX_SIZE by the shared ops.\n */\nexport interface LabelStyle {\n size?: number;\n color?: string;\n}\n\n/** Clamp bounds for a per-object label `size`, shared by ops, MCP, and UI. */\nexport const LABEL_STYLE_MIN_SIZE = 8;\nexport const LABEL_STYLE_MAX_SIZE = 24;\n\nexport interface LabelPresentation {\n visible?: boolean;\n /** Exact Designer-owned label anchor; public semantic MCP schemas omit it. */\n position?: Point;\n rotation?: number;\n style?: 'plain' | 'pill';\n /** Per-object size/color override for this row's or section's label. */\n labelStyle?: LabelStyle;\n /**\n * End-position preset for a ROW label — which end(s) of the row show it:\n * - `start` (default/undefined) — the row's numbering-start end (legacy behaviour).\n * - `end` — the far end of the row.\n * - `both` — a label at BOTH ends.\n * - `none` — hidden (kept coherent with `visible: false`).\n * A free-drag `position` overrides the preset (the designer shows a 'custom'\n * state). Ignored for sections (they use `position`/`visible` only).\n */\n positionPreset?: 'start' | 'end' | 'both' | 'none';\n}\n\n/** Brand/venue theming — applied by the renderer in both designer and picker. */\nexport interface ChartTheme {\n /** Canvas background color (default dark: #0e1117-ish radial). */\n background?: string;\n /** Preferred text color for the numbers inside seat markers. */\n seatLabelColor?: string;\n /** Preferred color for row identifiers such as A, B, C. Falls back to textColor. */\n rowLabelColor?: string;\n /** Selection ring / accent color (default white ring + brand accent). */\n selectionColor?: string;\n /** Décor (stage/shape) default fill. */\n decorFill?: string;\n /** Free-text color default. */\n textColor?: string;\n /** Font family (CSS stack) for all rendered text — row labels, seat numbers, sections, décor text. */\n fontFamily?: string;\n /** Seat size multiplier on the base radius (0.7–1.6, default 1) — bigger seats fit longer labels. */\n seatScale?: number;\n // ---- White-label branding (applied by the buyer picker chrome) ----\n /** Brand accent color — recolors buttons, links, the hold pill, selection UI. */\n accent?: string;\n /** Ink color for text on the accent (e.g. button labels). Default light. */\n accentInk?: string;\n /** Organizer logo shown in the picker header (data/R2 URL). Falls back to the name. */\n logoUrl?: string;\n /** Brand/venue name shown in the picker header when no event name is set. */\n brandName?: string;\n /** Paid-tier flag: hide the \"Powered by SeatMap\" badge. */\n hideBadge?: boolean;\n}\n\nexport interface RowObject {\n type: 'row';\n id: string;\n /** Present when this row was materialized by the in-canvas reference scan.\n * A re-scan of the same asset replaces rows carrying this marker and NEVER\n * touches hand-authored rows — the same replace-generated-only invariant as\n * applyReferenceInventory. */\n referenceScan?: { assetId: string };\n /** Row label, e.g. \"A\". Seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing row name. `label` remains the legacy inventory prefix. */\n displayLabel?: string;\n /**\n * Buyer-facing type word override (seats.io \"Displayed type\"). Replaces the\n * hardcoded \"Row\" in the picker tooltip/confirm/cart, e.g. \"Table\", \"Bench\",\n * \"Aisle\". ≤24 chars; absent = the default \"Row\". Pure presentation.\n */\n displayType?: string;\n labelPresentation?: LabelPresentation;\n /** Position of the FIRST seat. */\n origin: Point;\n /** Degrees, clockwise. 0 = seats laid out along +x. */\n rotation: number;\n /**\n * Total arc sweep in degrees across the whole row. 0 = straight.\n * Positive bends away from +y (concave toward the focal point when the\n * row faces it). Typical theatre rows: 10–40.\n */\n curve: number;\n seatCount: number;\n /** Distance between adjacent seat centers, in chart units. */\n seatSpacing: number;\n /** Optional exact cubic centreline. Normal code owns these coordinates and\n * distributes seats by arc length; MCP/model inputs never submit them. */\n path?: CubicPath;\n categoryKey: string;\n /** Deterministic provenance for rows fitted from confirmed reference\n * inventory. It enables revision-safe replacement without touching manually\n * authored rows or accepting client coordinates. */\n referenceInventorySource?: ReferenceInventorySource;\n /** Semantic parameters for a row produced by the shared Arc/Fan operation.\n * Designer can reopen these parameters while every segment in the group\n * still carries the same generation signature. Public MCP tools never accept\n * the stored center/angles as arbitrary model-authored coordinates. */\n arcFanGeneration?: {\n kind: 'arc-fan-v1';\n groupId: string;\n center: Point;\n innerRadius: number;\n rowCount: number;\n rowGap: number;\n startAngle: number;\n endAngle: number;\n seatPitch: number;\n fit: 'seat-pitch' | 'fixed-count';\n seatsPerRow?: number;\n facing: 'inward' | 'outward';\n taperDegrees: number;\n skewDegrees: number;\n aisleGaps: { left: number; center: number; right: number };\n rowLabelStart: number;\n seatLabelStart: number;\n rowIndex: number;\n segmentIndex: number;\n };\n /**\n * Membership in one buyer-facing segmented row. Physical component rows and\n * their `${rowId}:${slotIndex}` inventory ids remain authoritative; this\n * metadata only supplies logical ordering/presentation and explicit aisle\n * continuity. The descriptor is repeated on every component so selecting any\n * one can resolve the complete logical row without a chart-level side table.\n */\n segmentedRow?: {\n kind: 'segmented-row-v1';\n groupId: string;\n componentIndex: number;\n componentCount: number;\n /** The first component must use `start`; later boundaries are explicit. */\n boundaryBefore: 'start' | 'continuous' | 'break';\n /** Buyer-facing row name; technical component `label` values never change. */\n displayLabel: string;\n displayType?: string;\n labelPresentation?: LabelPresentation;\n viewFromSeatUrl?: string;\n /** Presentation intent for a continuous node-defined centreline. */\n smoothing?: boolean;\n };\n /**\n * Versioned provenance for rows created by the multiple/intertwined block\n * generator. Manual geometry edits remove this marker rather than allowing a\n * later regeneration to overwrite hand-authored work.\n */\n rowBlockGeneration?: {\n kind: 'row-block-v1';\n groupId: string;\n style: 'multiple' | 'intertwined';\n rowIndex: number;\n rowCount: number;\n seatsPerRow: number;\n origin: Point;\n rotation: number;\n rowGap: number;\n seatSpacing: number;\n curve: number;\n /** Stable canonical generator signature shared by every intact member. */\n signature: string;\n };\n /** First seat number (default 1). Roman/letters read it as a 1-based ordinal\n * (start 1 → I / A). */\n seatLabelStart?: number;\n /** Seat numbering within the row (default decimal, ltr, step 1). */\n seatNumbering?: {\n /** ltr / rtl number from an end; `center` numbers outward from the middle\n * (centre seat lowest — the premium-centre theatre convention). */\n direction: 'ltr' | 'rtl' | 'center';\n /** 2 = odd/even numbering (1,3,5… — start at 2 for evens). */\n step?: 1 | 2;\n /**\n * Label scheme for the seat NUMBER part (the row prefix is separate).\n * Default `decimal`. Composition with `direction`/`step`/`seatLabelStart`:\n * - `decimal` 1,2,3 — honours direction + step + start.\n * - `odd` 1,3,5 — odd numbers from the first odd ≥ start.\n * - `even` 2,4,6 — even numbers from the first even ≥ start.\n * - `updown` 1,3,5,…,6,4,2 — odd-up-even-back; REPLACES direction (uses\n * physical left→right order); start shifts.\n * - `updown-descending` …5,3,1,2,4,6 — odd-back-even-up; the distinct\n * reverse up/down sequence. Also replaces\n * direction and uses physical order.\n * - `roman` I,II,III — honours direction + step + start (uppercase).\n * - `letters-upper` A,B,C…Z,AA — honours direction + step + start.\n * - `letters-lower` a,b,c…z,aa — honours direction + step + start.\n * Like `step`/`direction` today, the scheme changes the seat's inventory\n * label (its booking identity), by design.\n */\n scheme?: 'decimal' | 'odd' | 'even' | 'updown' | 'updown-descending' | 'roman' | 'letters-upper' | 'letters-lower';\n /** Optional prefix prepended to every seat number, e.g. 'R' → 'R1', 'R2'. */\n prefix?: string;\n /**\n * End-at preset (\"useEndAt\"): the row's numbering ENDS at this value instead\n * of starting at `seatLabelStart`. The start is derived so the last-numbered\n * seat (highest position rank) lands on `endAt`, respecting the scheme's step\n * (odd/even = 2). When set it WINS over the stored `seatLabelStart` (which is\n * left untouched). For letters it is a 1-based number index (26 → last seat\n * 'Z'); `updown` owns its own sequence and ignores `endAt`.\n */\n endAt?: number;\n };\n /**\n * Per-seat exceptions, keyed by seat index (0-based position in the row).\n * `skip` removes the physical seat but keeps the numbering gap (theatre\n * convention: a pillar eats A-3; A-4 stays A-4).\n */\n overrides?: SeatOverride[];\n /**\n * Organizer-supplied equirectangular 360 (or wide photo) shown as the\n * view-from-seat for every seat in this row. When absent, the picker\n * generates a synthetic panorama from chart geometry.\n */\n viewFromSeatUrl?: string;\n /** Default commercial attributes inherited by seats without an override. */\n commercial?: SeatCommercialAttributes;\n}\n\nexport interface GAAreaObject {\n type: 'gaArea';\n id: string;\n /** Stable technical/inventory label. */\n label: string;\n /** Buyer-facing area name; technical `label` and GA unit ids stay stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default type word. Pure presentation. */\n displayType?: string;\n /** Closed polygon, in chart units. */\n points: Point[];\n /** Explicit aisles/pillars/cutouts excluded from the sellable GA surface. */\n holes?: Point[][];\n capacity: number;\n categoryKey: string;\n /** Corner-rounding radius in chart units (default 0 = sharp corners). Pure\n * presentation — softens the polygon's corners in every renderer without\n * touching capacity, unit identities, or the stored points. Clamped per\n * corner to half the shorter adjacent edge at draw time. */\n cornerRadius?: number;\n /**\n * Durable inventory provenance for a surface produced by Join Areas.\n *\n * A GA unit is identified by the id and zero-based range of the area that\n * originally authored it, not by the current polygon which happens to own\n * it. Keeping those source ranges means a geometric join never renumbers an\n * already published/booked unit. Ordinary (never-joined) areas omit this\n * field and implicitly own `[0, capacity)` under their own id.\n *\n * The ranges must be non-overlapping, contain positive whole counts, and sum\n * exactly to `capacity`; validation rejects malformed metadata. Capacity\n * growth appends a new range under the surviving area id, while shrinking a\n * joined area is deliberately refused because it would silently destroy\n * stable inventory identities.\n */\n inventorySegments?: GAInventorySegment[];\n referenceInventorySource?: ReferenceInventorySource;\n}\n\nexport interface GAInventorySegment {\n sourceAreaId: string;\n startIndex: number;\n count: number;\n}\n\n/**\n * Durable evidence link for sellable objects generated from a private reference.\n * The client supplies facts and stable logical-section ids, never coordinates.\n */\nexport interface ReferenceAccessibilitySource {\n placementDerivation: 'server-synthesized-row-edges';\n groupLogicalSectionIds: string[];\n assignmentEvidence: 'user-confirmed' | 'authoritative-source';\n assignmentSourceDescription: string;\n counts: Array<{\n type: AccessibilityType;\n count: number;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n }>;\n}\n\nexport interface ReferenceInventorySource {\n assetId: string;\n logicalSectionId: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n /** Distinguishes directly supplied inventory from a user-approved server\n * distribution based only on an aggregate capacity. */\n derivation?: 'explicit-inventory' | 'server-synthesized-from-aggregate';\n /** Evidence for the aggregate figure; synthesized rows remain\n * `user-confirmed` and are never mislabeled as source-extracted. */\n aggregateEvidence?: 'user-confirmed' | 'authoritative-source';\n /** Separate evidence for assigning standing inventory to this logical\n * section. Aggregate evidence alone cannot prove section placement. */\n sectionAssignmentEvidence?: 'user-confirmed' | 'authoritative-source';\n sectionAssignmentSourceDescription?: string;\n /** Aggregate row synthesis may propose numbering, but persistence requires\n * the applying user/agent to confirm that policy explicitly. */\n numberingEvidence?: 'user-confirmed';\n numberingSourceDescription?: string;\n /** Evidence and deterministic placement contract for synthesized accessible\n * units in this logical section. */\n accessibility?: ReferenceAccessibilitySource;\n}\n\n/** Durable evidence that a visible source-backed section shell intentionally\n * carries no generated sellable inventory in this reference configuration. */\nexport interface ReferenceInventoryExclusionSource {\n assetId: string;\n logicalSectionId: string;\n reason: string;\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n}\n\n/** Open-path stroke semantics. Optional ShapeObject fields retain the legacy\n * round/round/no-ending rendering when absent. */\nexport type ShapeLineCap = 'butt' | 'round' | 'square';\nexport type ShapeLineJoin = 'miter' | 'round' | 'bevel';\nexport type ShapeLineEnding = 'none' | 'arrow';\n\n/** Non-bookable décor: stage, walls, exits. */\nexport interface ShapeObject {\n type: 'shape';\n id: string;\n /**\n * Closed area shapes (`rect`/`ellipse`/`polygon`) take a `fill`; open path\n * primitives (`line` = two points, `polyline` = n points) are stroke-only and\n * never filled. All kinds honour the optional `stroke`.\n */\n kind: 'rect' | 'ellipse' | 'polygon' | 'line' | 'polyline';\n label?: string;\n /** For rect/ellipse: bounding box. For a stage polygon: the base (pre-shape) box, so its kind can be regenerated. */\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n /** For polygon/line/polyline. */\n points?: Point[];\n fill?: string;\n /** Optional outline. `width` is in chart units; both fields are required together. */\n stroke?: { color: string; width: number };\n /** Open line/polyline only. Absent fields preserve round/round/no-ending legacy rendering. */\n lineCap?: ShapeLineCap;\n /** Controls corners between open-path segments. */\n lineJoin?: ShapeLineJoin;\n /** Independent open-path start/end decorations. Closed outlines never use these fields. */\n startEnding?: ShapeLineEnding;\n endEnding?: ShapeLineEnding;\n /** Rect only — corner rounding radius in chart units, clamped to half the short side at edit time. */\n cornerRadius?: number;\n /** Whole-shape opacity 0.1–1 (default 1). */\n opacity?: number;\n /** Degrees clockwise about the shape's center (default 0). Applied at render time. */\n rotation?: number;\n /**\n * Semantic tag driving special rendering. `'stage'` gets the gradient +\n * prominent uppercase label treatment; a décor landmark role (bar, exit…)\n * gets a quieter label. Loose string to avoid a circular import with\n * stage.ts / decor.ts (see StageKind / DecorRole there).\n */\n role?: string;\n /** For a stage: which `StageKind` its polygon was generated from. */\n stageKind?: string;\n}\n\nexport type RectTableSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** Exact rectangular-table chair distribution. The four keys are deliberately\n * required: zero means that edge has no chair, while the sum is the authored\n * `seatCount`. Numeric chair identity remains `${table.id}:${index}` in the\n * canonical top, bottom, left, right expansion order. */\nexport interface RectTableSeatCounts {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\n/** Seats arranged around a table. Grouped selling is activated only by an\n * event's explicit inventory-model-2 snapshot; model-1 events continue to\n * treat every authored chair as an independent unit. */\nexport interface TableObject {\n type: 'table';\n id: string;\n /** e.g. \"T1\" — seat labels are `${label}-${n}`. */\n label: string;\n /** Buyer-facing table name; technical chair/group labels stay stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default \"Row\"/\"Table\" word. Pure presentation. */\n displayType?: string;\n center: Point;\n shape: 'round' | 'rect';\n /** Seats around the perimeter (round) or along the enabled edges (rect). */\n seatCount: number;\n /** Rect tables: which edges get seats (default ['top','bottom']). */\n sides?: RectTableSide[];\n /**\n * Rect tables only: exact chairs on every edge. Absent preserves the legacy\n * `seatCount` + `sides` round-robin distribution byte-for-byte. When present,\n * all four values are whole numbers >= 0 and their sum equals `seatCount`.\n */\n seatCountsBySide?: RectTableSeatCounts;\n /** Individual-chair semantic overrides. Grouped whole/variable tables cannot\n * author these because their only sellable identity is the table itself. */\n overrides?: SeatOverride[];\n rotation: number;\n /** Round tables. */\n radius?: number;\n /**\n * Round tables: the arc (in degrees) the seats occupy, default 360 (full\n * ring). Below 360 leaves an open side — e.g. a service gap for waiters, a\n * head table facing the room, or clearance against a wall. The opening is\n * centred on the `rotation` direction; seats spread across the rest.\n */\n seatArc?: number;\n /** Rect tables. */\n width?: number;\n height?: number;\n categoryKey: string;\n /** One buyer owns the complete table at exactly `seatCount` guests. */\n bookAsWhole?: boolean;\n /** One buyer owns the complete table and chooses a bounded guest quantity. */\n variableOccupancy?: boolean;\n /** Required inclusive guest bounds when `variableOccupancy` is true. */\n minOccupancy?: number;\n maxOccupancy?: number;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/** A booth: one bookable unit rendered as a block (trade shows, VIP boxes). */\nexport interface BoothObject {\n type: 'booth';\n id: string;\n /** Stable technical/inventory label. */\n label: string;\n /** Buyer-facing booth name; technical `label` stays stable. */\n displayLabel?: string;\n /** Buyer-facing type word override (seats.io \"Displayed type\"), ≤24 chars.\n * Absent = the default type word. Pure presentation. */\n displayType?: string;\n center: Point;\n width: number;\n height: number;\n rotation: number;\n /**\n * Optional custom outline (closed polygon, absolute chart coordinates) for\n * non-rectangular booths — L-shaped, corner, or island units on expo floors.\n * Absent = the default axis-aligned rectangle described by `width`/`height`/\n * `rotation`. A booth stays exactly ONE atomic sellable unit whatever its\n * outline; `points` is purely geometric. `width`/`height` are retained as the\n * last rectangular size so \"Back to rectangle\" can restore it. When `points`\n * is present, renderers draw the polygon and ignore `rotation`.\n */\n points?: Point[];\n categoryKey: string;\n referenceInventorySource?: ReferenceInventorySource;\n}\n\n/**\n * A named region of the venue (Balcony Left, Floor B…). Sections are outlines\n * only — objects belong to a section spatially (center inside the outline),\n * keeping the document flat (no nesting; simpler for tools and for AI edits).\n * Renderer: far zoom shows section shapes/labels instead of seats; clicking\n * a section zooms into it.\n */\nexport interface SectionObject {\n type: 'section';\n id: string;\n label: string;\n /** Buyer-facing section name; logical/id fields remain stable. */\n displayLabel?: string;\n /**\n * Buyer-facing entrance/door hint shown in the picker section card\n * (\"Entrance X\"). ≤40 chars; absent = no entrance line. Pure presentation.\n */\n entrance?: string;\n /**\n * Organizer-supplied view image inherited by buyer inventory whose owning\n * row/table/booth sits in this logical section. Seat and row photos take\n * precedence; multipart components are kept in sync by the shared section\n * metadata operation.\n */\n viewFromSeatUrl?: string;\n labelPresentation?: LabelPresentation;\n /**\n * Stable management/inventory identity shared by disconnected visual\n * components of one logical section. When absent, `id` is the logical id.\n * Each component keeps its own `id` and reference provenance so rendering,\n * editing, measured diffs, and source restoration remain exact.\n */\n logicalSectionId?: string;\n /** Shared semantic Arc/Fan group wrapped by this section. The section id is\n * preserved when the fan parameters are reopened and regenerated. */\n arcFanGroupId?: string;\n /** Closed polygon, chart units. */\n outline: Point[];\n /** Optional true line/arc/cubic boundary. `outline` is a deterministic sample\n * of this path and remains authoritative for membership, validation, and\n * clients that predate curved section rendering. */\n outlinePath?: SectionOutlinePath;\n /** Explicit aisle/cutout polygons excluded from rendering, hit-testing, and membership. */\n holes?: Point[][];\n /** Durable opaque link to the private reference component. Unlike generator\n * provenance, this survives manual geometry edits so a measured diff can\n * report drift and server-owned code can restore the source contour. */\n referenceSource?: {\n assetId: string;\n regionId: string;\n };\n /** Evidence-backed reason this source section remains a visible shell without\n * synthesized sellable inventory (press, closed technical zone, etc.). */\n referenceInventoryExclusion?: ReferenceInventoryExclusionSource;\n /** Deterministic generator provenance for editable reference/parametric shells. */\n geometry?: {\n kind: 'rectangle' | 'tapered' | 'bezier' | 'contour';\n sourceRegionId?: string;\n contourMethod?: 'pixel-edge-loops-rdp' | 'shared-edge-vector-fit-v1';\n simplificationTolerancePx?: number;\n vectorFitErrorPx?: number;\n sharedEdgeCount?: number;\n };\n /** Optional tint override (defaults to a neutral fill / dominant category mix). */\n color?: string;\n /** Zone this section belongs to (id into `ChartDoc.zones`). Far-zoom nav + pricing group. */\n zone?: string;\n /**\n * Tier height. 0 = floor (default). Higher values lift the section in the\n * picker's isometric (\"3D\") view, drawn on extruded side faces. Same field a\n * future multi-floor mode reuses — authored in 2D, never drawn by the user.\n *\n * This is the coarse, back-compat source for {@link height}/{@link rake}: when\n * those are absent, {@link sectionGeometry} derives real geometry from this\n * tier so legacy charts render pixel-identical.\n */\n elevation?: number;\n /**\n * 3D foundations (Phase A, additive — no migration; charts are JSON blobs).\n * Metres the section's **front edge** sits above floor 0 (a balcony/tier floor\n * height). Absent ⇒ derived from the coarse {@link elevation} tier via\n * {@link sectionGeometry}. Deliberately two scalars, not a foundation polygon:\n * front-height + {@link rake} fully determine a rectangular tier's back-height.\n *\n * NOTE: no consumer reads this raw field directly — all callers go through\n * {@link sectionGeometry}. Phase B consumers (iso view lift in\n * `SeatmapRenderer`, per-seat eye-height in the `generatePanorama` 360°\n * generator) are intentionally NOT wired in Phase A. Range 0–120 m.\n */\n height?: number;\n /**\n * Degrees of seating incline within the section (0 = flat; typical stalls\n * 5–15°, steep tiers 25–35°). Absent ⇒ 0. Consumed alongside {@link height}\n * by the future Phase B iso-lift shear and 360° sightline math — never in\n * Phase A. Range 0–45°.\n */\n rake?: number;\n /** Uniform scale about the outline centroid (1 = as drawn). Scales members too. */\n scale?: number;\n /** 0–100: reviewed strength last used to bend member rows toward a common fitted arc. */\n smoothing?: number;\n /** Degrees clockwise about the outline centroid (default 0). Rotates members too. */\n rotation?: number;\n}\n\n/**\n * A group of sections (Lower Bowl, Upper Bowl, Floor…). One concept, three jobs:\n * the farthest-zoom navigation unit, a pricing group, and (Batch 3) a timed-\n * release unit. Kept as a flat list on the doc; sections point back by `zone` id.\n */\nexport interface ZoneDef {\n id: string;\n label: string;\n color?: string;\n /**\n * Authored point this zone faces. Optional only for legacy documents: runtime\n * consumers fall back to the active floor/chart focal, while publication of\n * a zone-mode draft requires every used zone to carry an explicit point.\n */\n focalPoint?: Point;\n}\n\n/**\n * Selection layer — a hit-test/dim filter in the designer, NOT z-order management.\n * Fixed set of four; derived from object type via `layerOf()` (no per-object field yet).\n */\nexport type SelectionLayer = 'interactive' | 'background' | 'foreground' | 'surroundings';\n\n/** Shape roles emitted by the curated venue-landmark palette. Keep this list in\n * lockstep with `DECOR_PRESETS`; the selection-layer unit test fails if either\n * vocabulary changes without an explicit routing decision. `reference-focal`\n * is source-backed venue context rather than an authoring-palette preset. */\nexport const SURROUNDINGS_SHAPE_ROLES = [\n 'reference-focal',\n 'bar',\n 'entrance',\n 'exit',\n 'restroom',\n 'screen',\n 'sound',\n 'concession',\n 'coat',\n 'wall',\n] as const;\n\nconst SURROUNDINGS_SHAPE_ROLE_SET: ReadonlySet<string> = new Set(SURROUNDINGS_SHAPE_ROLES);\n\n/** Derive an object's selection layer from its type. */\nexport function layerOf(obj: ChartObject): SelectionLayer {\n switch (obj.type) {\n case 'row':\n case 'table':\n case 'gaArea':\n case 'booth':\n case 'section':\n return 'interactive';\n // Raster décor follows its explicit authored z-layer. Absence retains the\n // legacy Background default; bitmap content is never guessed semantically.\n case 'decorImage':\n return obj.layer === 'foreground' ? 'foreground' : 'background';\n // Source-backed focal geometry and curated venue landmarks help an author\n // orient around the sellable plan. A stage and an ordinary authored shape\n // remain Background even when they carry an arbitrary/custom role.\n case 'shape':\n return obj.role && SURROUNDINGS_SHAPE_ROLE_SET.has(obj.role)\n ? 'surroundings'\n : 'background';\n // Free text — including semantic icon text — is background furniture.\n case 'text':\n return 'background';\n default:\n return 'interactive';\n }\n}\n\n/** Free-standing text on the chart (aisle names, door labels…). */\nexport interface TextObject {\n type: 'text';\n id: string;\n /** Persisted provenance for objects created from the venue-icon palette. */\n semanticKind?: 'icon';\n /**\n * Registry key for a vector wayfinding icon (see src/core/icons.ts). Present\n * on modern icon placements; the object then renders as a single-color vector\n * Path instead of `text`. Absent on legacy emoji icons, which keep rendering\n * `text` through the shared glyph path — old charts are never rewritten.\n */\n iconKey?: string;\n text: string;\n position: Point;\n fontSize: number;\n /** Optional CSS family stack for this annotation; absent inherits ChartTheme.fontFamily. */\n fontFamily?: string;\n rotation: number;\n color?: string;\n /** Render weight (default false). Maps to Konva fontStyle bold. */\n bold?: boolean;\n /** Render slant (default false). Maps to Konva fontStyle italic. */\n italic?: boolean;\n}\n\n/**\n * A raster/vector decor graphic drawn IN the chart, beneath the seats and\n * sections (ice rink, basketball court, stage art, pitch markings). Purely\n * visual venue context — never bookable, never hit-tested, so it never steals a\n * seat click. `href` is a self-contained data URL (image or SVG) produced by the\n * same client-side downscale used for row photos, so it travels with the doc and\n * caches as a single bitmap blit (zero per-frame cost). Placed by top-left\n * (x,y) + size, rotated about its centre — the same handles a shape rect uses.\n */\nexport interface DecorImageObject {\n type: 'decorImage';\n id: string;\n /** Image or SVG data URL. */\n href: string;\n x: number;\n y: number;\n width: number;\n height: number;\n /** Degrees clockwise about the image centre (default 0). */\n rotation?: number;\n /** 0–1 (default 1). Multiplied by any chart-theme dimming at render time. */\n opacity?: number;\n /**\n * Z-layer relative to the interactive seat layer. `background` (default)\n * draws beneath the seats/sections; `foreground` draws above them (a roof\n * canopy, an overlay graphic). Absent = background — no migration needed.\n */\n layer?: 'background' | 'foreground';\n /** Optional caption for the designer inspector / accessibility (not drawn). */\n label?: string;\n}\n\nexport type ChartObject =\n | RowObject\n | GAAreaObject\n | ShapeObject\n | TableObject\n | BoothObject\n | TextObject\n | SectionObject\n | DecorImageObject;\n\n/**\n * One floor / level of a multi-floor venue (Batch 5). Each floor owns its own\n * geometry, stage focal point, and trace image; categories/zones/tiers stay\n * chart-global (one event, one inventory). A single-floor chart has NO `floors`\n * — its `objects[]` is the whole venue — so all existing charts are untouched.\n */\nexport interface Floor {\n id: string;\n name: string;\n /**\n * Absolute physical deck height in metres above the venue/stage datum.\n * Optional for backwards compatibility; an absent value resolves to ground\n * level (0 m). Section tiers and rakes are separate, section-local metadata.\n * Range 0–120 m.\n */\n baseHeightM?: number;\n objects: ChartObject[];\n focalPoint: Point;\n /**\n * Private organizer trace/calibration layer. This is authoring evidence and\n * must never be served to, or rendered by, a buyer surface.\n */\n referenceImage?: ChartReferenceImage;\n /**\n * Buyer-visible aesthetic background. Canonical documents store URL-only\n * images here. Historical `assetId` values are interpreted as a trace layer\n * by the background compatibility helpers.\n */\n backgroundImage?: ChartDoc['backgroundImage'];\n}\n\nexport interface ReferenceCalibration {\n type: 'two-point';\n /** Points in immutable source-image pixels, selected by a human or trusted detector. */\n sourceA: Point;\n sourceB: Point;\n /** Verified real-world distance between the two source points. */\n distance: number;\n unit: 'm' | 'ft' | 'chart-unit';\n /** Derived and stored for deterministic geometry compilers. */\n pixelsPerUnit: number;\n}\n\n/**\n * A single human-placed seat probe: the author clicks one seat on the reference\n * image and the server reads the surrounding seat lattice from it.\n *\n * COORDINATE-POLICY CARVE-OUT (owner decision 2026-07-21). The reference\n * blueprint pipeline runs `coordinatePolicy: 'opaque-region-ids-only'` — the\n * server is the sole source of chart coordinates and MCP clients select opaque\n * `reg_*` ids, never points. This type is a deliberate, narrow exception on the\n * same grounds as `ReferenceCalibration`: the point is placed by a human in the\n * designer canvas, not proposed by a model.\n *\n * Therefore this is DESIGNER-ONLY and is intentionally NOT exposed over MCP.\n * That is an accepted, documented exception to the MCP-parity rule — the\n * server-is-sole-source guarantee for model-driven edits is worth more than\n * parity here. Do not \"fix\" it by adding a seed point to an MCP tool schema.\n */\nexport interface ReferenceSeatSeed {\n /** Seed centre in immutable source-image pixels (never chart coordinates). */\n source: Point;\n /** Half-width of the author's sizing ring, in source pixels — the \"this is how\n * big one seat is\" hint that replaces seats.io's zoom-until-it-matches step. */\n radius: number;\n /** Whether `radius` was fitted from image pixels or set by hand. Detection\n * weights an author-set radius more heavily than one we guessed. */\n origin: 'auto-fit' | 'manual';\n}\n\n/** One detected row in a scan proposal — a straight seat run in CHART\n * coordinates (the server maps source pixels through referencePixelToChart;\n * clients never see source-pixel geometry back). */\nexport interface ReferenceScanRowProposal {\n start: Point;\n end: Point;\n seatCount: number;\n}\n\n/** Detected rows attributed to one compiled section (or unattributed when the\n * lattice extends outside every compiled polygon). */\nexport interface ReferenceScanSectionProposal {\n /** Id of the compiled SectionObject the rows landed in; null = unattributed. */\n sectionId: string | null;\n name: string;\n rows: ReferenceScanRowProposal[];\n seatCount: number;\n /** 0..1 — how well this section's lattice agreed with the probe's pitch. */\n confidence: number;\n /** Index of the seed (multi-probe) whose pitch produced these rows. */\n seedIndex: number;\n}\n\n/** Server response for an in-canvas reference scan. A PROPOSAL — nothing is\n * committed until the author applies it in the designer (chartOps + undo). */\nexport interface ReferenceScanProposal {\n assetId: string;\n /** Measured seat diameter / centre-to-centre pitch, in chart units. */\n seatDiameter: number;\n seatPitch: number;\n totalSeats: number;\n totalRows: number;\n sections: ReferenceScanSectionProposal[];\n}\n\n/** Coordinate-free physical scale derived by server code from a confirmed\n * semantic feature. Unlike manual two-point calibration, no source points pass\n * through an MCP client or language model. */\nexport interface ReferenceDerivedScale {\n method: 'confirmed-focal-axis-v1';\n feature: 'focal-long-axis' | 'focal-short-axis';\n distance: number;\n unit: 'm' | 'ft';\n evidence: 'user-confirmed' | 'authoritative-source';\n sourceDescription: string;\n chartUnitsPerUnit: number;\n}\n\nexport interface ChartReferenceImage {\n /** Stable private reference asset. New cloud-authored charts use this. */\n assetId?: string;\n /** Legacy/self-contained source. Optional when assetId is present. */\n url?: string;\n center: Point;\n /** Rendered width in chart units (height follows the cropped image aspect). */\n width: number;\n opacity: number;\n rotation?: number;\n visible?: boolean;\n layer?: 'below' | 'above';\n locked?: boolean;\n /** Normalized source crop; defaults to the full image. */\n crop?: { x: number; y: number; width: number; height: number };\n calibration?: ReferenceCalibration;\n /** Server-derived semantic calibration without source-image coordinates. */\n derivedScale?: ReferenceDerivedScale;\n}\n\nexport interface ChartDoc {\n version: 1;\n name: string;\n venueType: 'SIMPLE' | 'MIXED';\n /** The stage / point every seat looks at. Anchors seat-view + sightlines.\n * Multi-floor: mirrors floor 0; each floor also carries its own focalPoint. */\n focalPoint: Point;\n categories: Category[];\n /** Section groupings for far-zoom navigation + pricing (optional; sections reference by id). */\n zones?: ZoneDef[];\n /** Multi-floor venues (Batch 5): present ⇒ floors[] is the source of truth;\n * absent ⇒ single-floor and `objects` below is the whole chart. `objects`\n * is kept mirroring floor 0 so single-floor readers never branch. */\n floors?: Floor[];\n objects: ChartObject[];\n /**\n * Private floor-plan source used for tracing, calibration, scanning and\n * reference-backed generation. Buyer projections always remove this field.\n */\n referenceImage?: ChartReferenceImage;\n /**\n * Buyer-visible aesthetic background. Canonical values are URL-only.\n * Compatibility: a historical value containing `assetId` is trace-only and\n * is never rendered or exposed to buyers.\n */\n backgroundImage?: ChartReferenceImage;\n /** Brand/venue theming (colors); categories carry their own colors separately. */\n theme?: ChartTheme;\n /** Parametric-template provenance: present ⇒ the chart came from a capacity-\n * adjustable template family, and the designer offers a capacity control that\n * regenerates it at a new target seat count (Batch 4 \"curated singles + resize\"). */\n template?: { family: string; targetSeats: number };\n}\n\n// ---------------------------------------------------------------------------\n// Expanded (render-time) model — produced by layout.ts, consumed by the engine\n// ---------------------------------------------------------------------------\n\nexport interface ExpandedSeat {\n /** Stable id: `${rowId}:${index}` */\n id: string;\n /** Public label: `${rowLabel}-${seatNumber}` */\n label: string;\n /** Buyer-facing copy; absent on legacy charts, where `label` is displayed. */\n displayLabel?: string;\n x: number;\n y: number;\n rowId: string;\n /** Owning logical section and navigation zone, resolved once at expand time. */\n sectionId?: string;\n zoneId?: string;\n /** Zone focal when authored, otherwise the active floor/chart legacy fallback. */\n focalPoint?: Point;\n /** Buyer-facing segmented-row identity. `rowId` stays the physical owner id. */\n logicalRowId?: string;\n /**\n * Seat order inside the logical row. A deliberate missing integer is inserted\n * at every aisle boundary, so numerical adjacency cannot bridge a gap.\n */\n logicalSeatIndex?: number;\n categoryKey: string;\n /** 'booth' units render as blocks (dimensions looked up via rowId = booth id). */\n kind?: 'seat' | 'booth';\n /** True when the seat has any accessibility accommodation — renderer rings/dims these. */\n accessible?: boolean;\n /** Specific accessibility accommodations (absent = none) — picker badges/filters these. */\n accessibility?: AccessibilityType[];\n /** Physical wheelchair provision resolved from the seat override. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n commercial?: SeatCommercialAttributes;\n /** Organizer-supplied view-from-seat image (inherited from the row). */\n viewUrl?: string;\n /** Per-seat label size/color override; absent = inherit the row/theme default. */\n labelStyle?: LabelStyle;\n /**\n * Real-world eye height in metres above the focal/stage datum, resolved at\n * expand time from the owning section's `{height, rake}` + drawn depth (Phase B2).\n * Feeds the auto-360° generator's stage-pitch math. Absent ⇒ flat seated eye\n * height (legacy / seats in no section) — so old charts stay pixel-identical.\n */\n eyeHeightM?: number;\n}\n\nexport type SeatStatus = 'free' | 'held' | 'booked' | 'not_for_sale';\n\n/** Buyer canvas projection. Perspective is a view-only projected-2.5D lane. */\nexport type RendererViewMode = 'flat' | 'isometric' | 'perspective';\n\n// ---------------------------------------------------------------------------\n// Renderer engine public API — implemented in src/engine/SeatmapRenderer.ts\n// ---------------------------------------------------------------------------\n\nexport interface RendererCallbacks {\n onSelect?: (seat: ExpandedSeat) => void;\n onDeselect?: (seat: ExpandedSeat) => void;\n /** Buyer tried to add a seat after the active selection cap was reached. */\n onSelectionLimit?: (maxSelection: number) => void;\n /** seat is null when the pointer leaves any seat. */\n onHover?: (seat: ExpandedSeat | null) => void;\n /** Keyboard focus moved to a seat (arrow-key navigation) — for screen-reader announcements. */\n onFocusSeat?: (seat: ExpandedSeat | null) => void;\n /** Called ~1×/sec with the measured frames-per-second. */\n onFps?: (fps: number) => void;\n /** Fired when a GA area is clicked (quantity picking is UI-side). */\n onGAClick?: (areaId: string) => void;\n /**\n * Fired when a tap lands on a section outline while seats are NOT the active\n * rung (i.e. zoomed out, section/zone LOD). The host glides in + shows a\n * section-summary card instead of trying to select a 4px seat (Slice 5).\n */\n onSectionTap?: (sectionId: string) => void;\n /**\n * Fired when a seat/deck is tapped in the 3D all-floors stacked overview — the\n * host drops back to the flat 2D map on that floor (\"tap a deck to enter\").\n */\n onDeckTap?: (floorId: string) => void;\n /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */\n onViewChange?: () => void;\n /**\n * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on\n * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,\n * with the FULL current selection (selectable seats only). The host toolbar\n * reads this to drive bulk block/unblock. Never fires when manageMode is off.\n */\n onMarquee?: (seats: ExpandedSeat[]) => void;\n}\n\n/** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */\nexport type LodRung = 'zones' | 'sections' | 'seats';\n\nexport interface RendererOptions extends RendererCallbacks {\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** Only these statuses are clickable (default ['free']). */\n selectableStatuses?: SeatStatus[];\n /**\n * Opt-in host behaviour flag — the renderer's own click/selection logic is\n * unchanged (it still selects + fires `onSelect` immediately, so the seat\n * highlights right away). When true, the host (e.g. PublicEventPage) treats\n * that `onSelect` as a pending candidate and shows a confirm card instead of\n * pushing straight into the cart; `deselect([seat.id])` on Cancel un-highlights.\n */\n confirmSelection?: boolean;\n /** ISO 4217 currency for on-map prices (\"FROM …\"); defaults to money.DEFAULT_CURRENCY.\n * Locale for grouping/symbol placement comes from the active i18n locale. */\n currency?: string;\n /**\n * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode\n * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /\n * pinch / tap and every existing code path are byte-identical when this is\n * false (every manage branch is gated on it). Default false.\n */\n manageMode?: boolean;\n /**\n * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung\n * draws a rubber-band marquee that bulk-selects the seats it covers (emitting\n * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger\n * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below\n * the seats rung (zoom in first). No effect unless `manageMode` is also set.\n */\n marqueeSelect?: boolean;\n}\n\nexport type RenderedLabelHiddenReason =\n | 'below-minimum-size'\n | 'outside-viewport'\n | 'dimmed-or-unavailable'\n | 'clutter-or-fit'\n | 'renderer-hidden';\n\n/** Browser-renderer evidence used by visual QA and catalog release gates. */\nexport interface RenderedBookableLabelEvidence {\n seatId: string;\n label: string;\n kind: 'seat' | 'booth';\n /** Painted inventory silhouette. Empty wheelchair bays are deliberately\n * square, while physical seats retain the ordinary circular marker. */\n markerShape: 'circle' | 'square' | 'booth';\n /** Physical wheelchair provision represented by this inventory unit. */\n wheelchairSpaceType?: 'seat-present' | 'no-seat';\n categoryKey: string;\n sectionId?: string;\n zoneId?: string;\n status: SeatStatus;\n selected: boolean;\n visible: boolean;\n renderedFontPx: number;\n fill: string;\n ink: string;\n opacity: number;\n /** Buyer-visible accessibility glyph evidence. Filter emphasis uses a\n * screen-space minimum so wheelchair provision remains recognizable at fit. */\n accessibilityMarker?: {\n glyphVisible: boolean;\n glyphWidthPx: number;\n emphasizedByFilter: boolean;\n };\n /** Direct Konva shape bounds and the production near-miss rescue combined. */\n pointerTarget: {\n active: boolean;\n directWidthPx: number;\n directHeightPx: number;\n effectiveMinimumPx: number;\n };\n /** Centre of the painted unit, even when its text is intentionally hidden. */\n screenCenter: { x: number; y: number };\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: RenderedLabelHiddenReason;\n}\n\nexport interface RenderedHierarchyLabelEvidence {\n id: string;\n kind: 'section' | 'zone';\n role: 'name' | 'availability' | 'price';\n label: string;\n visible: boolean;\n renderedFontPx: number;\n opacity: number;\n fill: string;\n ink: string;\n /** Independent geometric containment check for section-owned text. */\n fitsContainer?: boolean;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RenderedFreeTextEvidence {\n objectId: string;\n kind: 'free-text' | 'stage' | 'table' | 'decor' | 'ga-label' | 'ga-capacity';\n text: string;\n visible: boolean;\n renderedFontPx: number;\n ink: string;\n background: string;\n opacity: number;\n screenBox?: { x: number; y: number; width: number; height: number };\n hiddenReason?: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden';\n}\n\nexport interface RenderedGAAreaEvidence {\n areaId: string;\n label: string;\n capacity: number;\n categoryKey: string;\n /** Owning logical section when the rendered GA surface is section-contained. */\n sectionId?: string;\n visible: boolean;\n interactive: boolean;\n opacity: number;\n fill: string;\n effectiveBackground: string;\n screenBox?: { x: number; y: number; width: number; height: number };\n}\n\nexport interface RendererQualityEvidence {\n viewport: { width: number; height: number };\n /** Runtime projection actually used for the pixels and hit graph below. */\n projection: RendererViewMode;\n /** Phase-C proof metadata. Present only in the projected-2.5D lane. */\n perspective?: {\n model: 'pinhole-exact-seat-anchors';\n sectionSurfaceModel: 'tangent-plane';\n exactSeatAnchorCount: number;\n depthSorted: true;\n };\n canvasBackground: string;\n effectiveScale: number;\n rung: LodRung;\n minimumVisibleLabelPx: number;\n totalLabelledBookableUnits: number;\n visibleLabels: number;\n hiddenLabels: number;\n /** Seats/table-seats/booths plus the full GA capacity. */\n totalBookableUnits: number;\n selectionRingSeatIds: string[];\n selectionRingColor: string;\n focusedSectionId: string | null;\n focusBackdropVisible: boolean;\n categoryFilterKeys: string[] | null;\n /** Exact scene-graph proof for the clean section-first overview contract. */\n overviewStyle: {\n visibleSectionShells: number;\n categoryPaintedSectionShells: number;\n visibleCategoryDetailOutlines: number;\n visibleSectionRowHints: number;\n visibleSectionAvailabilityLabels: number;\n visibleSectionGADetails: number;\n };\n labels: RenderedBookableLabelEvidence[];\n gaAreas: RenderedGAAreaEvidence[];\n hierarchyLabels: RenderedHierarchyLabelEvidence[];\n freeTextLabels: RenderedFreeTextEvidence[];\n}\n\nexport interface ISeatmapRenderer {\n /** Replace the chart. Resets selection and statuses, zooms to fit.\n * `opts.floorId` picks which floor to render on a multi-floor chart (Batch 5). */\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void;\n /** Bulk status update; re-renders affected seats only. */\n setStatus(seatIds: string[], status: SeatStatus): void;\n /**\n * Mark the active buyer's own held seats. They remain server-status `held`,\n * but render with the buyer selection treatment instead of the anonymous\n * unavailable treatment used for another buyer's hold.\n */\n setOwnedHold?(seatIds: string[] | null): void;\n /**\n * Mark one selected seat as the buyer's pending confirmation candidate.\n * The candidate receives a strong focus halo while unrelated seats recede;\n * pass null after Select/Cancel. This is visual only and never mutates the\n * renderer selection.\n */\n setSelectionFocus?(seatId: string | null): void;\n /**\n * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()\n * (used by setStatus and friends) schedules the actual paint on the next rAF\n * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded\n * tabs — so a seat-status delta updates the scene graph but the pixels never\n * change until the tab is foregrounded again. forceDraw() paints the affected\n * layers immediately (Layer.draw() is synchronous) and flushes any pending\n * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in\n * always-live board) can guarantee the canvas reflects current state\n * regardless of tab visibility. No-op difference in the foreground.\n */\n forceDraw(): void;\n getStatus(seatId: string): SeatStatus;\n getSelection(): ExpandedSeat[];\n clearSelection(): void;\n /** Update the buyer selection cap without rebuilding the chart or camera. */\n setMaxSelection?(maxSelection: number): void;\n /**\n * Programmatically restore free seats (for example an Undo action). Added\n * seats respect the active cap and do not reopen a confirmation popover.\n */\n select?(seatIds: string[]): ExpandedSeat[];\n /**\n * Dynamically update organizer-only interaction without rebuilding the\n * renderer. No buyer surface calls this; every behavior remains gated by\n * `manageMode` exactly as it is at construction time.\n */\n setManageInteraction?(options: {\n manageMode: boolean;\n marqueeSelect: boolean;\n selectableStatuses: SeatStatus[];\n maxSelection?: number;\n }): void;\n /** Organizer-only section heat overlay. Values are normalized 0..1. */\n setSectionHeat?(scores: Record<string, number> | null): void;\n /**\n * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).\n * They select the matching SELECTABLE seats (respecting `selectableStatuses`\n * + closed sections), union with the current selection, and return the seats\n * they added — the SDK SeatManager expands category/row/section picks to\n * labels and drives one batched block/unblock from them.\n */\n selectAllSelectable?(): ExpandedSeat[];\n selectByLabels?(labels: string[]): ExpandedSeat[];\n /** Exact-render QA only: select one server-chosen unit without label ambiguity. */\n setEvidenceSelection?(seatId: string): boolean;\n /** Selectable seats belonging to a section OR zone id (no selection side-effect). */\n getSelectableInSection?(sectionId: string): ExpandedSeat[];\n /** Programmatic deselect of specific seats (e.g. chip × in the cart). */\n deselect(seatIds: string[]): void;\n /**\n * Brief attention pulse on a seat (a ring that expands + fades once) — used to\n * signal live activity, e.g. a seat \"just taken\" by another buyer via a WS\n * delta. Purely visual; no state change. `color` overrides the default.\n */\n flashSeat(seatId: string, color?: string): void;\n /**\n * Brief organizer attention pulse around a whole section. This is a visual\n * overlay only: it never changes section geometry, hit targets, selection, or\n * the active camera. Useful for grouped realtime operations at venue overview.\n */\n flashSection?(sectionId: string, color?: string): void;\n zoomToFit(): void;\n /** Zoom in one step about the viewport center, clamped to the usual zoom bounds. */\n zoomIn(): void;\n /** Zoom out one step about the viewport center, clamped to the usual zoom bounds. */\n zoomOut(): void;\n /** Individually status-managed seats/table-seats/booths; excludes GA capacity. */\n seatCount(): number;\n /** Seats/table-seats/booths plus the full capacity of rendered GA areas. */\n bookableCount(): number;\n /**\n * Maps a chart-space point (or a seat, by its x/y) to container-relative\n * screen pixels, using the current stage scale/position. Lets host UI anchor\n * DOM overlays (confirm card, tooltip) over a live seat and re-anchor them\n * on `onViewChange`.\n */\n worldToScreen(point: Point): { x: number; y: number };\n /** When on, dim non-accessible free seats so accessible seats stand out. */\n setAccessibleFilter(on: boolean): void;\n /**\n * Dim free seats that lack ANY of these accessibility types. `null` clears the\n * filter; `[]` means \"any accessible seat\" (same as setAccessibleFilter(true)).\n */\n setAccessibilityFilter(types: AccessibilityType[] | null): void;\n /** Legend hover-highlight: dim free seats of other categories (null clears). */\n setCategoryHighlight?(key: string | null): void;\n /** Price-band filter (F4): dim free seats whose category is NOT in `keys`\n * (null clears). The widget resolves which categories fall in the band. */\n setCategoryFilter?(keys: string[] | null): void;\n /** Smoothly frame the currently available seats in these categories. `null`\n * returns to the full chart. Used after an explicit buyer price-filter action. */\n focusCategories?(keys: string[] | null): void;\n /** Dim the seats of these section/zone ids (organizer manager: held-back inventory). */\n setDimmedSections?(ids: string[] | null): void;\n /**\n * Phase 2 event-level section states: mark these section/zone ids `closed` —\n * flat grey block, seats greyed + not pickable, section stays rendered.\n * `null`/empty clears. (Distinct from the buyer's applyHidden seat-strip.)\n */\n setClosedSections?(ids: string[] | null): void;\n /**\n * AXS section-focus: dim + desaturate every other section, draw a calm backdrop\n * behind this section, and glide the camera to frame it. Seat-picking is gated\n * until seats are large enough on screen (≥ LABEL_SCALE). Slice 5 / Phase 2 §4.\n */\n focusSection?(id: string): void;\n /** Clear an AXS section focus (restore full-bowl brightness + drop backdrop). */\n clearSectionFocus?(): void;\n /** The currently AXS-focused section id, or null. */\n getFocusedSection?(): string | null;\n /** World-space rect currently visible in the viewport (minimap viewport frame). */\n getVisibleWorldRect?(): { x: number; y: number; width: number; height: number };\n /** Axis-aligned world bounds of all seats + section outlines (minimap frame). */\n getWorldBounds?(): { x: number; y: number; width: number; height: number };\n /**\n * Colorblind-safe mode: category hues switch to an Okabe-Ito palette and\n * booked seats render hollow (a non-color cue), so seat state never relies\n * on hue alone. Off (the default) renders exactly as before.\n */\n setColorblindSafe?(on: boolean): void;\n /**\n * Switch the projection. `'flat'` = normal top-down; `'isometric'` = the\n * legacy affine preview; `'perspective'` = projected 2.5D with exact pinhole\n * seat anchors/native hit shapes and bounded per-section tangent surfaces.\n * Purely visual — the chart is authored flat.\n */\n setViewMode?(mode: RendererViewMode): void;\n /** Current projection (defaults to 'flat' when unimplemented). */\n getViewMode?(): RendererViewMode;\n /** Multi-floor (Batch 5): switch the shown floor; list floors; read the active id. */\n setActiveFloor?(floorId: string): void;\n getFloors?(): { id: string; name: string }[];\n getActiveFloorId?(): string;\n /** Render all floors stacked (3D overview) vs the active floor. No-op single-floor. */\n setStacked?(on: boolean): void;\n isStacked?(): boolean;\n /**\n * Section id whose outline contains a container-relative screen point (or null).\n * Feeds the far-zoom \"tap a section to zoom in\" flow (Slice 5).\n */\n sectionAt?(clientPoint: Point): string | null;\n /** Seat ids belonging to a section — for the section-summary card (Slice 5). */\n sectionMembers?(id: string): string[];\n /**\n * Smoothly glide (pan+zoom) the camera to frame a section (by id) or a world-\n * space bounds rect over a calm easeInOutCubic glide. `prefers-reduced-motion` snaps.\n * A pointer-down (grab/pan) cancels an in-flight glide. Slice 5 \"glide in\".\n */\n focusRegion?(\n target: string | { x: number; y: number; width: number; height: number },\n opts?: { animate?: boolean; minScale?: number; durationMs?: number },\n ): void;\n /** Current LOD rung derived from zoom (for the ZONES/SECTIONS/SEATS pill). */\n getRung?(): LodRung;\n /** Jump the camera to a rung's zoom band, centred on the chart (glided). */\n setRung?(rung: LodRung): void;\n /** Read actual browser-rendered label visibility, size, fill, ink and state.\n * Pure diagnostic: it never changes chart or renderer state. */\n getRenderedQualityEvidence(): RendererQualityEvidence;\n destroy(): void;\n}\n\n/** localStorage key the Designer writes and the Picker reads. */\nexport const CHART_STORAGE_KEY = 'seatmap.chart';\n","import type { CubicPath, Point } from './types';\n\nexport type SectionShellMode = 'auto' | 'rectangle' | 'tapered' | 'bezier';\n\nexport function cubicPoint(path: CubicPath, t: number): Point {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n return {\n x: a * path.start.x + b * path.control1.x + c * path.control2.x + d * path.end.x,\n y: a * path.start.y + b * path.control1.y + c * path.control2.y + d * path.end.y,\n };\n}\n\n/** Equal-arc-length points on a cubic path, including both endpoints. */\nexport function distributeAlongCubic(path: CubicPath, count: number, resolution = 192): Point[] {\n if (!Number.isInteger(count) || count < 1) throw new Error('Path point count must be a positive integer');\n if (count === 1) return [cubicPoint(path, 0.5)];\n const samples = Array.from({ length: resolution + 1 }, (_, index) => cubicPoint(path, index / resolution));\n const lengths = new Float64Array(samples.length);\n for (let index = 1; index < samples.length; index += 1) {\n const dx = samples[index].x - samples[index - 1].x;\n const dy = samples[index].y - samples[index - 1].y;\n lengths[index] = lengths[index - 1] + Math.hypot(dx, dy);\n }\n const total = lengths[lengths.length - 1];\n if (total <= 1e-9) return Array.from({ length: count }, () => ({ ...path.start }));\n const output: Point[] = [];\n let segment = 1;\n for (let index = 0; index < count; index += 1) {\n const target = (total * index) / (count - 1);\n while (segment < lengths.length - 1 && lengths[segment] < target) segment += 1;\n const before = lengths[segment - 1];\n const after = lengths[segment];\n const ratio = after === before ? 0 : (target - before) / (after - before);\n output.push({\n x: samples[segment - 1].x + (samples[segment].x - samples[segment - 1].x) * ratio,\n y: samples[segment - 1].y + (samples[segment].y - samples[segment - 1].y) * ratio,\n });\n }\n return output;\n}\n\nfunction add(a: Point, b: Point): Point { return { x: a.x + b.x, y: a.y + b.y }; }\nfunction sub(a: Point, b: Point): Point { return { x: a.x - b.x, y: a.y - b.y }; }\nfunction mul(a: Point, scale: number): Point { return { x: a.x * scale, y: a.y * scale }; }\nfunction distance(a: Point, b: Point): number { return Math.hypot(a.x - b.x, a.y - b.y); }\nfunction lerp(a: Point, b: Point, t: number): Point { return add(a, mul(sub(b, a), t)); }\n\nfunction sample(path: CubicPath, count = 13): Point[] {\n return Array.from({ length: count }, (_, index) => cubicPoint(path, index / (count - 1)));\n}\n\nfunction pointOnSampledPath(points: Point[], t: number): Point {\n const scaled = Math.max(0, Math.min(1, t)) * (points.length - 1);\n const index = Math.min(points.length - 2, Math.floor(scaled));\n return lerp(points[index], points[index + 1], scaled - index);\n}\n\nfunction sampledPathSegment(points: Point[], from: number, to: number): Point[] {\n const start = Math.max(0, Math.min(1, from));\n const end = Math.max(start, Math.min(1, to));\n const output = [pointOnSampledPath(points, start)];\n for (let index = 1; index < points.length - 1; index += 1) {\n const t = index / (points.length - 1);\n if (t > start + 1e-9 && t < end - 1e-9) output.push(points[index]);\n }\n output.push(pointOnSampledPath(points, end));\n return output;\n}\n\ninterface SectionFrame {\n p0: Point;\n p1: Point;\n p2: Point;\n p3: Point;\n normal: Point;\n depth: number;\n}\n\nfunction orientSectionFrame(corners: Point[], focal: Point): SectionFrame {\n const edges: Array<[number, number]> = [[0, 1], [1, 2], [2, 3], [3, 0]];\n let nearEdge = 0;\n let nearDistance = Number.POSITIVE_INFINITY;\n edges.forEach(([a, b], index) => {\n const d = distance(lerp(corners[a], corners[b], 0.5), focal);\n if (d < nearDistance) {\n nearDistance = d;\n nearEdge = index;\n }\n });\n const p0 = corners[nearEdge];\n const p1 = corners[(nearEdge + 1) % 4];\n const p2 = corners[(nearEdge + 2) % 4];\n const p3 = corners[(nearEdge + 3) % 4];\n const nearMid = lerp(p0, p1, 0.5);\n const inward = sub(focal, nearMid);\n const inwardLength = Math.max(1e-9, Math.hypot(inward.x, inward.y));\n return {\n p0,\n p1,\n p2,\n p3,\n normal: mul(inward, 1 / inwardLength),\n depth: (distance(p0, p3) + distance(p1, p2)) / 2,\n };\n}\n\nfunction bezierSectionPaths(frame: SectionFrame): { nearPath: CubicPath; farPath: CubicPath } {\n const { p0, p1, p2, p3, normal, depth } = frame;\n const nearSpan = sub(p1, p0);\n const farSpan = sub(p2, p3);\n const nearCurve = depth * 0.22;\n const farCurve = depth * 0.12;\n return {\n nearPath: {\n start: p0,\n control1: add(add(p0, mul(nearSpan, 1 / 3)), mul(normal, nearCurve)),\n control2: add(add(p0, mul(nearSpan, 2 / 3)), mul(normal, nearCurve)),\n end: p1,\n },\n farPath: {\n start: p2,\n control1: add(add(p3, mul(farSpan, 2 / 3)), mul(normal, farCurve)),\n control2: add(add(p3, mul(farSpan, 1 / 3)), mul(normal, farCurve)),\n end: p3,\n },\n };\n}\n\n/**\n * Convert a server-mapped rectangle into an editable complex shell. The four\n * corners must be clockwise. No caller-supplied control points are accepted.\n */\nexport function buildSectionShell(corners: Point[], focal: Point, requested: SectionShellMode): {\n mode: Exclude<SectionShellMode, 'auto'>;\n outline: Point[];\n} {\n if (corners.length !== 4) throw new Error('A section shell requires four mapped bounds corners');\n const center = corners.reduce((sum, point) => add(sum, point), { x: 0, y: 0 });\n center.x /= 4;\n center.y /= 4;\n const width = distance(corners[0], corners[1]);\n const height = distance(corners[0], corners[3]);\n const mode = requested === 'auto'\n ? (width > height * 1.25 && distance(center, focal) > height ? 'bezier' : 'tapered')\n : requested;\n if (mode === 'rectangle') return { mode, outline: corners.map((point) => ({ ...point })) };\n\n // Rotate corners so local p0→p1 is the edge nearest the focal point and\n // p3→p2 is the far edge, while preserving clockwise winding.\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n\n if (mode === 'tapered') {\n const inset = 0.14;\n return {\n mode,\n outline: [\n add(p0, mul(sub(p1, p0), inset)),\n add(p0, mul(sub(p1, p0), 1 - inset)),\n p2,\n p3,\n ],\n };\n }\n\n const { nearPath, farPath } = bezierSectionPaths(frame);\n return { mode, outline: [...sample(nearPath), ...sample(farPath).slice(1)] };\n}\n\n/** Server-owned straight aisle cutouts spanning the near/far edges. */\nexport function buildAisleHoles(\n corners: Point[],\n focal: Point,\n count: number,\n mode: Exclude<SectionShellMode, 'auto'>,\n): Point[][] {\n if (corners.length !== 4) throw new Error('Aisle generation requires four mapped bounds corners');\n if (!Number.isInteger(count) || count < 0 || count > 3) throw new Error('Aisle count must be an integer from 0 to 3');\n if (count === 0) return [];\n const frame = orientSectionFrame(corners, focal);\n const { p0, p1, p2, p3 } = frame;\n const paths = mode === 'bezier' ? bezierSectionPaths(frame) : null;\n // For curved shells, interpolate the same sampled polylines stored in the\n // document. Exact cubic points between samples can sit fractionally outside\n // their chord approximation and fail topology validation/hit clipping.\n const nearSamples = paths ? sample(paths.nearPath) : null;\n const farLateralSamples = paths ? sample(paths.farPath).reverse() : null;\n const widthFraction = Math.min(0.055, 0.18 / (count + 1));\n return Array.from({ length: count }, (_, index) => {\n const t = (index + 1) / (count + 1);\n const left = t - widthFraction / 2;\n const right = t + widthFraction / 2;\n if (nearSamples && farLateralSamples) {\n return [\n ...sampledPathSegment(nearSamples, left, right),\n ...sampledPathSegment(farLateralSamples, left, right).reverse(),\n ];\n }\n return [lerp(p0, p1, left), lerp(p0, p1, right), lerp(p3, p2, right), lerp(p3, p2, left)];\n });\n}\n","import type { Point, SectionOutlinePath, SectionPathSegment } from './types';\n\nconst TAU = Math.PI * 2;\n\nfunction finitePoint(point: Point): boolean {\n return Number.isFinite(point.x) && Number.isFinite(point.y);\n}\n\nfunction distance(left: Point, right: Point): number {\n return Math.hypot(left.x - right.x, left.y - right.y);\n}\n\nfunction arcSweep(start: number, end: number, clockwise: boolean): number {\n let delta = end - start;\n if (clockwise) {\n while (delta < 0) delta += TAU;\n while (delta >= TAU) delta -= TAU;\n } else {\n while (delta > 0) delta -= TAU;\n while (delta <= -TAU) delta += TAU;\n }\n return delta;\n}\n\nexport function sectionPathSegmentEnd(segment: SectionPathSegment): Point {\n return segment.end;\n}\n\n/** Validate finite, continuous closed-path geometry without trusting renderer\n * behaviour. Arc endpoints must lie on their declared circle. */\nexport function validSectionOutlinePath(path: SectionOutlinePath): boolean {\n if (path.version !== 1 || path.closed !== true || !finitePoint(path.start)\n || !Array.isArray(path.segments) || path.segments.length < 2 || path.segments.length > 512) return false;\n let current = path.start;\n for (const segment of path.segments) {\n if (!segment || !finitePoint(segment.end)) return false;\n if (segment.kind === 'line') {\n if (distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'bezier') {\n if (!finitePoint(segment.control1) || !finitePoint(segment.control2)\n || distance(current, segment.end) <= 1e-9) return false;\n } else if (segment.kind === 'arc') {\n if (!finitePoint(segment.center) || !Number.isFinite(segment.radius) || segment.radius <= 1e-6\n || Math.abs(distance(current, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || Math.abs(distance(segment.end, segment.center) - segment.radius) > Math.max(1e-4, segment.radius * 1e-4)\n || distance(current, segment.end) <= 1e-9) return false;\n } else return false;\n current = segment.end;\n }\n return distance(current, path.start) <= 1e-4;\n}\n\nfunction cubicPoint(start: Point, segment: Extract<SectionPathSegment, { kind: 'bezier' }>, t: number): Point {\n const mt = 1 - t;\n return {\n x: mt ** 3 * start.x + 3 * mt ** 2 * t * segment.control1.x\n + 3 * mt * t ** 2 * segment.control2.x + t ** 3 * segment.end.x,\n y: mt ** 3 * start.y + 3 * mt ** 2 * t * segment.control1.y\n + 3 * mt * t ** 2 * segment.control2.y + t ** 3 * segment.end.y,\n };\n}\n\n/** Deterministic polygon sample used by validation, hit testing, diff, and old\n * clients. The returned loop omits the duplicate closing point. */\nexport function sampleSectionOutlinePath(path: SectionOutlinePath, maxStep = 2): Point[] {\n if (!validSectionOutlinePath(path)) throw new Error('Section outline path is invalid');\n const step = Math.max(0.25, maxStep);\n const points: Point[] = [{ ...path.start }];\n let current = path.start;\n for (const segment of path.segments) {\n if (segment.kind === 'line') {\n points.push({ ...segment.end });\n } else if (segment.kind === 'arc') {\n const startAngle = Math.atan2(current.y - segment.center.y, current.x - segment.center.x);\n const endAngle = Math.atan2(segment.end.y - segment.center.y, segment.end.x - segment.center.x);\n const sweep = arcSweep(startAngle, endAngle, segment.clockwise);\n const count = Math.max(2, Math.ceil(Math.abs(sweep) * segment.radius / step));\n for (let index = 1; index <= count; index += 1) {\n const angle = startAngle + sweep * index / count;\n points.push({\n x: segment.center.x + Math.cos(angle) * segment.radius,\n y: segment.center.y + Math.sin(angle) * segment.radius,\n });\n }\n } else {\n const controlLength = distance(current, segment.control1)\n + distance(segment.control1, segment.control2)\n + distance(segment.control2, segment.end);\n const count = Math.max(2, Math.ceil(controlLength / step));\n for (let index = 1; index <= count; index += 1) points.push(cubicPoint(current, segment, index / count));\n }\n current = segment.end;\n }\n if (distance(points[points.length - 1], points[0]) <= 1e-4) points.pop();\n return points;\n}\n\nexport function translateSectionOutlinePath(path: SectionOutlinePath, dx: number, dy: number): SectionOutlinePath {\n const translate = (point: Point): Point => ({ x: point.x + dx, y: point.y + dy });\n return transformSectionOutlinePath(path, translate);\n}\n\n/** Apply a similarity transform. Callers provide the point transform and the\n * absolute radius scale; reflections toggle arc direction. */\nexport function transformSectionOutlinePath(\n path: SectionOutlinePath,\n transform: (point: Point) => Point,\n radiusScale = 1,\n reflected = false,\n): SectionOutlinePath {\n return {\n ...path,\n start: transform(path.start),\n segments: path.segments.map((segment) => segment.kind === 'line'\n ? { ...segment, end: transform(segment.end) }\n : segment.kind === 'arc'\n ? {\n ...segment,\n center: transform(segment.center),\n radius: segment.radius * Math.abs(radiusScale),\n clockwise: reflected ? !segment.clockwise : segment.clockwise,\n end: transform(segment.end),\n }\n : {\n ...segment,\n control1: transform(segment.control1),\n control2: transform(segment.control2),\n end: transform(segment.end),\n }),\n };\n}\n\n/** Reverse a closed path without changing its painted boundary. */\nexport function reverseSectionOutlinePath(path: SectionOutlinePath): SectionOutlinePath {\n const starts: Point[] = [];\n let current = path.start;\n for (const segment of path.segments) {\n starts.push(current);\n current = segment.end;\n }\n const segments: SectionPathSegment[] = [];\n for (let index = path.segments.length - 1; index >= 0; index -= 1) {\n const segment = path.segments[index];\n const end = starts[index];\n if (segment.kind === 'line') segments.push({ kind: 'line', end: { ...end } });\n else if (segment.kind === 'arc') segments.push({\n kind: 'arc', center: { ...segment.center }, radius: segment.radius,\n clockwise: !segment.clockwise, end: { ...end },\n });\n else segments.push({\n kind: 'bezier', control1: { ...segment.control2 }, control2: { ...segment.control1 }, end: { ...end },\n });\n }\n return { version: 1, closed: true, start: { ...path.start }, segments };\n}\n","/**\n * Pure row/seat labeling helpers used by the designer's \"relabel\" tools\n * (e.g. bulk-renumber rows A, B, C… or 1, 2, 3…). No dependencies.\n */\n\nexport interface RelabelOptions {\n scheme: 'letters' | 'numbers';\n /** 1-based start: letters 1=A; numbers 1=1. */\n startAt: number;\n /** Letters only: skip I and O (common theatre convention). */\n skipAmbiguous?: boolean;\n /** Apply labels in reverse order over the given array. */\n reverse?: boolean;\n}\n\nconst FULL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst SAFE_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // no I, no O\n\nconst LOWER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz';\n\n/**\n * Bijective base-N conversion: 0 -> first letter, N -> second letter's\n * first repeat cycle (e.g. base26: 25 -> 'Z', 26 -> 'AA').\n */\nexport function toBijectiveBase(index: number, alphabet: string): string {\n const base = alphabet.length;\n let n = index + 1; // bijective numeration is 1-based\n let out = '';\n while (n > 0) {\n n -= 1;\n const rem = n % base;\n out = alphabet[rem] + out;\n n = Math.floor(n / base);\n }\n return out;\n}\n\nexport function indexLabel(i: number, opts: RelabelOptions): string {\n const start = opts.startAt - 1; // convert 1-based startAt to 0-based offset\n const idx = i + start;\n if (opts.scheme === 'numbers') {\n return String(idx + 1);\n }\n const alphabet = opts.skipAmbiguous ? SAFE_ALPHABET : FULL_ALPHABET;\n return toBijectiveBase(idx, alphabet);\n}\n\n/**\n * Alphabetic label for a 1-based value (1 -> 'A', 26 -> 'Z', 27 -> 'AA').\n * Uppercase by default; `lower` gives the a,b,c… variant. Values ≤ 0 clamp to 'A'.\n */\nexport function toLetters(value: number, lower = false): string {\n const alphabet = lower ? LOWER_ALPHABET : FULL_ALPHABET;\n return toBijectiveBase(Math.max(0, Math.floor(value) - 1), alphabet);\n}\n\nconst ROMAN_TABLE: Array<[number, string]> = [\n [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], [100, 'C'], [90, 'XC'],\n [50, 'L'], [40, 'XL'], [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'],\n];\n\n/** Uppercase Roman numeral for a positive integer (1 -> 'I', 4 -> 'IV', 9 -> 'IX').\n * Non-positive / non-finite inputs fall back to their decimal string. */\nexport function toRoman(value: number): string {\n if (!Number.isFinite(value) || value <= 0) return String(value);\n let remaining = Math.floor(value);\n let out = '';\n for (const [n, sym] of ROMAN_TABLE) {\n while (remaining >= n) {\n out += sym;\n remaining -= n;\n }\n }\n return out;\n}\n\nexport function relabelRows<T extends { label: string }>(rows: T[], opts: RelabelOptions): T[] {\n const n = rows.length;\n return rows.map((row, i) => {\n const assignIndex = opts.reverse ? n - 1 - i : i;\n return { ...row, label: indexLabel(assignIndex, opts) };\n });\n}\n","/**\n * Real-world scale primitives — the ONE place the app fixes chart-unit ↔ metre ↔\n * renderer-world scale, and the section 3D-geometry resolver that rides on it.\n *\n * Everything that converts between chart units, metres, and renderer \"world\"\n * units derives from {@link METRES_PER_CHART_UNIT}. Renderer world units and\n * chart units are 1:1, so metres → world is exactly {@link CHART_UNITS_PER_METRE}\n * (the single m→world conversion constant Phase B consumers use).\n *\n * This is a leaf module (types only) so both `layout.ts` and `sections.ts` can\n * import it without the two forming an import cycle.\n */\nimport type { SectionObject } from './types';\n\n/**\n * Chart units → metres. seatSpacing 24 ≈ 0.55 m (a real seat pitch). This single\n * constant anchors every real-world scale in the app; `generatePanorama` and the\n * iso lift both derive from it instead of re-declaring their own 0.55/24.\n */\nexport const METRES_PER_CHART_UNIT = 0.55 / 24;\n\n/**\n * Metres → chart units, i.e. metres → renderer world units (world == chart units\n * in the engine). THE single m→world conversion constant: the iso view lifts an\n * elevated section by `sectionGeometry(section).height × CHART_UNITS_PER_METRE`.\n */\nexport const CHART_UNITS_PER_METRE = 1 / METRES_PER_CHART_UNIT;\n\n/**\n * Renderer world units a section lifts per {@link SectionObject.elevation} tier in\n * the legacy iso view (mirror of `SeatmapRenderer`'s old `LIFT_PER_STEP`). Kept so\n * the tier→metres fallback below reproduces today's iso look byte-for-byte.\n */\nexport const LIFT_PER_STEP_WORLD = 58;\n\n/**\n * Metres of front-edge height one elevation tier represents. Chosen (not guessed)\n * so `elevation × TIER_HEIGHT_M` metres, scaled back through\n * {@link CHART_UNITS_PER_METRE}, equals the legacy `elevation × LIFT_PER_STEP`\n * world lift exactly — an un-authored chart stays pixel-identical. ≈ 1.329 m/tier.\n */\nexport const TIER_HEIGHT_M = LIFT_PER_STEP_WORLD * METRES_PER_CHART_UNIT;\n\n/** Canonical authored section-geometry bounds. Keep every UI/API/renderer on\n * these constants so a producer cannot silently invent a second unit system. */\nexport const SECTION_ELEVATION_TIER_MIN = 0;\nexport const SECTION_ELEVATION_TIER_MAX = 3;\nexport const SECTION_HEIGHT_MIN_M = 0;\nexport const SECTION_HEIGHT_MAX_M = 120;\nexport const SECTION_RAKE_MIN_DEG = 0;\nexport const SECTION_RAKE_MAX_DEG = 45;\n\n/** Curated charts released before the height field used coarse levels 4–7.\n * Preserve their established lift while drafts/templates migrate to an explicit\n * height. Values above 7 came from broken compiler multipliers and must never be\n * interpreted as physical tiers. */\nexport const LEGACY_SECTION_ELEVATION_TIER_MAX = 7;\n\n/**\n * Seated spectator eye height above the tier floor (arena ≈ 1.20 m; theatre refs\n * use 1.15 m). Also the flat-ground baseline eye height, so a flat, ground-level\n * seat produces zero elevation offset in the 360° stage-pitch math (back-compat).\n */\nexport const SEATED_EYE_HEIGHT_M = 1.2;\n\n/**\n * Resolve a section's real 3D geometry, applying the legacy-elevation fallback so\n * old charts and new charts share ONE code path. Every consumer (iso lift, 360°\n * eye-height, author lint, any 2D depth cue) must call this and never read the raw\n * {@link SectionObject.height}/{@link SectionObject.rake} fields — that is what\n * keeps un-authored charts rendering identically to today.\n *\n * - `height`: authored absolute metres if present, else owning-floor base height\n * plus `elevation × TIER_HEIGHT_M`.\n * - `rake`: authored degrees if present, else 0 (flat).\n *\n * Malformed values are bounded here as a last defensive barrier. Structural\n * validation still reports them so drafts can be repaired instead of silently\n * persisting a renderer-only interpretation.\n *\n * Pure — no document mutation, no side effects.\n */\nexport interface SectionGeometryContext {\n /** Absolute physical height of the owning floor above the venue datum. */\n floorBaseHeightM?: number;\n}\n\nfunction finiteClamped(value: number | undefined, min: number, max: number, fallback: number): number {\n return Number.isFinite(value) ? Math.max(min, Math.min(max, value as number)) : fallback;\n}\n\n/** Canonical 0–3 tier exposed by Designer/shared operations. */\nexport function sectionElevationTier(value: number | undefined): number {\n if (!Number.isFinite(value)) return SECTION_ELEVATION_TIER_MIN;\n return Math.max(\n SECTION_ELEVATION_TIER_MIN,\n Math.min(SECTION_ELEVATION_TIER_MAX, Math.round(value as number)),\n );\n}\n\n/** Runtime-only compatibility tier. Released curated charts used integers 4–7;\n * preserve those while bounding compiler mistakes such as 12/55/220 to the\n * canonical maximum. New documents must store only {@link sectionElevationTier}. */\nfunction compatibleAutomaticTier(value: number | undefined): number {\n if (!Number.isFinite(value) || !Number.isInteger(value) || (value as number) < 0) return 0;\n if ((value as number) <= LEGACY_SECTION_ELEVATION_TIER_MAX) return value as number;\n return SECTION_ELEVATION_TIER_MAX;\n}\n\nexport function sectionGeometry(\n section: Pick<SectionObject, 'elevation' | 'height' | 'rake'>,\n context: SectionGeometryContext = {},\n): {\n height: number;\n rake: number;\n} {\n const floorBaseHeightM = finiteClamped(\n context.floorBaseHeightM,\n SECTION_HEIGHT_MIN_M,\n SECTION_HEIGHT_MAX_M,\n 0,\n );\n const automaticHeight = Math.min(\n SECTION_HEIGHT_MAX_M,\n floorBaseHeightM + compatibleAutomaticTier(section.elevation) * TIER_HEIGHT_M,\n );\n const height = section.height === undefined\n ? automaticHeight\n : finiteClamped(section.height, SECTION_HEIGHT_MIN_M, SECTION_HEIGHT_MAX_M, automaticHeight);\n const rake = finiteClamped(section.rake, SECTION_RAKE_MIN_DEG, SECTION_RAKE_MAX_DEG, 0);\n return { height, rake };\n}\n","/**\n * Pure geometry helpers — no Konva, no DOM. Turns the parametric chart\n * document into concrete seat coordinates and computes bounding boxes.\n */\n\nimport type {\n AccessibilityType,\n BoothObject,\n ChartDoc,\n ChartObject,\n ExpandedSeat,\n Floor,\n LabelStyle,\n Point,\n RowObject,\n RectTableSeatCounts,\n RectTableSide,\n SeatOverride,\n SectionObject,\n TableObject,\n} from './types';\nimport { distributeAlongCubic } from './complexGeometry';\nimport { translateSectionOutlinePath } from './sectionPath';\nimport { toLetters, toRoman } from './labeling';\nimport { METRES_PER_CHART_UNIT, SEATED_EYE_HEIGHT_M, sectionGeometry } from './units';\n\n/** Resolve a seat override's accessibility, honouring the legacy boolean flag. */\nfunction overrideAccessibility(o: SeatOverride | undefined): AccessibilityType[] {\n if (!o) return [];\n if (o.accessibility && o.accessibility.length) {\n return o.wheelchairSpaceType && !o.accessibility.includes('wheelchair')\n ? ['wheelchair', ...o.accessibility]\n : o.accessibility;\n }\n if (o.wheelchairSpaceType) return ['wheelchair'];\n return o.accessible ? ['wheelchair'] : [];\n}\n\nconst DEG = Math.PI / 180;\n/** Seat visual radius (mirrors the renderer) — used only for bounds padding. */\nconst SEAT_R = 9;\n/** How far outside a table's body its seats sit. */\nconst TABLE_SEAT_OFFSET = 16;\n\n/** Rotate a local point clockwise by `deg` (screen coords, +y down) then translate. */\nfunction place(lx: number, ly: number, deg: number, origin: Point): { x: number; y: number } {\n const a = deg * DEG;\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n return {\n x: origin.x + lx * cos - ly * sin,\n y: origin.y + lx * sin + ly * cos,\n };\n}\n\n/**\n * Expand a parametric row into seat positions.\n *\n * Straight (curve === 0): seat i sits at local (i·spacing, 0).\n *\n * Curved: seats lie on a circular arc. Per-seat angular step is\n * `curve/(seatCount-1)`; radius is derived so the chord between neighbours\n * equals seatSpacing → radius = spacing / (2·sin(step/2)). Seat 0 sits at the\n * bottom of the arc (local origin) with the circle centre directly above it at\n * (0,-radius); increasing index sweeps toward +x while the ends rise toward -y,\n * i.e. positive curve is concave toward -y (a row wrapping a stage above it).\n * Local points are then rotated by `rotation` and translated to `origin`.\n *\n * Numbering (labels only, never geometry): `seatNumbering.direction === 'rtl'`\n * numbers from the far physical end; `step === 2` produces odd/even numbering\n * (start at 1 → 1,3,5…; start at 2 → 2,4,6…).\n */\n/** Base (pre-override) seat centre per index — shared by expandRow + designer edit mode. */\nexport function rowSeatPositions(row: RowObject): Point[] {\n const { seatCount, seatSpacing, curve, rotation, origin } = row;\n const out: Point[] = [];\n if (row.path) return distributeAlongCubic(row.path, seatCount);\n if (seatCount <= 1) {\n if (seatCount === 1) out.push({ x: origin.x, y: origin.y });\n return out;\n }\n if (curve === 0) {\n for (let i = 0; i < seatCount; i++) out.push(place(i * seatSpacing, 0, rotation, origin));\n return out;\n }\n const arcStep = (curve / (seatCount - 1)) * DEG; // radians per seat\n const radius = seatSpacing / (2 * Math.sin(Math.abs(arcStep) / 2));\n // Centre above seat 0. φ measured from the downward vertical, growing with index.\n for (let i = 0; i < seatCount; i++) {\n const phi = i * arcStep;\n const lx = radius * Math.sin(phi);\n const ly = -radius + radius * Math.cos(phi); // ≤ 0 → ends rise toward -y\n out.push(place(lx, ly, rotation, origin));\n }\n return out;\n}\n\nfunction overrideMap(row: RowObject): Map<number, SeatOverride> {\n const m = new Map<number, SeatOverride>();\n if (row.overrides) for (const o of row.overrides) m.set(o.index, o);\n return m;\n}\n\n/** Sellable row slots: skipped slots are absent; empty wheelchair bays remain. */\nexport function rowInventoryCount(row: RowObject): number {\n const skipped = new Set((row.overrides ?? [])\n .filter((override) => override.skip && Number.isInteger(override.index)\n && override.index >= 0 && override.index < row.seatCount)\n .map((override) => override.index));\n return Math.max(0, row.seatCount - skipped.size);\n}\n\n/**\n * Every seat slot of a row INCLUDING skipped ones (designer seat-edit mode uses\n * this to draw un-skip handles). Overrides (dx/dy/label/categoryKey) are applied\n * but a skipped slot is flagged, not omitted.\n */\nexport interface RowSeatSlot {\n index: number;\n x: number;\n y: number;\n label: string;\n displayLabel: string;\n categoryKey: string;\n skipped: boolean;\n accessible: boolean;\n accessibility: AccessibilityType[];\n wheelchairSpaceType?: SeatOverride['wheelchairSpaceType'];\n commercial?: RowObject['commercial'];\n viewUrl?: string;\n labelStyle?: LabelStyle;\n}\n\n/** Every authored table-chair slot, including skipped inventory. This mirrors\n * row seat slots so Designer, MCP and buyer/event expansion share one semantic\n * source while retaining the table's stable numeric slot identity. */\nexport interface TableSeatSlot extends RowSeatSlot {\n side?: RectTableSide;\n}\n\n/**\n * Number outward from the middle: rank seats by distance from centre (inner-left\n * wins ties), so the centre seat gets rank 0 (the lowest number). Shared by the\n * `center` direction across every scheme.\n */\nfunction centerRank(n: number): number[] {\n const rank = new Array<number>(n);\n Array.from({ length: n }, (_, i) => i)\n .sort((a, b) => Math.abs(2 * a - (n - 1)) - Math.abs(2 * b - (n - 1)) || a - b)\n .forEach((idx, k) => (rank[idx] = k));\n return rank;\n}\n\n/**\n * The seat NUMBER part of a row seat's label (the row prefix is prepended by the\n * caller). Applies the row's numbering scheme, direction, step, start and label\n * prefix. Labels only — never geometry. See `RowObject.seatNumbering.scheme`.\n */\nexport function seatLabelPart(row: RowObject, i: number): string {\n const rawStart = row.seatLabelStart ?? 1;\n const dir = row.seatNumbering?.direction ?? 'ltr';\n const step = row.seatNumbering?.step ?? 1;\n const scheme = row.seatNumbering?.scheme ?? 'decimal';\n const prefix = row.seatNumbering?.prefix ?? '';\n const endAt = row.seatNumbering?.endAt;\n const n = row.seatCount;\n\n // Both up/down variants replace direction and number by physical left→right\n // order. `updown` is odd-up-even-back (1,3,5,…,6,4,2); the distinct reverse\n // variant is odd-back-even-up (…5,3,1,2,4,6). `start` shifts either sequence.\n // They own their sequence, so both ignore `endAt`.\n if (scheme === 'updown' || scheme === 'updown-descending') {\n const half = Math.ceil(n / 2);\n const core = scheme === 'updown'\n ? (i < half ? rawStart + 2 * i : rawStart - 1 + 2 * (n - i))\n : (i < half ? rawStart + 2 * (half - 1 - i) : rawStart + 1 + 2 * (i - half));\n return `${prefix}${core}`;\n }\n\n // End-at preset (\"useEndAt\"): derive `start` so the LAST-numbered seat\n // (position rank n-1) lands on `endAt`, honouring the scheme's effective step\n // (odd/even = 2). `endAt` wins over the stored `seatLabelStart`.\n const effStep = scheme === 'odd' || scheme === 'even' ? 2 : step;\n const start = endAt != null && Number.isFinite(endAt) ? endAt - (n - 1) * effStep : rawStart;\n\n // Position rank p ∈ [0, n-1]: the 0-based ordinal along the numbering\n // direction. Every remaining scheme is a formatting of `start + p*step`.\n const p = dir === 'center' ? centerRank(n)[i] : dir === 'rtl' ? n - 1 - i : i;\n\n let core: string;\n switch (scheme) {\n case 'odd': {\n const firstOdd = start % 2 === 1 ? start : start + 1;\n core = String(firstOdd + p * 2);\n break;\n }\n case 'even': {\n const firstEven = start % 2 === 0 ? start : start + 1;\n core = String(firstEven + p * 2);\n break;\n }\n case 'roman':\n core = toRoman(start + p * step);\n break;\n case 'letters-upper':\n core = toLetters(start + p * step, false);\n break;\n case 'letters-lower':\n core = toLetters(start + p * step, true);\n break;\n case 'decimal':\n default:\n core = String(start + p * step);\n break;\n }\n return `${prefix}${core}`;\n}\n\nexport function expandRowSlots(row: RowObject): RowSeatSlot[] {\n const ov = overrideMap(row);\n return rowSeatPositions(row).map((p, i) => {\n const o = ov.get(i);\n const accessibility = overrideAccessibility(o);\n const part = seatLabelPart(row, i);\n const inventoryLabel = o?.label ?? `${row.label}-${part}`;\n const displayPrefix = row.displayLabel ?? row.label;\n const commercial = { ...row.commercial, ...o?.commercial };\n return {\n index: i,\n x: p.x + (o?.dx ?? 0),\n y: p.y + (o?.dy ?? 0),\n label: inventoryLabel,\n displayLabel: o?.displayLabel ?? `${displayPrefix}-${part}`,\n categoryKey: o?.categoryKey ?? row.categoryKey,\n skipped: !!o?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n wheelchairSpaceType: o?.wheelchairSpaceType,\n commercial: Object.values(commercial).some((value) => value !== undefined && value !== false && value !== '') ? commercial : undefined,\n viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl,\n labelStyle: o?.labelStyle,\n };\n });\n}\n\nexport function expandRow(row: RowObject): ExpandedSeat[] {\n const seats: ExpandedSeat[] = [];\n for (const slot of expandRowSlots(row)) {\n if (slot.skipped) continue; // physical seat absent; numbering gap preserved\n seats.push({\n id: `${row.id}:${slot.index}`,\n label: slot.label,\n displayLabel: slot.displayLabel === slot.label ? undefined : slot.displayLabel,\n x: slot.x,\n y: slot.y,\n rowId: row.id,\n categoryKey: slot.categoryKey,\n accessible: slot.accessible || undefined,\n accessibility: slot.accessibility.length ? slot.accessibility : undefined,\n wheelchairSpaceType: slot.wheelchairSpaceType,\n commercial: slot.commercial,\n viewUrl: slot.viewUrl,\n labelStyle: slot.labelStyle,\n });\n }\n return seats;\n}\n\n/**\n * Expand a table into its perimeter seats.\n *\n * Round: seats spread evenly on a circle of radius `radius + 16`, the first at\n * angle `rotation` (degrees, clockwise from +x). Rect: seats line the top and\n * bottom edges (split evenly, any remainder to the top), 16u outside the edge,\n * the whole set rotated about the table centre.\n */\n/** Legacy rect tables distribute aggregate capacity round-robin across enabled\n * sides, then emit chairs in canonical top/bottom/left/right order. */\nexport function tableSeatCountsBySide(t: TableObject): RectTableSeatCounts {\n if (t.seatCountsBySide) return { ...t.seatCountsBySide };\n const enabled = t.sides && t.sides.length ? t.sides : ['top', 'bottom'];\n const order = (['top', 'bottom', 'left', 'right'] as const).filter((side) => enabled.includes(side));\n const counts: RectTableSeatCounts = { top: 0, bottom: 0, left: 0, right: 0 };\n if (!order.length) return counts;\n const n = Math.max(0, Math.round(t.seatCount));\n for (let index = 0; index < n; index++) counts[order[index % order.length]] += 1;\n return counts;\n}\n\n/** Expand every authored table chair, including skipped slots needed by the\n * Designer to restore inventory. */\nexport function expandTableSlots(t: TableObject): TableSeatSlot[] {\n const seats: TableSeatSlot[] = [];\n const n = Math.max(0, Math.round(t.seatCount));\n if (n === 0) return seats;\n const overrides = new Map((t.overrides ?? []).map((override) => [override.index, override]));\n const mk = (index: number, x: number, y: number, side?: RectTableSide): TableSeatSlot => {\n const override = overrides.get(index);\n const accessibility = overrideAccessibility(override);\n const label = override?.label ?? `${t.label}-${index + 1}`;\n const displayPrefix = t.displayLabel ?? t.label;\n return {\n index,\n label,\n displayLabel: override?.displayLabel ?? `${displayPrefix}-${index + 1}`,\n x: x + (override?.dx ?? 0),\n y: y + (override?.dy ?? 0),\n categoryKey: override?.categoryKey ?? t.categoryKey,\n skipped: !!override?.skip,\n accessible: accessibility.length > 0,\n accessibility,\n wheelchairSpaceType: override?.wheelchairSpaceType,\n commercial: override?.commercial,\n viewUrl: override?.viewFromSeatUrl,\n labelStyle: override?.labelStyle,\n ...(side ? { side } : {}),\n };\n };\n\n if (t.shape === 'round') {\n const R = (t.radius ?? 40) + TABLE_SEAT_OFFSET;\n const base = t.rotation * DEG;\n const arc = Math.max(0, Math.min(360, t.seatArc ?? 360));\n if (arc >= 360 || n === 1) {\n for (let i = 0; i < n; i++) {\n const a = base + (i / n) * 2 * Math.PI;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n const arcRad = arc * DEG;\n const halfGap = (2 * Math.PI - arcRad) / 2;\n const start = base + halfGap;\n for (let i = 0; i < n; i++) {\n const a = start + (i / (n - 1)) * arcRad;\n seats.push(mk(i, t.center.x + R * Math.cos(a), t.center.y + R * Math.sin(a)));\n }\n return seats;\n }\n\n const w = t.width ?? 80;\n const h = t.height ?? 50;\n const counts = tableSeatCountsBySide(t);\n const order = ['top', 'bottom', 'left', 'right'] as const;\n let idx = 0;\n for (const side of order) {\n const count = counts[side];\n for (let j = 0; j < count; j++) {\n let localX: number;\n let localY: number;\n if (side === 'top') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = -h / 2 - TABLE_SEAT_OFFSET;\n } else if (side === 'bottom') {\n localX = -w / 2 + ((j + 0.5) * w) / count;\n localY = h / 2 + TABLE_SEAT_OFFSET;\n } else if (side === 'left') {\n localX = -w / 2 - TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n } else {\n localX = w / 2 + TABLE_SEAT_OFFSET;\n localY = -h / 2 + ((j + 0.5) * h) / count;\n }\n const point = place(localX, localY, t.rotation, t.center);\n seats.push(mk(idx++, point.x, point.y, side));\n }\n }\n return seats;\n}\n\n/** Sellable individual table chairs. Grouped tables own one atomic inventory\n * unit elsewhere and therefore retain their full authored chair capacity. */\nexport function tableInventoryCount(t: TableObject): number {\n if (t.bookAsWhole || t.variableOccupancy) return Math.max(0, Math.round(t.seatCount));\n return expandTableSlots(t).filter((slot) => !slot.skipped).length;\n}\n\nexport function expandTable(t: TableObject): ExpandedSeat[] {\n return expandTableSlots(t).filter((slot) => !slot.skipped).map((slot) => ({\n id: `${t.id}:${slot.index}`,\n label: slot.label,\n ...(slot.displayLabel !== slot.label ? { displayLabel: slot.displayLabel } : {}),\n x: slot.x,\n y: slot.y,\n rowId: t.id,\n categoryKey: slot.categoryKey,\n ...(slot.accessible ? { accessible: true } : {}),\n ...(slot.accessibility.length ? { accessibility: slot.accessibility } : {}),\n ...(slot.wheelchairSpaceType ? { wheelchairSpaceType: slot.wheelchairSpaceType } : {}),\n ...(slot.commercial ? { commercial: slot.commercial } : {}),\n ...(slot.viewUrl ? { viewUrl: slot.viewUrl } : {}),\n ...(slot.labelStyle ? { labelStyle: slot.labelStyle } : {}),\n }));\n}\n\n/** Expand a booth into its single bookable block unit. */\nexport function expandBooth(b: BoothObject): ExpandedSeat[] {\n return [\n {\n id: `${b.id}:0`,\n label: b.label,\n ...(b.displayLabel && b.displayLabel !== b.label ? { displayLabel: b.displayLabel } : {}),\n x: b.center.x,\n y: b.center.y,\n rowId: b.id,\n categoryKey: b.categoryKey,\n kind: 'booth',\n },\n ];\n}\n\n/** Ray-cast point-in-polygon test — odd crossings ⇒ inside. */\nexport function pointInPolygon(p: Point, poly: Point[]): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const xi = poly[i].x;\n const yi = poly[i].y;\n const xj = poly[j].x;\n const yj = poly[j].y;\n const hit = yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;\n if (hit) inside = !inside;\n }\n return inside;\n}\n\nfunction pointOnPolygonBoundary(p: Point, poly: Point[]): boolean {\n return poly.some((start, index) => {\n const end = poly[(index + 1) % poly.length];\n const cross = (p.y - start.y) * (end.x - start.x) - (p.x - start.x) * (end.y - start.y);\n if (Math.abs(cross) > 1e-7) return false;\n const dot = (p.x - start.x) * (end.x - start.x) + (p.y - start.y) * (end.y - start.y);\n const lengthSquared = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;\n return dot >= -1e-7 && dot <= lengthSquared + 1e-7;\n });\n}\n\nexport function pointInPolygonWithHoles(p: Point, outer: Point[], holes: Point[][] | undefined): boolean {\n return pointInPolygon(p, outer)\n && !(holes ?? []).some((hole) => pointInPolygon(p, hole) || pointOnPolygonBoundary(p, hole));\n}\n\n/** Stable interior label anchor that cannot land inside a polygon cutout. */\nexport function polygonLabelPoint(outer: Point[], holes: Point[][] | undefined): Point {\n if (!outer.length) return { x: 0, y: 0 };\n const xs = outer.map((point) => point.x);\n const ys = outer.map((point) => point.y);\n const bounds = { minX: Math.min(...xs), maxX: Math.max(...xs), minY: Math.min(...ys), maxY: Math.max(...ys) };\n const centroid = polygonCentroid(outer);\n if (pointInPolygonWithHoles(centroid, outer, holes)) return centroid;\n let best = outer[0];\n let bestScore = -Infinity;\n const rings = [outer, ...(holes ?? [])];\n for (let row = 1; row < 24; row += 1) {\n for (let column = 1; column < 24; column += 1) {\n const point = {\n x: bounds.minX + ((bounds.maxX - bounds.minX) * column) / 24,\n y: bounds.minY + ((bounds.maxY - bounds.minY) * row) / 24,\n };\n if (!pointInPolygonWithHoles(point, outer, holes)) continue;\n const score = Math.min(...rings.flatMap((ring) => ring.map((start, index) => {\n const end = ring[(index + 1) % ring.length];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const denominator = dx * dx + dy * dy;\n const projection = denominator\n ? ((point.x - start.x) * dx + (point.y - start.y) * dy) / denominator\n : 0;\n const t = Math.max(0, Math.min(1, projection));\n return Math.hypot(point.x - (start.x + t * dx), point.y - (start.y + t * dy));\n })));\n if (score > bestScore) { best = point; bestScore = score; }\n }\n }\n return best;\n}\n\n/** Average of polygon vertices (v1 centroid — good enough for labels/membership). */\nfunction polygonCentroid(pts: Point[]): Point {\n if (!pts.length) return { x: 0, y: 0 };\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p.x;\n y += p.y;\n }\n return { x: x / pts.length, y: y / pts.length };\n}\n\n/**\n * Visual centre of any object — used for spatial section membership and for\n * rotating an object about its centre. Rows: centroid of expanded seats (or\n * origin when empty); tables/booths: centre; GA/section: polygon centroid;\n * shape: bbox centre; text: its position.\n */\nexport function objectCenter(o: ChartObject): Point {\n switch (o.type) {\n case 'row': {\n const seats = expandRow(o);\n if (!seats.length) return { x: o.origin.x, y: o.origin.y };\n let x = 0;\n let y = 0;\n for (const s of seats) {\n x += s.x;\n y += s.y;\n }\n return { x: x / seats.length, y: y / seats.length };\n }\n case 'table':\n case 'booth':\n return { x: o.center.x, y: o.center.y };\n case 'gaArea':\n return polygonCentroid(o.points);\n case 'section':\n return polygonCentroid(o.outline);\n case 'text':\n return { x: o.position.x, y: o.position.y };\n case 'shape':\n if (o.points && o.points.length) return polygonCentroid(o.points);\n if (o.x != null && o.y != null && o.width != null && o.height != null) {\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n return { x: o.x ?? 0, y: o.y ?? 0 };\n case 'decorImage':\n return { x: o.x + o.width / 2, y: o.y + o.height / 2 };\n }\n}\n\nfunction samePoints(left: Point[], right: Point[]): boolean {\n return left.length === right.length\n && left.every((point, index) => point.x === right[index].x && point.y === right[index].y);\n}\n\nfunction sameGASurfaceAsSection(object: ChartObject, section: SectionObject): boolean {\n if (object.type !== 'gaArea' || !samePoints(object.points, section.outline)) return false;\n const objectHoles = object.holes ?? [];\n const sectionHoles = section.holes ?? [];\n return objectHoles.length === sectionHoles.length\n && objectHoles.every((hole, index) => samePoints(hole, sectionHoles[index]));\n}\n\n/**\n * Resolve one bookable object's owning physical section using the canonical\n * first-match rule. Generated reference inventory may name a logical section,\n * but that provenance is trusted only when the stored geometry confirms it.\n * Keeping this primitive in layout lets section inventory, category painting,\n * and buyer view inheritance share one ownership decision.\n */\nexport function owningSectionForObject(\n objects: ChartObject[],\n object: ChartObject,\n): SectionObject | undefined {\n const sections = objects.filter((candidate): candidate is SectionObject => candidate.type === 'section');\n const referencedLogicalId = 'referenceInventorySource' in object\n ? object.referenceInventorySource?.logicalSectionId\n : undefined;\n const center = objectCenter(object);\n const referencedOwner = referencedLogicalId\n ? sections.find((section) => (\n (section.logicalSectionId ?? section.id) === referencedLogicalId\n && (sameGASurfaceAsSection(object, section)\n || pointInPolygonWithHoles(center, section.outline, section.holes))\n ))\n : undefined;\n return referencedOwner\n ?? sections.find((section) => pointInPolygonWithHoles(center, section.outline, section.holes));\n}\n\n/**\n * Normalized floor list (Batch 5): a multi-floor chart's `floors`, or a synthetic\n * single floor wrapping a single-floor chart's `objects`. Every consumer that needs\n * to reason about floors goes through this so single-floor charts stay untouched.\n */\nexport function floorsOf(doc: ChartDoc): Floor[] {\n if (doc.floors && doc.floors.length) return doc.floors;\n return [{\n id: 'floor-0',\n name: 'Main',\n objects: doc.objects,\n focalPoint: doc.focalPoint,\n referenceImage: doc.referenceImage,\n backgroundImage: doc.backgroundImage,\n }];\n}\n\n/** Objects of one floor by id (defaults to the first floor). */\nexport function floorObjects(doc: ChartDoc, floorId?: string): ChartObject[] {\n const floors = floorsOf(doc);\n return (floorId ? floors.find((f) => f.id === floorId) : floors[0])?.objects ?? [];\n}\n\n/** Every object across ALL floors — the whole venue (single-floor = `doc.objects`). */\nexport function allObjects(doc: ChartDoc): ChartObject[] {\n return doc.floors && doc.floors.length ? doc.floors.flatMap((f) => f.objects) : doc.objects;\n}\n\n/** A copy of an object translated by (dx, dy) — every coordinate field shifted. */\nfunction translateObject(o: ChartObject, dx: number, dy: number): ChartObject {\n const p = (pt: Point): Point => ({ x: pt.x + dx, y: pt.y + dy });\n const pts = (a: Point[]): Point[] => a.map(p);\n switch (o.type) {\n case 'row':\n return { ...o, origin: p(o.origin) };\n case 'table':\n case 'booth':\n return { ...o, center: p(o.center) };\n case 'gaArea':\n return { ...o, points: pts(o.points), ...(o.holes ? { holes: o.holes.map(pts) } : {}) };\n case 'section':\n return {\n ...o,\n outline: pts(o.outline),\n ...(o.outlinePath ? { outlinePath: translateSectionOutlinePath(o.outlinePath, dx, dy) } : {}),\n ...(o.holes ? { holes: o.holes.map(pts) } : {}),\n };\n case 'text':\n return { ...o, position: p(o.position) };\n case 'shape':\n return {\n ...o,\n ...(o.points ? { points: pts(o.points) } : {}),\n ...(o.x != null ? { x: o.x + dx } : {}),\n ...(o.y != null ? { y: o.y + dy } : {}),\n };\n case 'decorImage':\n return { ...o, x: o.x + dx, y: o.y + dy };\n }\n}\n\n/**\n * Multi-floor 3D stack (Batch 5): flatten every floor into ONE doc with floor `i`\n * lifted by `i * spread` in −y, so the isometric view shows the floors as stacked\n * decks (ground at the bottom). Returns a single-floor doc (no `floors`). Meant\n * only for the 3D overview render — 2D still shows one floor via `floorObjects`.\n */\nexport function stackFloors(doc: ChartDoc, spread = 900): ChartDoc {\n if (!doc.floors || doc.floors.length < 2) return doc;\n const objects: ChartObject[] = [];\n doc.floors.forEach((f, i) => {\n const dy = -i * spread;\n for (const o of f.objects) objects.push(dy === 0 ? o : translateObject(o, 0, dy));\n });\n return { ...doc, objects, floors: undefined };\n}\n\nexport interface ExpandChartOptions {\n /** Physical height for a single-floor projection extracted from a multi-floor\n * document. Full multi-floor documents resolve each floor directly. */\n floorBaseHeightM?: number;\n}\n\nfunction expandFloorObjects(\n objects: ChartObject[],\n zones: ChartDoc['zones'],\n fallbackFocal: Point | undefined,\n): ExpandedSeat[] {\n const out: ExpandedSeat[] = [];\n const segmented = new Map<string, {\n groupId: string;\n adjacencyOffset: number;\n displayOffset: number;\n displayLabel: string;\n totalSeats: number;\n canonical: RowObject;\n viewFromSeatUrl?: string;\n }>();\n\n // Resolve only complete, internally coherent groups. Malformed metadata is\n // surfaced by validation and deliberately falls back to physical-row\n // semantics here, so a corrupt document can never make buyer adjacency more\n // permissive than the legacy model.\n const grouped = new Map<string, RowObject[]>();\n for (const object of objects) {\n if (object.type !== 'row' || !object.segmentedRow) continue;\n const list = grouped.get(object.segmentedRow.groupId) ?? [];\n list.push(object);\n grouped.set(object.segmentedRow.groupId, list);\n }\n for (const [groupId, members] of grouped) {\n const ordered = members.slice().sort((left, right) => (\n left.segmentedRow!.componentIndex - right.segmentedRow!.componentIndex\n ));\n const expectedCount = ordered[0]?.segmentedRow?.componentCount ?? 0;\n const first = ordered[0]?.segmentedRow;\n if (!first) continue;\n const valid = expectedCount >= 2\n && ordered.length === expectedCount\n && first?.boundaryBefore === 'start'\n && ordered.every((row, index) => (\n row.segmentedRow?.kind === 'segmented-row-v1'\n && row.segmentedRow.groupId === groupId\n && row.segmentedRow.componentCount === expectedCount\n && row.segmentedRow.componentIndex === index\n && (index === 0\n ? row.segmentedRow.boundaryBefore === 'start'\n : row.segmentedRow.boundaryBefore !== 'start')\n && row.segmentedRow.displayLabel === first.displayLabel\n ));\n if (!valid) continue;\n const totalSeats = ordered.reduce((sum, row) => sum + row.seatCount, 0);\n let adjacencyOffset = 0;\n let displayOffset = 0;\n for (const row of ordered) {\n if (row.segmentedRow!.boundaryBefore === 'break') adjacencyOffset += 1;\n segmented.set(row.id, {\n groupId,\n adjacencyOffset,\n displayOffset,\n displayLabel: first.displayLabel,\n totalSeats,\n canonical: ordered[0],\n viewFromSeatUrl: first.viewFromSeatUrl,\n });\n adjacencyOffset += row.seatCount;\n displayOffset += row.seatCount;\n }\n }\n\n for (const obj of objects) {\n let seats: ExpandedSeat[] = [];\n if (obj.type === 'row') seats = expandRow(obj);\n else if (obj.type === 'table') seats = expandTable(obj);\n else if (obj.type === 'booth') seats = expandBooth(obj);\n if (!seats.length) continue;\n if (obj.type === 'row') {\n const logical = segmented.get(obj.id);\n if (logical) {\n const overrides = new Map((obj.overrides ?? []).map((override) => [override.index, override]));\n for (const seat of seats) {\n const physicalIndex = Number(seat.id.slice(seat.id.lastIndexOf(':') + 1));\n if (!Number.isInteger(physicalIndex)) continue;\n const displayOrdinal = logical.displayOffset + physicalIndex;\n seat.logicalRowId = logical.groupId;\n seat.logicalSeatIndex = logical.adjacencyOffset + physicalIndex;\n // A seat-level display override remains the highest-precedence copy.\n if (!overrides.get(physicalIndex)?.displayLabel) {\n const numberingRow: RowObject = {\n ...logical.canonical,\n seatCount: logical.totalSeats,\n label: logical.displayLabel,\n displayLabel: logical.displayLabel,\n };\n seat.displayLabel = `${logical.displayLabel}-${seatLabelPart(numberingRow, displayOrdinal)}`;\n }\n seat.viewUrl ??= logical.viewFromSeatUrl;\n }\n }\n }\n const owner = owningSectionForObject(objects, obj);\n const inheritedView = owner?.viewFromSeatUrl;\n const zone = owner?.zone ? zones?.find((candidate) => candidate.id === owner.zone) : undefined;\n const resolvedFocal = zone?.focalPoint ?? fallbackFocal;\n for (const seat of seats) {\n if (inheritedView) seat.viewUrl ??= inheritedView;\n if (owner) seat.sectionId = owner.logicalSectionId ?? owner.id;\n if (owner?.zone) seat.zoneId = owner.zone;\n if (resolvedFocal) seat.focalPoint = { ...resolvedFocal };\n }\n out.push(...seats);\n }\n return out;\n}\n\n/** Expand every seat-bearing object across all floors (rows, tables, booths).\n * Multi-floor ownership is resolved one floor at a time: local coordinates may\n * overlap between floors and must never assign a seat to another floor's section. */\nexport function expandChart(doc: ChartDoc, options: ExpandChartOptions = {}): ExpandedSeat[] {\n if (doc.floors?.length) {\n const out: ExpandedSeat[] = [];\n for (const floor of doc.floors) {\n const floorFocal = floor.focalPoint ?? doc.focalPoint;\n const seats = expandFloorObjects(floor.objects, doc.zones, floorFocal);\n assignEyeHeights(floor.objects, floor.focalPoint ?? doc.focalPoint, floor.baseHeightM ?? 0, seats);\n out.push(...seats);\n }\n return out;\n }\n const out = expandFloorObjects(doc.objects, doc.zones, doc.focalPoint);\n assignEyeHeights(doc.objects, doc.focalPoint, options.floorBaseHeightM ?? 0, out);\n return out;\n}\n\n/**\n * Phase B2: annotate each expanded seat with a real-world eye height (metres above\n * the focal/stage datum) for the auto-360° generator. Resolved once at expand time\n * — never per render frame — so the 13k-seat render path pays no cost.\n *\n * `eyeHeightM = section front-edge height + row rise + seated eye height`, where\n * the ROW RISE is derived from the seat's DRAWN radial depth into its section\n * (chart units → metres × tan(rake)), NOT a hard-coded row pitch. Deriving rise\n * from drawn geometry (the same distances the panorama already uses horizontally)\n * is the binding fix for the 30–40% under-rise the sightline de-risk study flagged\n * (docs/3d-sightline-derisk-2026-07-21.md §7).\n *\n * A chart with no elevated/raked/height-authored section skips the spatial pass\n * entirely and every seat resolves to the flat seated-eye baseline — so legacy\n * charts stay pixel-identical and `expandChart`'s other callers pay nothing.\n */\nfunction assignEyeHeights(\n objects: ChartObject[],\n focal: Point | undefined,\n floorBaseHeightM: number,\n seats: ExpandedSeat[],\n): void {\n const sections = objects.filter((o): o is SectionObject => o.type === 'section');\n const hasGeometry = floorBaseHeightM > 0\n || sections.some((s) => s.height !== undefined || s.rake !== undefined || (s.elevation ?? 0) > 0);\n if (!sections.length || !hasGeometry || !focal) {\n for (const seat of seats) seat.eyeHeightM = floorBaseHeightM + SEATED_EYE_HEIGHT_M;\n return;\n }\n // Pass 1: owning section (first drawn section containing the seat) + the drawn\n // distance of the section's front edge (nearest member to the focal point).\n const owner = new Array<SectionObject | null>(seats.length);\n const geo = new Map<string, { height: number; rake: number }>();\n const frontDistU = new Map<string, number>();\n for (let i = 0; i < seats.length; i++) {\n const seat = seats[i];\n const sec = sections.find((s) => pointInPolygonWithHoles({ x: seat.x, y: seat.y }, s.outline, s.holes)) ?? null;\n owner[i] = sec;\n if (!sec) continue;\n if (!geo.has(sec.id)) geo.set(sec.id, sectionGeometry(sec, { floorBaseHeightM }));\n const seatFocal = seat.focalPoint ?? focal;\n const d = Math.hypot(seat.x - seatFocal.x, seat.y - seatFocal.y);\n const cur = frontDistU.get(sec.id);\n if (cur === undefined || d < cur) frontDistU.set(sec.id, d);\n }\n // Pass 2: front-edge height + drawn-depth rise + seated eye.\n for (let i = 0; i < seats.length; i++) {\n const seat = seats[i];\n const sec = owner[i];\n if (!sec) { seat.eyeHeightM = floorBaseHeightM + SEATED_EYE_HEIGHT_M; continue; }\n const g = geo.get(sec.id)!;\n let riseM = 0;\n if (g.rake > 0) {\n const seatFocal = seat.focalPoint ?? focal;\n const d = Math.hypot(seat.x - seatFocal.x, seat.y - seatFocal.y);\n const depthU = Math.max(0, d - (frontDistU.get(sec.id) ?? d));\n riseM = depthU * METRES_PER_CHART_UNIT * Math.tan((g.rake * Math.PI) / 180);\n }\n seat.eyeHeightM = g.height + riseM + SEATED_EYE_HEIGHT_M;\n }\n}\n\nconst PAD = 40;\n\n/** Axis-aligned bounds over every object plus the background image, with padding. */\nexport function chartBounds(doc: ChartDoc): { x: number; y: number; width: number; height: number } {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n const acc = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n };\n\n for (const s of expandChart(doc)) acc(s.x, s.y);\n\n for (const obj of allObjects(doc)) {\n if (obj.type === 'gaArea') {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.type === 'section') {\n for (const p of obj.outline) acc(p.x, p.y);\n } else if (obj.type === 'decorImage') {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n } else if (obj.type === 'shape') {\n if (obj.points && obj.points.length) {\n for (const p of obj.points) acc(p.x, p.y);\n } else if (obj.x != null && obj.y != null && obj.width != null && obj.height != null) {\n acc(obj.x, obj.y);\n acc(obj.x + obj.width, obj.y + obj.height);\n }\n } else if (obj.type === 'table') {\n const off = TABLE_SEAT_OFFSET + SEAT_R;\n const ext =\n obj.shape === 'round'\n ? (obj.radius ?? 40) + off\n : Math.max((obj.width ?? 80) / 2, (obj.height ?? 50) / 2) + off; // rotation-agnostic over-approximation\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'booth') {\n const ext = Math.max(obj.width, obj.height) / 2;\n acc(obj.center.x - ext, obj.center.y - ext);\n acc(obj.center.x + ext, obj.center.y + ext);\n } else if (obj.type === 'text') {\n const w = obj.fontSize * obj.text.length * 0.6; // approximate glyph advance\n acc(obj.position.x, obj.position.y);\n acc(obj.position.x + w, obj.position.y + obj.fontSize);\n }\n }\n\n for (const image of [doc.referenceImage, doc.backgroundImage]) {\n if (!image) continue;\n const { center, width } = image;\n const bh = (width * 3) / 4; // assume 4:3 when the true aspect is unknown at bounds-time\n acc(center.x - width / 2, center.y - bh / 2);\n acc(center.x + width / 2, center.y + bh / 2);\n }\n\n // Empty document → a sane default box around the focal point.\n if (!isFinite(minX)) {\n const f = doc.focalPoint ?? { x: 0, y: 0 };\n return { x: f.x - 200, y: f.y - 200, width: 400, height: 400 };\n }\n\n return {\n x: minX - PAD,\n y: minY - PAD,\n width: maxX - minX + PAD * 2,\n height: maxY - minY + PAD * 2,\n };\n}\n","import type { ChartDoc, GAAreaObject, 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 */\nexport function stateAwareBookableLabelInk(fill: string, preferred: string): string {\n const preferredContrast = renderedTextContrast(preferred, fill);\n if (preferredContrast != null && preferredContrast >= SMALL_TEXT_CONTRAST) return preferred;\n const darkContrast = renderedTextContrast(DARK_BOOKABLE_LABEL_INK, fill) ?? 0;\n const lightContrast = renderedTextContrast(LIGHT_BOOKABLE_LABEL_INK, fill) ?? 0;\n if (darkContrast === 0 && lightContrast === 0) return preferred;\n return darkContrast >= lightContrast ? DARK_BOOKABLE_LABEL_INK : LIGHT_BOOKABLE_LABEL_INK;\n}\n\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): LabelInkContrastSummary {\n const preferredValid = OPAQUE_HEX.test(preferred.trim());\n const preferredHex = preferred.trim().toLowerCase();\n let total = 0;\n let overridden = 0;\n let overrideInk: string | null = null;\n for (const fill of backgrounds) {\n if (!preferredValid || !OPAQUE_HEX.test(fill.trim())) continue;\n total += 1;\n const ink = stateAwareBookableLabelInk(fill, preferred);\n if (ink.toLowerCase() !== preferredHex) {\n overridden += 1;\n overrideInk = ink;\n }\n }\n const status = total === 0 ? 'none'\n : overridden === 0 ? 'applies'\n : overridden === total ? 'overridden'\n : 'mixed';\n return { total, overridden, status, overrideInk };\n}\n","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 { 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 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/**\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;\nconst SECTION_STROKE_PX = 2;\nconst LIGHT_OVERVIEW_SECTION_FILL = '#e5e7eb';\nconst LIGHT_OVERVIEW_SECTION_STROKE = '#c7cbd1';\nconst LIGHT_OVERVIEW_SECTION_INK = '#595f69';\nconst LIGHT_OVERVIEW_FOCAL_FILL = '#d1d5db';\nconst LIGHT_OVERVIEW_FOCAL_STROKE = '#b8bdc4';\nconst DARK_OVERVIEW_SECTION_FILL = '#273142';\nconst DARK_OVERVIEW_SECTION_STROKE = '#526078';\nconst DARK_OVERVIEW_SECTION_INK = '#f1f5f9';\nconst DARK_OVERVIEW_FOCAL_FILL = '#374151';\nconst DARK_OVERVIEW_FOCAL_STROKE = '#64748b';\n/** Screen-space target sizes (px) for scale-compensated section/zone labels. */\nconst SECTION_LABEL_PX = 20;\nconst MIN_SECTION_LABEL_PX = 12;\nconst ZONE_LABEL_PX = 18;\nconst ZONE_SUB_PX = 12;\nconst HIERARCHY_PILL_BACKGROUND = '#111827';\n\nconst HELD_FILL = '#6b7280';\nconst TAKEN_FILL = '#374151';\nconst NFS_STROKE = '#4b5563';\n/** Phase 2 event-level `closed` section: a flat desaturated slate block (label\n * kept), distinct from the per-seat availability-grey. Seats inside read grey\n * at 40% and are not pickable (per chart-design-standards §3). */\nconst CLOSED_SEAT_FILL = '#4b5563';\nconst CLOSED_SEAT_OPACITY = 0.4;\n/** AXS section-focus: non-focused sections dim to this opacity. */\nconst FOCUS_DIM_OPACITY = 0.16;\n/** Light/neutral backdrop panel drawn behind the focused section's seats. */\nconst FOCUS_BACKDROP_FILL = 'rgba(244,246,248,0.06)';\n/** Okabe-Ito colorblind-safe hues (black dropped — unreadable on dark charts).\n * Categories 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\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/** Centre-first interior anchors used when a hole/concavity occupies the shell centre. */\nfunction polygonLabelCandidates(outer: Point[], holes: Point[][], preferred: Point): Point[] {\n const bounds = polyBounds(outer);\n const centre = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n const points: Point[] = [preferred];\n for (let row = 1; row < 12; row += 1) {\n for (let column = 1; column < 12; column += 1) {\n const point = {\n x: bounds.x + bounds.width * column / 12,\n y: bounds.y + bounds.height * row / 12,\n };\n if (pointInPolygonWithHoles(point, outer, holes)) points.push(point);\n }\n }\n return points\n .sort((left, right) => Math.hypot(left.x - centre.x, left.y - centre.y)\n - Math.hypot(right.x - centre.x, right.y - centre.y))\n .filter((point, index, all) => index === all.findIndex((other) => (\n Math.abs(other.x - point.x) < 1e-6 && Math.abs(other.y - point.y) < 1e-6\n )));\n}\n\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 centre-first alternatives for concave/holed label fitting. */\n labelAnchors: Point[];\n zone?: string;\n /** Seats whose centre falls inside the outline (first-match, doc order). */\n memberIds: string[];\n total: number;\n free: number;\n /** Category-mix (or explicit override) fill BEFORE the availability tint. */\n baseFill: string;\n outlineTint: string;\n /** Faint outline drawn under seats — the existing near-zoom look, untouched. */\n outlinePoly: Shape;\n /** Solid block fill that melts in at the block rung. */\n blockPoly: Shape;\n /** Section name (always drawn; brightens at the block rung, hides at zone rung). */\n nameLabel: Text;\n /** Availability retained for focused/detail UI, never painted on the overview shell. */\n subLabel: Text;\n /** Preferred name ink (labelStyle.color or the overview default) fed through\n * auto-contrast each frame so an authored colour survives the block melt. */\n preferredInk: string;\n /** labelStyle.size relative to the default (1 = default), scaling the fitted\n * screen-px band so a larger authored label reads larger in the overview. */\n labelScale: number;\n /** Responsive fit decisions for the current stage scale and local polygon span. */\n nameLabelFits: boolean;\n subLabelFits: boolean;\n /** Tier height (0 = floor). Lifts the section + members in iso (\"3D\") view. */\n elevation: number;\n /**\n * 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\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: Array<{ text: string; x: number; y: number; rotation: number; fontSize: number; ink: string; opacity: number }> = [];\n /** Category order from the doc — the stable index into the CB palette. */\n private catOrder: string[] = [];\n\n private selection = new Set<string>();\n /** Whole-seat/block selection markers: outline + non-colour check cue. */\n private selectionMarkers = new Map<string, Group>();\n /** Held by this picker instance, not by another buyer. */\n private ownedHold = new Set<string>();\n /** One selected seat being inspected before it is committed to the cart. */\n private selectionFocusId: string | null = null;\n private hoverRing: Circle;\n /** 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\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.currency = options.currency;\n\n Konva.pixelRatio = this.dpr;\n\n this.stage = new Stage({\n container,\n width: container.clientWidth || 1,\n height: container.clientHeight || 1,\n draggable: false, // pan/pinch are ours, via pointer events\n });\n\n container.style.touchAction = 'none';\n container.addEventListener('pointerdown', this.onPointerDown, { passive: false });\n container.addEventListener('pointermove', this.onPointerMove, { passive: false });\n container.addEventListener('pointerup', this.onPointerEnd, { passive: false });\n container.addEventListener('pointercancel', this.onPointerEnd, { passive: false });\n\n // Keyboard accessibility: the canvas is focusable and navigable seat-by-seat.\n if (container.tabIndex < 0) container.tabIndex = 0;\n container.setAttribute('role', 'application');\n if (!container.getAttribute('aria-label')) {\n container.setAttribute('aria-label', t('map.aria'));\n }\n container.addEventListener('keydown', this.onKeyDown);\n\n this.bgLayer = new Layer({ listening: true });\n this.seatLayer = new Layer({ listening: true });\n this.overlayLayer = new Layer({ listening: false });\n this.labelGroup = new Group({ listening: false });\n this.overlayLayer.add(this.labelGroup);\n // 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\n this.wireInteraction();\n this.startFpsLoop();\n\n if (import.meta.env.DEV) {\n (window as unknown as Record<string, unknown>).__seatmap = this;\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObs = new ResizeObserver(() => this.handleResize());\n this.resizeObs.observe(container);\n }\n }\n\n // ---- ISeatmapRenderer -----------------------------------------------------\n\n setChart(doc: ChartDoc, opts?: { floorId?: string }): void {\n // Multi-floor: render the active floor (2D) or all floors stacked (3D). `view`\n // scopes the chart accordingly — single-floor charts pass through (=== doc).\n // A fresh chart (new ref) resets to 2D; a re-render (same ref) preserves the mode.\n if (doc !== this.chartDoc) this.stacked = false;\n this.chartDoc = doc;\n this.activeFloorId = opts?.floorId ?? floorsOf(doc)[0].id;\n // Object id → floor id, for resolving which deck a tap hit in the 3D stack\n // (stackFloors keeps object ids, so the map holds across the flatten).\n this.objectFloor.clear();\n if (doc.floors && doc.floors.length > 1) {\n for (const f of doc.floors) for (const o of f.objects) this.objectFloor.set(o.id, f.id);\n }\n const view = this.floorView(doc);\n this.focusedId = null;\n this.focusRing.visible(false);\n this.bgLayer.destroyChildren();\n this.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(true);\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: true });\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 = ga.sectionId != null && this.effScale() < CACHE_THRESHOLD;\n ga.polygon.opacity(overviewHidden\n ? 0\n : this.gaCategoryDimmed(ga.categoryKey)\n ? GA_FILL_OPACITY * 0.08\n : GA_FILL_OPACITY);\n // A legend hover is only visual; a price-filter exclusion is not sellable\n // from the map until the filter is cleared.\n ga.polygon.listening(!overviewHidden && !filteredOut);\n }\n }\n\n /** Frame the currently available inventory that survived a buyer price\n * filter. Clearing the filter glides back to the full venue. */\n focusCategories(keys: string[] | null): void {\n if (!keys?.length) {\n this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });\n return;\n }\n const wanted = new Set(keys);\n const matching = this.seats.filter((seat) => {\n if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;\n const status = this.statusById.get(seat.id) ?? 'free';\n return status === 'free' || this.ownedHold.has(seat.id);\n });\n if (!matching.length) return;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const seat of matching) {\n 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 if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.isoRaf) cancelAnimationFrame(this.isoRaf);\n if (this.glideRaf) cancelAnimationFrame(this.glideRaf);\n if (this.viewChangeRaf) cancelAnimationFrame(this.viewChangeRaf);\n if (this.recacheTimer) clearTimeout(this.recacheTimer);\n this.resizeObs?.disconnect();\n this.container.removeEventListener('pointerdown', this.onPointerDown);\n this.container.removeEventListener('pointermove', this.onPointerMove);\n this.container.removeEventListener('pointerup', this.onPointerEnd);\n this.container.removeEventListener('pointercancel', this.onPointerEnd);\n this.container.removeEventListener('keydown', this.onKeyDown);\n this.stage.destroy();\n }\n\n // ---- rendering ------------------------------------------------------------\n\n /** Theme font stack for all rendered text (falls back to Inter). */\n private labelFont(): string {\n return this.theme.fontFamily || 'Inter, sans-serif';\n }\n\n /**\n * Where a seat's nodes live: an elevated section's lift group (so the whole\n * tier shifts with one offset in iso view) or the seat layer directly.\n */\n private seatContainer(id: string): Group | Layer {\n return this.seatSection.get(id)?.liftGroupSeat ?? this.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.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 (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));\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(stateAwareBookableLabelInk(typeof fill === 'string' ? fill : '', '#ffffff'));\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 /** Organizer floor-plan photo, dimmed, at the very bottom of the bg layer. */\n private renderBackgroundImage(bg: NonNullable<ChartDoc['backgroundImage']>): void {\n if (!bg.url || bg.visible === false) return;\n const img = new window.Image();\n img.onload = () => {\n const natW = img.naturalWidth || 4;\n const natH = img.naturalHeight || 3;\n const rawCrop = bg.crop ?? { x: 0, y: 0, width: 1, height: 1 };\n const cropX = Math.max(0, Math.min(0.99, rawCrop.x));\n const cropY = Math.max(0, Math.min(0.99, rawCrop.y));\n const crop = {\n x: cropX,\n y: cropY,\n width: Math.max(0.01, Math.min(1 - cropX, rawCrop.width)),\n height: Math.max(0.01, Math.min(1 - cropY, rawCrop.height)),\n };\n const w = bg.width;\n const h = w * ((natH * crop.height) / (natW * crop.width));\n const node = new KImage({\n image: img,\n x: bg.center.x,\n y: bg.center.y,\n offsetX: w / 2,\n offsetY: h / 2,\n width: w,\n height: h,\n rotation: bg.rotation ?? 0,\n crop: {\n x: crop.x * natW,\n y: crop.y * natH,\n width: crop.width * natW,\n height: crop.height * natH,\n },\n opacity: bg.opacity,\n listening: false,\n });\n this.bgLayer.add(node);\n node.moveToBottom();\n this.bgLayer.batchDraw();\n };\n img.src = bg.url;\n }\n\n /**\n * A decor graphic (rink / court / stage art). The KImage node is added to the\n * bgLayer synchronously so it keeps its z-slot beneath the sections drawn right\n * after; the bitmap is decoded async and pasted in on load. A single node = a\n * single drawImage per frame, and it rides the same layer cache — effectively\n * zero per-frame cost. Never listens, so it can't intercept a seat click.\n */\n private renderDecorImage(obj: Extract<ChartDoc['objects'][number], { type: 'decorImage' }>): void {\n // Pass the (not-yet-loaded) Image element as the node's image: Konva draws\n // nothing until it decodes, then onload triggers a repaint. Keeps the node's\n // z-slot fixed beneath the sections drawn immediately after.\n const img = new window.Image();\n const node = new KImage({\n image: img,\n x: obj.x + obj.width / 2,\n y: obj.y + obj.height / 2,\n offsetX: obj.width / 2,\n offsetY: obj.height / 2,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation ?? 0,\n opacity: clamp(obj.opacity ?? 1, 0, 1),\n listening: false,\n perfectDrawEnabled: false,\n });\n // 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 img.onload = () => {\n const layer = node.getLayer();\n if (!layer) return; // chart swapped out before the image loaded\n layer.batchDraw();\n };\n img.src = obj.href;\n }\n\n private renderTable(obj: Extract<ChartDoc['objects'][number], { type: 'table' }>): void {\n if (obj.shape === 'round') {\n this.bgLayer.add(\n new Circle({\n x: obj.center.x,\n y: obj.center.y,\n radius: obj.radius ?? 40,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n listening: false,\n }),\n );\n } else {\n const w = obj.width ?? 80;\n const h = obj.height ?? 50;\n this.bgLayer.add(\n new Rect({\n x: obj.center.x,\n y: obj.center.y,\n width: w,\n height: h,\n offsetX: w / 2,\n offsetY: h / 2,\n rotation: obj.rotation,\n fill: '#232c40',\n stroke: '#2a3348',\n strokeWidth: 1.5,\n cornerRadius: 4,\n listening: false,\n }),\n );\n }\n const label = this.addCentredLabel(this.bgLayer, obj.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.75,\n fill: rgba(outlineTint, 0.08),\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(outlinePoly);\n\n // Neutral overview shell — category paint is intentionally deferred until\n // focus/seat detail so the venue hierarchy remains legible at first glance.\n const blockPoly = polygonWithHolesShape(obj.outline, obj.holes, {\n fill: palette.sectionFill,\n stroke: palette.sectionStroke,\n strokeWidth: SECTION_STROKE_PX,\n opacity: 0,\n listening: false,\n }, obj.outlinePath);\n bgTarget.add(blockPoly);\n\n // Per-section label overrides (size/color) layered on the overview defaults.\n // color becomes the preferred ink the block-melt loop auto-contrasts each\n // frame; size scales the fitted screen-px band (default section size = 18).\n const labelStyle = obj.labelPresentation?.labelStyle;\n const preferredInk = labelStyle?.color ?? palette.sectionInk;\n const labelScale = (labelStyle?.size ?? 18) / 18;\n const nameLabel = new Text({\n x: obj.labelPresentation?.position?.x ?? centroid.x,\n y: obj.labelPresentation?.position?.y ?? centroid.y,\n text: obj.displayLabel ?? obj.label,\n rotation: obj.labelPresentation?.rotation ?? 0,\n visible: obj.labelPresentation?.visible !== false,\n fontSize: 22 * labelScale,\n fontStyle: '700',\n fontFamily: this.labelFont(),\n fill: stateAwareBookableLabelInk(palette.sectionFill, preferredInk),\n listening: false,\n perfectDrawEnabled: false,\n });\n nameLabel.offsetX(nameLabel.width() / 2);\n nameLabel.offsetY(nameLabel.height() / 2);\n bgTarget.add(nameLabel);\n\n const subLabel = new Text({\n x: centroid.x,\n y: centroid.y,\n text: t('map.seatsLeft', { count: free }),\n fontSize: 12,\n fontStyle: '700',\n fontFamily: 'JetBrains Mono, ui-monospace, monospace',\n fill: palette.sectionInk,\n opacity: 0,\n listening: false,\n perfectDrawEnabled: false,\n });\n subLabel.offsetX(subLabel.width() / 2);\n bgTarget.add(subLabel);\n\n const sec: SectionRender = {\n id: obj.id,\n logicalId: obj.logicalSectionId ?? obj.id,\n label: obj.displayLabel ?? obj.label,\n outline: obj.outline,\n ...(obj.outlinePath ? { outlinePath: obj.outlinePath } : {}),\n holes: obj.holes ?? [],\n centroid,\n labelAnchors: polygonLabelCandidates(obj.outline, obj.holes ?? [], centroid),\n zone: obj.zone,\n memberIds,\n total: memberIds.length,\n free,\n baseFill,\n outlineTint,\n outlinePoly,\n blockPoly,\n nameLabel,\n subLabel,\n preferredInk,\n labelScale,\n nameLabelFits: true,\n subLabelFits: true,\n elevation,\n 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. Section names\n * are already proven inside disjoint shells, so they must not cull each other.\n */\n private decollideRungLabels(sx: number): void {\n const GAP = 4;\n interface Cand { node: Text; tier: number; section: boolean; box: { x: number; y: number; w: number; h: number } }\n const cands: Cand[] = [];\n const boxOf = (t: Text): { x: number; y: number; w: number; h: number } => {\n const p = this.worldToScreen({ x: t.x(), y: t.y() });\n const rotated = pointsBounds(rotatedRectPoints(\n { x: 0, y: 0 },\n t.width() * sx,\n t.height() * sx,\n t.rotation(),\n ));\n const w = rotated.width;\n const h = rotated.height;\n return { x: p.x - w / 2, y: p.y - h / 2, w, h };\n };\n for (const zone of this.zones) {\n if (zone.label.opacity() > 0.05) {\n const p = this.worldToScreen(zone.anchor);\n const w = zone.back.width() * sx;\n const h = zone.back.height() * sx;\n cands.push({ node: zone.label, tier: 0, section: false, box: { x: p.x - w / 2, y: p.y - h / 2, w, h } });\n }\n }\n for (const sec of this.sections) {\n if (sec.nameLabel.opacity() > 0.05) cands.push({ node: sec.nameLabel, tier: 1, section: true, box: boxOf(sec.nameLabel) });\n }\n if (cands.length < 2) return;\n cands.sort((a, b) => a.tier - b.tier || a.box.y - b.box.y || a.box.x - b.box.x);\n const kept: Cand['box'][] = [];\n const collides = (b: Cand['box']): boolean =>\n kept.some((k) =>\n b.x < k.x + k.w + GAP && k.x < b.x + b.w + GAP &&\n b.y < k.y + k.h + GAP && k.y < b.y + b.h + GAP,\n );\n for (const c of cands) {\n if (collides(c.box)) {\n c.node.opacity(0);\n } else if (!c.section) {\n // Section shells do not collide by construction; only zone pills form\n // blockers for later transitional labels.\n kept.push(c.box);\n }\n }\n }\n\n /** Set a centred label's world fontSize (for a target screen px) and re-anchor it. */\n private sizeLabel(t: Text, fontSize: number, y: number): void {\n t.fontSize(Math.max(1, fontSize));\n t.offsetX(t.width() / 2);\n t.offsetY(t.height() / 2);\n t.y(y);\n }\n\n /** Fit one centred section name, rotating narrow shells like the target chart. */\n private fitSectionRungLabels(sec: SectionRender, sx: number): void {\n const paddingPx = 8;\n sec.subLabelFits = false;\n // Scale the fitted screen-px band by the section's authored label size so a\n // larger override reads larger; the step still shrinks to fit the polygon.\n const maxPx = SECTION_LABEL_PX * sec.labelScale;\n const minPx = MIN_SECTION_LABEL_PX * sec.labelScale;\n for (let fontPx = maxPx; fontPx >= minPx; fontPx -= 1) {\n for (const rotation of [0, -90]) {\n sec.nameLabel.rotation(rotation);\n this.sizeLabel(sec.nameLabel, fontPx / sx, sec.nameLabel.y());\n for (const anchor of sec.labelAnchors) {\n sec.nameLabel.position(anchor);\n const paddingWorld = paddingPx / sx;\n if (rotatedRectFitsPolygon(\n anchor,\n sec.nameLabel.width() + paddingWorld,\n sec.nameLabel.height() + paddingWorld,\n rotation,\n sec.outline,\n sec.holes,\n )) {\n sec.nameLabelFits = true;\n return;\n }\n }\n }\n }\n sec.nameLabel.position(sec.centroid);\n sec.nameLabel.rotation(0);\n sec.nameLabelFits = false;\n }\n\n /** Size one screen-constant zone name/price pill around its shared anchor. */\n private sizeZonePill(zone: ZoneRender, sx: number): void {\n const padX = 10 / sx;\n const padY = 6 / sx;\n const gap = zone.sub ? 3 / sx : 0;\n this.sizeLabel(zone.label, ZONE_LABEL_PX / sx, zone.anchor.y);\n if (zone.sub) this.sizeLabel(zone.sub, ZONE_SUB_PX / sx, zone.anchor.y);\n const width = Math.max(zone.label.width(), zone.sub?.width() ?? 0) + padX * 2;\n const height = zone.label.height() + (zone.sub ? gap + zone.sub.height() : 0) + padY * 2;\n zone.label.y(zone.anchor.y - (zone.sub ? (gap + zone.sub.height()) / 2 : 0));\n if (zone.sub) zone.sub.y(zone.anchor.y + (zone.label.height() + gap) / 2);\n zone.back.position(zone.anchor);\n zone.back.size({ width, height });\n zone.back.offset({ x: width / 2, y: height / 2 });\n zone.back.cornerRadius(7 / sx);\n zone.back.strokeWidth(1 / sx);\n }\n\n /**\n * Map a container-relative screen point back to world coords. Inverts the\n * stage (scale/pos) and, in iso view, the iso affine — so screen-space taps\n * test against the flat world outlines/geometry. Identity-equivalent at isoT=0.\n */\n private screenToWorld(clientPoint: { x: number; y: number }): { x: number; y: number } {\n const s = this.stage.scaleX();\n const iso = { x: (clientPoint.x - this.stage.x()) / s, y: (clientPoint.y - this.stage.y()) / s };\n 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 marker.add(new Circle({ ...common, radius: this.seatR + (candidate ? 4.5 : 2.5), strokeWidth: candidate ? 3.5 : 2.5 }));\n if (candidate) {\n marker.add(new Circle({\n ...common,\n radius: this.seatR + 8,\n strokeWidth: 2,\n opacity: 0.55,\n }));\n } else {\n marker.add(new Line({\n points: [-this.seatR * 0.52, 0, -this.seatR * 0.12, this.seatR * 0.4, this.seatR * 0.6, -this.seatR * 0.46],\n stroke: '#ffffff',\n strokeWidth: Math.max(2.6, this.seatR * 0.34),\n lineCap: 'round',\n lineJoin: 'round',\n shadowColor: '#0b1220',\n shadowBlur: 1.5,\n shadowOpacity: 0.55,\n listening: false,\n }));\n }\n }\n\n this.selectionMarkers.set(id, marker);\n this.overlayLayer.add(marker);\n }\n\n // ---- interaction ----------------------------------------------------------\n\n /**\n * The stage scale `focusRegion(id)` would settle at — i.e. the zoom that\n * frames this section in the current viewport. Used to decide whether\n * redirecting a seat tap to section-focus would actually zoom in FURTHER, or\n * whether the section already fills the viewport (small container) so the tap\n * must fall through and pick.\n */\n private sectionBounds(id: string): { x: number; y: number; width: number; height: number } | null {\n const bounds = this.sections\n .filter((section) => section.id === id || section.logicalId === id)\n .map((section) => {\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 ink: typeof ink === 'string' ? ink : (this.theme.seatLabelColor ?? DEF_SEAT_LABEL),\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.viewChangeRaf) return;\n this.viewChangeRaf = requestAnimationFrame(() => {\n this.viewChangeRaf = 0;\n this.opts.onViewChange?.();\n });\n }\n\n private updateLOD(): void {\n // Effective scale folds in the iso y-squash (smaller ⇒ seats read smaller),\n // so LOD/melt thresholds trip correctly in 3D view. Equals the raw stage\n // scale at isoT=0 → flat behaviour is unchanged.\n const scale = this.effScale();\n const focalScale = Math.max(scale, 0.0001);\n for (const [label, targetPx] of this.primaryFocalLabels) {\n this.sizeLabel(label, targetPx / focalScale, label.y());\n }\n if (this.hasSections) this.applySectionLod(scale);\n else if (this.primaryFocalLabels.size) this.bgLayer.batchDraw();\n this.paintGAStateForView();\n // 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 = 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(true);\n this.cached = false;\n this.seatLayer.batchDraw();\n }\n }\n\n /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the\n * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */\n private rebuildSeatCache(): void {\n // 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 private updateFreeTextVisibility(): void {\n const effectiveScale = this.effScale();\n for (const { objectId, node, categoryKey, kind } of this.freeTextById.values()) {\n const gaDimmed = categoryKey != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaCategoryDimmed(categoryKey);\n const gaOverviewHidden = objectId != null\n && (kind === 'ga-label' || kind === 'ga-capacity')\n && this.gaById.get(objectId)?.sectionId != null\n && effectiveScale < CACHE_THRESHOLD;\n node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));\n }\n // 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 );\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) => this.rowLabelPlan.push({ text, x, y, rotation, fontSize, ink, opacity });\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 radians = (obj.rotation * Math.PI) / 180;\n const along = { x: Math.cos(radians), y: Math.sin(radians) };\n const gap = this.seatR + 12;\n const preset = presentation?.positionPreset ?? 'start';\n if (preset === 'start' || preset === 'both') push(first.x - along.x * gap, first.y - along.y * gap);\n if (preset === 'end' || preset === 'both') push(last.x + along.x * gap, last.y + along.y * gap);\n }\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.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 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 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/** 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 (the 150KB-gzipped complete CDN budget is a\n * product contract).\n *\n * Scope: the buyer surface (picker, public event\n * page, SDK) ships fully translated in en/es/de/fr; dashboard pages route\n * their strings through t() as they are rebuilt but ship English this round.\n *\n * Keys are flat dot-namespaced strings (\"picker.holdSeats\"). Interpolation\n * uses {name} placeholders. Missing keys fall back to English, then to the\n * key itself — a page never crashes over a translation.\n */\n\nimport { setMoneyLocale } from '../lib/money';\nimport { en } from './locales/en';\n\nexport type Locale = 'en' | 'es' | 'de' | 'fr';\nexport const SUPPORTED_LOCALES: Locale[] = ['en', 'es', 'de', 'fr'];\n\nexport type Dict = Record<string, string>;\n\nconst bundles: Partial<Record<Locale, Dict>> = { en };\n\n/** Extra strings layered over the active bundle (SDK white-label overrides). */\nlet overrides: Dict = {};\n\nlet active: Locale = 'en';\n\n/** explicit setting → stored preference → browser language → en */\nexport function resolveLocale(explicit?: string | null, stored?: string | null): Locale {\n for (const candidate of [explicit, stored, typeof navigator !== 'undefined' ? navigator.language : null]) {\n if (!candidate) continue;\n const base = candidate.toLowerCase().split('-')[0] as Locale;\n if (SUPPORTED_LOCALES.includes(base)) return base;\n }\n return 'en';\n}\n\nexport function getLocale(): Locale {\n return active;\n}\n\n/**\n * Set the active locale. Locale bundles other than English are registered by\n * the surface that needs them (the picker imports its own es/de/fr bundles;\n * the dashboard stays English until its translations ship).\n */\nexport function setLocale(locale: Locale, bundle?: Dict): void {\n if (bundle) bundles[locale] = { ...bundles[locale], ...bundle };\n active = bundles[locale] ? locale : 'en';\n setMoneyLocale(active);\n if (typeof document !== 'undefined') document.documentElement.lang = active;\n}\n\nexport function setStringOverrides(next: Dict): void {\n overrides = next;\n}\n\nconst PLACEHOLDER = /\\{(\\w+)\\}/g;\n\nexport function t(key: string, vars?: Record<string, string | number>): string {\n const raw = overrides[key] ?? bundles[active]?.[key] ?? en[key] ?? key;\n if (!vars) return raw;\n return raw.replace(PLACEHOLDER, (_, name: string) => String(vars[name] ?? `{${name}}`));\n}\n\n/** \"1 seat\" / \"3 seats\" without hand-rolled concatenation. */\nexport function tCount(key: string, count: number, vars?: Record<string, string | number>): string {\n const rule = new Intl.PluralRules(active).select(count);\n const exact = overrides[`${key}.${rule}`] ?? bundles[active]?.[`${key}.${rule}`] ?? en[`${key}.${rule}`];\n const raw = exact ?? overrides[`${key}.other`] ?? bundles[active]?.[`${key}.other`] ?? en[`${key}.other`] ?? key;\n return raw.replace(PLACEHOLDER, (_, name: string) => String({ count, ...vars }[name] ?? `{${name}}`));\n}\n\nexport function formatDate(value: number | Date, opts?: Intl.DateTimeFormatOptions): string {\n return new Intl.DateTimeFormat(active, opts ?? { dateStyle: 'medium', timeStyle: 'short' }).format(value);\n}\n","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\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/** 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): Promise<BestAvailableResponse>;\n release(key: string, labels: string[], holdId: string): Promise<unknown>;\n /** Optional capability-style lookup used to restore an active browser hold. */\n resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;\n /** Optional — the SDK omits booking (it hands the holdId to the host page). */\n book?(key: string, labels: string[], holdId: string, bookingRef: string): Promise<unknown>;\n /** Optional (P4) — push an active hold's expiry out (\"need more time?\"). */\n extend?(key: string, holdId: string, ttlMs?: number): Promise<{ holdId: string; expiresAt: number; extends?: number }>;\n socketUrl(key: string): string;\n}\n\nexport interface PickerCallbacks extends RendererCallbacks {\n /** Selection changed (manual clicks or a server best-available pick). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /** A 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 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 /** Atomically replace an active variable-table hold with a new guest count. */\n async replaceTableQuantity(label: string, quantity: 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, undefined, 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 async bestAvailable(\n qty: number,\n categoryKey?: string,\n opts: { preferPremium?: boolean; zoneId?: string } = {},\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);\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);\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 */\n async book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null> {\n const r = this.renderer;\n if (!r) return null;\n if (!this.api.book) throw new Error('picker: transport has no book() — hold-only mode');\n const labels = labelsArg ?? 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 undefined,\n replaceHoldId,\n );\n holdId = h.holdId;\n this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });\n }\n await this.api.book(this.key, labels, holdId, bookingRef);\n } catch (err) {\n const { status, conflicts, reason } = errInfo(err);\n this.clearHold();\n if (status === 409 && reason === 'event_closed') {\n this.opts.onSalesClosed?.();\n } else if (status === 409 && conflicts?.length) {\n // Paint the taken seats, deselect them, release the still-free remainder.\n const takenLabels = new Set(conflicts.map((c) => c.label));\n const takenIds = 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.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 this.opts.onStatusChange?.();\n this.clearBookedHoldIfSettled();\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 private connect(): void {\n if (this.closed) return;\n // A transport may be fully local (demo/mock) — an empty socketUrl means\n // \"no live feed\"; skip the connection instead of retrying forever.\n const url = this.api.socketUrl(this.key);\n if (!url) return;\n let ws: WebSocket;\n try {\n ws = new WebSocket(url);\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n\n ws.onopen = () => {\n this.attempt = 0;\n void this.resnapshot();\n };\n ws.onmessage = (e) => {\n let msg: unknown;\n try {\n msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n } catch {\n return;\n }\n const r = this.renderer;\n if (!r || !msg || typeof msg !== 'object') return;\n const m = msg as { type?: string; hidden?: string[]; closed?: string[]; seats?: Record<string, string>; changes?: { label: string; status: string }[] };\n // Reconcile hidden sections whenever they arrive (dedicated 'hidden' message\n // OR a snapshot that carries them). Only rebuilds the chart when it changed.\n if (Array.isArray(m.hidden) && this.syncHidden(m.hidden)) {\n void this.resnapshot(); // repaint statuses onto the rebuilt chart\n this.opts.onStatusChange?.();\n }\n // Reconcile closed sections (Phase 2). Cheap grey restyle, no chart rebuild —\n // so flipping a section open/closed mid-sale repaints for connected buyers.\n if (Array.isArray(m.closed) && this.syncClosed(m.closed)) {\n this.opts.onStatusChange?.();\n }\n if (m.type === 'hidden') return; // dedicated hidden message carries no seats\n if (m.seats && typeof m.seats === 'object') {\n this.applySeatsMap(m.seats);\n } else if (Array.isArray(m.changes)) {\n for (const ch of m.changes) {\n this.liveStatuses.set(ch.label, ch.status);\n const 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 ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.scheduleReconnect();\n };\n ws.onerror = () => {\n try {\n ws.close();\n } catch {\n /* onclose drives reconnect */\n }\n };\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const attempt = Math.min(this.attempt++, 5);\n const delay = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n}\n","/**\n * 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 a dark hall with the stage\n * placed at the correct bearing and angular size for THIS seat — closer seats\n * see a bigger stage, off-center seats see it at an angle. Used whenever the\n * organizer hasn't uploaded a real photo/360 for the seat; both go through the\n * same viewer.\n *\n * Equirectangular mapping: x = (yaw + 180°)/360° · W, y = (90° − pitch)/180° · H,\n * where yaw 0 = the direction the camera faces by default.\n */\n\nimport type { ExpandedSeat, Point } from '../core/types';\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;\n\nconst yawToX = (yawDeg: number) => ((yawDeg + 180) / 360) * W;\nconst pitchToY = (pitchDeg: number) => ((90 - pitchDeg) / 180) * H;\n\nexport interface PanoramaResult {\n url: string;\n /** Meters from the stage, for the caption. */\n distanceM: number;\n}\n\nexport function generateSeatPanorama(\n seat: ExpandedSeat,\n focalPoint: Point,\n neighborSeats: ExpandedSeat[],\n): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = W;\n canvas.height = H;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distU = Math.hypot(dx, dy);\n const distM = Math.max(2, distU * UNIT);\n\n // ---- room shell: ceiling → walls → floor -------------------------------\n const sky = ctx.createLinearGradient(0, 0, 0, H);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.42, '#11172a');\n sky.addColorStop(0.5, '#1a2238');\n sky.addColorStop(0.56, '#10141f');\n sky.addColorStop(1, '#07090f');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, W, H);\n\n // ---- stage, centered at yaw 0 (the viewer opens facing it) -------------\n // Angular size from real proportions: stage ~8m wide, ~1m platform + 6m set.\n // Pitch is eye-height-aware (Phase B2): a raised/raked seat looks down at it.\n const eyeM = seat.eyeHeightM ?? SEATED_EYE_HEIGHT_M;\n const stageHalfYaw = Math.min(80, (Math.atan2(4, distM) * 180) / Math.PI);\n const sightline = stageSightlinePitch(eyeM, distM);\n const stageTopPitch = Math.min(45, sightline.topPitch);\n const stageBasePitch = sightline.basePitch;\n\n const sx0 = yawToX(-stageHalfYaw);\n const sx1 = yawToX(stageHalfYaw);\n const sy0 = pitchToY(stageTopPitch);\n const sy1 = pitchToY(stageBasePitch);\n\n // glow behind the stage\n const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 10, W / 2, (sy0 + sy1) / 2, (sx1 - sx0) * 1.1);\n glow.addColorStop(0, 'rgba(129, 140, 248, 0.5)');\n glow.addColorStop(0.5, 'rgba(99, 102, 241, 0.16)');\n glow.addColorStop(1, 'rgba(99, 102, 241, 0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - (sx1 - sx0) * 0.6, sy0 - (sy1 - sy0) * 1.2, (sx1 - sx0) * 2.2, (sy1 - sy0) * 3.4);\n\n // stage box + lit backdrop\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.75;\n ctx.fillStyle = backdrop;\n const inset = (sx1 - sx0) * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + (sy1 - sy0) * 0.12, sx1 - sx0 - inset * 2, (sy1 - sy0) * 0.62);\n ctx.globalAlpha = 1;\n // stage lip\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - (sy1 - sy0) * 0.1, sx1 - sx0, (sy1 - sy0) * 0.1);\n\n // performer silhouettes, scaled by distance\n const performerH = (sy1 - sy0) * 0.45;\n ctx.fillStyle = 'rgba(8, 10, 16, 0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + (sx1 - sx0) * fx;\n const py = sy1 - (sy1 - sy0) * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - performerH * 0.82, performerH * 0.16, 0, Math.PI * 2); // head\n ctx.fill();\n ctx.fillRect(px - performerH * 0.14, py - performerH * 0.68, performerH * 0.28, performerH * 0.68); // body\n }\n\n // spotlight beams from above the stage\n ctx.globalAlpha = 0.14;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + (sx1 - sx0) * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.lineTo(bx - (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + (sx1 - sx0) * 0.09, sy1);\n ctx.lineTo(bx + 8, pitchToY(Math.min(60, stageTopPitch + 25)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // ---- rig lights along the ceiling all around ---------------------------\n ctx.fillStyle = 'rgba(199, 210, 254, 0.8)';\n for (let i = 0; i < 26; i++) {\n const x = (i / 26) * W;\n const y = pitchToY(55 + (i % 3) * 6);\n ctx.beginPath();\n ctx.arc(x, y, 3.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // ---- audience: heads of nearby seats, at their true bearings -----------\n // Bearing relative to the stage direction so yaw 0 keeps facing the stage.\n const stageBearing = Math.atan2(dx, -dy); // screen coords, -y is \"up\" the hall\n ctx.fillStyle = 'rgba(16, 20, 30, 0.95)';\n for (const other of neighborSeats) {\n if (other.id === seat.id) continue;\n const ox = other.x - seat.x;\n const oy = other.y - seat.y;\n const d = Math.hypot(ox, oy) * UNIT;\n if (d < 0.3 || d > 14) continue;\n const bearing = Math.atan2(ox, -oy) - stageBearing;\n const yaw = ((((bearing * 180) / Math.PI + 540) % 360) - 180);\n const headPitch = (-Math.atan2(0.35, d) * 180) / Math.PI; // heads slightly below eye level\n const headR = Math.min(46, 260 / (d / UNIT / 24 + 1.2) / 4);\n const hx = yawToX(yaw);\n const hy = pitchToY(headPitch);\n ctx.beginPath();\n ctx.arc(hx, hy, headR, 0, Math.PI * 2);\n ctx.fill();\n ctx.beginPath(); // shoulders\n ctx.ellipse(hx, hy + headR * 1.4, headR * 1.7, headR * 0.9, 0, Math.PI, 0, true);\n ctx.fill();\n }\n\n // subtle vignette at the poles (hides equirect pinching)\n const poleFade = ctx.createLinearGradient(0, 0, 0, H);\n poleFade.addColorStop(0, 'rgba(0,0,0,0.85)');\n poleFade.addColorStop(0.12, 'rgba(0,0,0,0)');\n poleFade.addColorStop(0.88, 'rgba(0,0,0,0)');\n poleFade.addColorStop(1, 'rgba(0,0,0,0.85)');\n ctx.fillStyle = poleFade;\n ctx.fillRect(0, 0, W, H);\n\n return { url: canvas.toDataURL('image/jpeg', 0.82), distanceM: Math.round(distM) };\n}\n\n// ---------------------------------------------------------------------------\n// Compact forward-view thumbnail — a cheap (480×270) rectilinear preview of\n// what this seat faces, for inline display inside the buyer's confirm card.\n// Unlike the full equirectangular panorama it maps a ~100°×60° forward field\n// of view directly (no 360 squish), so it reads as a real POV at a glance and\n// costs a fraction of the full render. Same geometry → the two stay consistent.\n// ---------------------------------------------------------------------------\n\nconst TW = 480;\nconst TH = 270;\nconst HALF_HFOV = 50; // degrees left/right of the stage direction\nconst HALF_VFOV = 30; // degrees up/down of the horizon\n\nconst yawToTX = (yawDeg: number) => ((yawDeg + HALF_HFOV) / (2 * HALF_HFOV)) * TW;\nconst pitchToTY = (pitchDeg: number) => ((HALF_VFOV - pitchDeg) / (2 * HALF_VFOV)) * TH;\n\nexport function generateSeatThumb(seat: ExpandedSeat, focalPoint: Point, _neighborSeats?: ExpandedSeat[]): PanoramaResult {\n const canvas = document.createElement('canvas');\n canvas.width = TW;\n canvas.height = TH;\n const ctx = canvas.getContext('2d')!;\n\n const dx = focalPoint.x - seat.x;\n const dy = focalPoint.y - seat.y;\n const distM = Math.max(2, Math.hypot(dx, dy) * UNIT);\n\n // hall shell (ceiling → wall → floor), horizon at mid-height\n const sky = ctx.createLinearGradient(0, 0, 0, TH);\n sky.addColorStop(0, '#05070c');\n sky.addColorStop(0.44, '#141b30');\n sky.addColorStop(0.5, '#1b2440');\n sky.addColorStop(0.58, '#10141f');\n sky.addColorStop(1, '#070910');\n ctx.fillStyle = sky;\n ctx.fillRect(0, 0, TW, TH);\n\n // stage geometry (identical formulas to the full panorama, eye-height-aware)\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\n // glow\n const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.1);\n glow.addColorStop(0, 'rgba(129,140,248,0.5)');\n glow.addColorStop(0.5, 'rgba(99,102,241,0.15)');\n glow.addColorStop(1, 'rgba(99,102,241,0)');\n ctx.fillStyle = glow;\n ctx.fillRect(sx0 - sw * 0.6, sy0 - sh * 1.2, sw * 2.2, sh * 3.4);\n\n // stage box + lit backdrop + lip\n ctx.fillStyle = '#242c44';\n ctx.fillRect(sx0, sy0, sw, sh);\n const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);\n backdrop.addColorStop(0, '#7c5cff');\n backdrop.addColorStop(0.5, '#e1447a');\n backdrop.addColorStop(1, '#f59e0b');\n ctx.globalAlpha = 0.78;\n ctx.fillStyle = backdrop;\n const inset = sw * 0.06;\n ctx.fillRect(sx0 + inset, sy0 + sh * 0.12, sw - inset * 2, sh * 0.62);\n ctx.globalAlpha = 1;\n ctx.fillStyle = '#0d1119';\n ctx.fillRect(sx0, sy1 - sh * 0.1, sw, sh * 0.1);\n\n // performer silhouettes\n const ph = sh * 0.45;\n ctx.fillStyle = 'rgba(8,10,16,0.85)';\n for (const fx of [0.35, 0.5, 0.65]) {\n const px = sx0 + sw * fx;\n const py = sy1 - sh * 0.12;\n ctx.beginPath();\n ctx.arc(px, py - ph * 0.82, ph * 0.16, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillRect(px - ph * 0.14, py - ph * 0.68, ph * 0.28, ph * 0.68);\n }\n\n // spotlight beams\n ctx.globalAlpha = 0.15;\n ctx.fillStyle = '#c7d2fe';\n for (const fx of [0.3, 0.5, 0.7]) {\n const bx = sx0 + sw * fx;\n ctx.beginPath();\n ctx.moveTo(bx - 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.lineTo(bx - sw * 0.09, sy1);\n ctx.lineTo(bx + sw * 0.09, sy1);\n ctx.lineTo(bx + 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));\n ctx.closePath();\n ctx.fill();\n }\n ctx.globalAlpha = 1;\n\n // a few rig lights across the ceiling\n ctx.fillStyle = 'rgba(199,210,254,0.75)';\n for (let i = 0; i < 8; i++) {\n ctx.beginPath();\n ctx.arc(((i + 0.5) / 8) * TW, pitchToTY(HALF_VFOV - 4 - (i % 2) * 3), 2.2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // seat-back rows in the foreground for depth\n ctx.fillStyle = 'rgba(10,13,20,0.9)';\n ctx.fillRect(0, TH - 26, TW, 26);\n ctx.fillStyle = 'rgba(30,37,54,0.9)';\n for (let i = 0; i < 9; i++) ctx.fillRect(i * (TW / 9) + 6, TH - 22, TW / 9 - 12, 14);\n\n return { url: canvas.toDataURL('image/jpeg', 0.8), distanceM: Math.round(distM) };\n}\n","/**\n * Locale bundle loader — keeps non-English translations OUT of the initial\n * bundle (the 150 KB complete CDN budget is a product contract) and code-splits each\n * locale so a page/SDK only downloads the language it actually uses.\n *\n * `loadLocale('de')` dynamic-imports the German dictionary, registers it via\n * setLocale(), and resolves once it's active. English is built in, so\n * `loadLocale('en')` is synchronous and never fetches. Unknown/unsupported\n * codes fall back to English without throwing.\n */\nimport { setLocale, resolveLocale, type Dict, type Locale } from './index';\n\n/** Dynamic importers per non-English locale (English ships in the core). */\nconst LOADERS: Record<Exclude<Locale, 'en'>, () => Promise<{ default: Dict }>> = {\n es: () => import('./locales/es').then((m) => ({ default: m.es })),\n de: () => import('./locales/de').then((m) => ({ default: m.de })),\n fr: () => import('./locales/fr').then((m) => ({ default: m.fr })),\n};\n\nconst loaded = new Set<Locale>(['en']);\n\n/**\n * Resolve `code` to a supported locale, load its bundle if needed, and make it\n * active. Returns the locale that ended up active (English on any failure).\n */\nexport async function loadLocale(code?: string | null): Promise<Locale> {\n const locale = resolveLocale(code);\n if (locale === 'en' || loaded.has(locale)) {\n setLocale(locale);\n return locale;\n }\n try {\n const mod = await LOADERS[locale]();\n setLocale(locale, mod.default);\n loaded.add(locale);\n return locale;\n } catch {\n setLocale('en');\n return 'en';\n }\n}\n"],"mappings":"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","names":["t","core","t","overrides","bounds","centroid","out","objects","bounds","t","rgb","bounds","scale","stageX","stageY","centroid","seatIndex","active","t"]}
|