@seatlayer/js 0.51.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/manageApi.ts","../src/channelPlan.ts","../src/channelsMode.ts","../src/manager.ts","../src/SeatManager.ts","../src/manageAssets.ts"],"sourcesContent":["/**\n * Organizer manage-surface client for workers/api (the `/v1/events/:key/*`\n * inventory routes + the public realtime channel). Companion to api.ts (the\n * buyer `/pub/*` client) — kept separate because the manage surface is\n * token-authed (Bearer) and cross-origin from the CMS:\n *\n * - Writes + reports send `Authorization: Bearer <token>`. Browser code must\n * use a short-lived, event-scoped organizer grant (`mse_…`, minted by a\n * trusted backend). The low-level client retains tenant-secret (`sk_…`)\n * compatibility for trusted server runtimes only; never pass one to\n * SeatManager or any other browser bundle.\n * - `credentials: 'omit'` — there is no session cookie; the CMS runs\n * cross-origin. The worker's credentialed CORS still echoes the CMS origin.\n * - chart geometry and authored media use authenticated organizer Event\n * routes. A manage bearer is not buyer authority and is never sent to\n * `/pub`. The seat STATE reads are private too. `/pub/.../objects` and an unticketed\n * `/pub/.../subscribe` both answer with the BUYER projection, which shows\n * inventory the caller may not buy as a neutral `blocked` — so an organizer\n * reading them sees its own channel allocations as blocked seats. Both now\n * go through the token: `/v1/events/:key/objects` for the snapshot, and a\n * `/v1/events/:key/subscribe-tickets` mint for the socket's scope.\n *\n * Managed sales are deliberately not exposed by this browser client. Create\n * them from trusted server code through the inventory booking API; SeatManager\n * exposes only the organizer operations it can actually complete itself.\n */\nimport type { AvailabilityRule, ChartDoc } from '@seatlayer/core';\nimport type {\n AccessLinkRecord,\n AccessLinkReveal,\n AccessLinkStatusRecord,\n AssignmentResult,\n ChannelAccessIntent,\n ChannelCounts,\n ChannelListResult,\n ChannelRecord,\n ChannelState,\n} from './channelPlan';\n\nexport type { AvailabilityRule } from '@seatlayer/core';\n\n/** One page of the organizer-only label → channel projection. */\nexport interface ChannelAllocationPage {\n assignmentVersion: number;\n allocations: Array<{ label: string; channelId: string }>;\n nextAfterLabel: string | null;\n}\n\nexport interface ChannelAuditEntry {\n id: number;\n at: number;\n actor: string | null;\n action: string;\n channelId: string | null;\n assignmentVersion: number;\n before: unknown;\n after: unknown;\n reason: string | null;\n}\n\nexport interface ChannelAuditPage {\n entries: ChannelAuditEntry[];\n nextBefore: number | null;\n}\n\n/**\n * Buyer projection for a preview audience — the same scoped server view the\n * buyer SDK receives. When an audience cannot be previewed (a paused or\n * archived channel), the server answers `{available:false, unavailable:[…]}`\n * and the UI shows the real paused/unavailable landing state instead of\n * rendering those seats as eligible.\n *\n * Fields stay optional: a worker that predates the hardening merge 404s here,\n * and Channels mode says the preview needs a newer server rather than faking a\n * projection client-side.\n */\nexport interface ChannelPreviewProjection {\n available?: boolean;\n unavailable?: Array<{ channelId: string; state: 'paused' | 'archived' | string }>;\n channelIds?: string[];\n includePublic?: boolean;\n /** Labels this audience may buy. Everything else renders as ONE neutral\n * unavailable state so preview never leaks which channel holds a seat. */\n eligible?: string[];\n counts?: { eligible?: number; free?: number; held?: number; booked?: number };\n}\n\nexport class ManageApiError extends Error {\n status: number;\n code?: string;\n /** Present when a block/unbook 409s because seats were just taken. */\n conflicts?: { label: string; reason?: string }[];\n /**\n * Structured refusal detail. The channel routes use it for the two 409s a UI\n * must render rather than merely report: `channel_archive_blocked_by_holds`\n * carries {activeHolds, heldUnits, latestHoldExpiresAt, retryAfterMs}, and\n * `channel_assignment_conflict` carries the current assignmentVersion.\n */\n details?: Record<string, unknown>;\n /**\n * The server's own human sentence, when it sent one. `message` is the machine\n * code (that is what `error` carries), so a UI that wants to state a PLATFORM\n * RULE — \"redemptions must be between 1 and 10 000\" — reads this instead of\n * re-encoding the bound locally and risking disagreement with the server.\n */\n serverMessage?: string;\n\n constructor(\n status: number,\n message: string,\n code?: string,\n conflicts?: { label: string; reason?: string }[],\n details?: Record<string, unknown>,\n serverMessage?: string,\n ) {\n super(message);\n this.name = 'ManageApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.details = details;\n this.serverMessage = serverMessage;\n }\n}\n\nexport interface ReportByStatus {\n free: number;\n held: number;\n booked: number;\n not_for_sale: number;\n}\n\nexport interface ReportCategoryRow {\n category: string;\n total: number;\n free: number;\n held: number;\n booked: number;\n not_for_sale: number;\n /** Configured-price snapshots for booked inventory; not proof of payment. */\n bookedValue: number;\n /** @deprecated Use `bookedValue`. */\n bookedRevenue: number;\n}\n\nexport interface ReportCategoryMeta {\n key: string;\n label: string;\n color: string;\n price: number;\n}\n\nexport interface ReportResult {\n report: { byStatus: ReportByStatus; byCategory: ReportCategoryRow[]; bySection?: ControlRoomSectionMetric[] };\n event: { key: string; name: string; seatTotal: number; currency?: string };\n categories: ReportCategoryMeta[];\n}\n\nexport interface ControlRoomSectionMetric {\n sectionId: string;\n sectionLabel: string;\n zoneId: string | null;\n total: number;\n free: number;\n held: number;\n booked: number;\n not_for_sale: number;\n bookedValue: number;\n /** @deprecated Use `bookedValue`. */\n bookedRevenue: number;\n}\n\n/** Recent seat-state change safe for an event:view control-room grant. Full\n * audit references remain available only through the event:reports log API. */\nexport interface ControlRoomActivityEntry {\n id: number;\n at: number;\n action: string;\n labels: string[];\n}\n\nexport interface ControlRoomSnapshot {\n version: number;\n currency: string;\n totals: { free: number; held: number; booked: number; blocked: number };\n /** Configured value attached to booked inventory, never payment revenue. */\n bookedValue: { gross: number; bySection: ControlRoomSectionMetric[] };\n /** @deprecated Use `bookedValue`. */\n revenue: { gross: number; bySection: ControlRoomSectionMetric[] };\n velocity: {\n windowMinutes: number;\n bySection: Array<{\n sectionId: string;\n netBooked: number;\n bookedValue: number;\n /** @deprecated Use `bookedValue`. */\n grossRevenue: number;\n previousNetBooked: number;\n trend: 'rising' | 'steady' | 'cooling';\n }>;\n };\n presence: { shoppingSessions: number; activeHolds: number };\n /** Present on workers that support reload-safe activity hydration. */\n activity?: ControlRoomActivityEntry[];\n event: { key: string; name: string; seatTotal: number; currency?: string };\n}\n\nexport interface LogEntry {\n id: number;\n at: number;\n action: string;\n labels: string[];\n ref: string | null;\n}\n\nexport interface LogPage {\n entries: LogEntry[];\n nextBefore: number | null;\n}\n\n/** Platform/SDK inventory history — deliberately unrelated to commerce Orders. */\nexport type InventoryBookingState = 'booked' | 'partially_cancelled' | 'cancelled';\n\nexport interface InventoryBookingObject {\n label: string;\n objectId: string;\n objectType: 'seat' | 'booth' | 'ga' | 'table';\n categoryKey: string;\n sectionId: string | null;\n sectionLabel: string | null;\n zoneId: string | null;\n tierId: string | null;\n releaseId: string | null;\n bookingMode: 'individual' | 'whole' | 'variable';\n quantity: number;\n /** Event-configured price snapshot; not proof of what a buyer paid. */\n unitPrice: number;\n configuredValue: number;\n currency: string;\n channelId: string | null;\n channelExternalRef: string | null;\n source: string;\n state: 'booked' | 'cancelled';\n bookedAt: number;\n cancelledAt: number | null;\n}\n\nexport interface InventoryBooking {\n eventKey: string;\n eventMode: 'live' | 'test';\n bookingRef: string;\n state: InventoryBookingState;\n bookedAt: number;\n updatedAt: number;\n cancelledAt: number | null;\n source: string;\n bookedBy: string | null;\n lastActor: string | null;\n lastSource: string;\n labels: string[];\n objects: InventoryBookingObject[];\n quantity: number;\n activeQuantity: number;\n configuredValue: number;\n activeConfiguredValue: number;\n currency: string | null;\n}\n\nexport interface InventoryBookingsQuery {\n q?: string;\n state?: InventoryBookingState | null;\n cursor?: string | null;\n limit?: number;\n}\n\nexport interface InventoryBookingsPage {\n bookings: InventoryBooking[];\n nextCursor: string | null;\n}\n\nexport interface InventoryBookingActivity {\n id: number;\n action: 'book' | 'replay' | 'partial_cancel' | 'cancel' | 'reconcile';\n at: number;\n labels: string[];\n actor: string | null;\n source: string;\n}\n\nexport interface InventoryBookingDetail {\n booking: InventoryBooking;\n activity: InventoryBookingActivity[];\n activityTruncated: boolean;\n}\n\n/** Booking-time facts attached to the channel that produced the inventory move. */\nexport interface ChannelAttribution {\n sold: number;\n units: number;\n bookedValue: number | null;\n /** @deprecated Use `bookedValue`. */\n revenue: number | null;\n}\n\nexport interface ChannelReportRow {\n channelId: string;\n name: string;\n externalRef: string | null;\n state: ChannelState;\n allocation: ChannelCounts;\n attribution: ChannelAttribution;\n sellThrough: number | null;\n}\n\nexport interface ChannelReport {\n assignmentVersion: number;\n includesBookedValue: boolean;\n /** @deprecated Use `includesBookedValue`. */\n includesRevenue: boolean;\n methodology: { allocation: string; attribution: string; sellThrough: string };\n rows: ChannelReportRow[];\n totals: {\n allocated: number;\n free: number;\n held: number;\n booked: number;\n blocked: number;\n sold: number;\n bookedValue: number | null;\n /** @deprecated Use `bookedValue`. */\n revenue: number | null;\n };\n}\n\nexport interface ChannelReportResult {\n report: ChannelReport;\n event: { key: string; name: string; seatTotal?: number; currency?: string };\n}\n\nexport interface ChannelReportLinkRecord {\n id: string;\n channelId: string;\n label: string | null;\n includesBookedValue: boolean;\n /** @deprecated Use `includesBookedValue`. */\n includesRevenue: boolean;\n expiresAt: number;\n state: 'active' | 'revoked';\n status: 'active' | 'revoked' | 'expired';\n views: number;\n lastViewedAt: number | null;\n createdAt: number;\n createdBy: string | null;\n revokedAt: number | null;\n}\n\nexport interface ChannelReportLinkReveal {\n link: ChannelReportLinkRecord;\n url: string;\n capability: string;\n revealedOnce: true;\n}\n\n/**\n * A one-use WebSocket subscribe ticket. `protocols` is exactly what to hand\n * `new WebSocket(url, protocols)` — the ticket rides in `Sec-WebSocket-Protocol`\n * because a browser socket cannot carry an Authorization header and a bearer\n * must never travel in a URL.\n */\nexport interface SubscribeTicket {\n ticket: string;\n expiresAt: number;\n protocol: string;\n protocols: string[];\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status keyed by label (free seats omitted). */\n seats: Record<string, string>;\n hidden?: string[];\n closed?: string[];\n updatedAt: number;\n}\n\nexport interface PubChartResult {\n event: {\n key: string;\n name: string;\n status?: string;\n venue?: string | null;\n startsAt?: number | null;\n currency?: string;\n mode?: string;\n };\n doc: ChartDoc;\n}\n\nasync function parse<T>(res: Response): Promise<T> {\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n if (!res.ok) {\n const err = data as {\n error?: string;\n code?: string;\n conflicts?: { label: string; reason?: string }[];\n details?: Record<string, unknown>;\n message?: string;\n } | null;\n throw new ManageApiError(\n res.status,\n err?.error ?? `request_failed_${res.status}`,\n err?.code,\n err?.conflicts,\n err?.details,\n typeof err?.message === 'string' ? err.message : undefined,\n );\n }\n return data as T;\n}\n\ntype UnknownRecord = Record<string, unknown>;\n\nfunction record(value: unknown): UnknownRecord {\n return value && typeof value === 'object' ? value as UnknownRecord : {};\n}\n\nfunction finite(primary: unknown, legacy: unknown, fallback = 0): number {\n if (typeof primary === 'number' && Number.isFinite(primary)) return primary;\n if (typeof legacy === 'number' && Number.isFinite(legacy)) return legacy;\n return fallback;\n}\n\nfunction nullableFinite(primary: unknown, legacy: unknown): number | null {\n // `null` is an authorization-safe canonical answer (for example, a channel\n // viewer may see counts but not configured booked value). Fall back only\n // when the canonical field is genuinely absent during a rolling upgrade.\n if (primary === null) return null;\n if (typeof primary === 'number' && Number.isFinite(primary)) return primary;\n if (primary !== undefined) return null;\n if (typeof legacy === 'number' && Number.isFinite(legacy)) return legacy;\n return null;\n}\n\nfunction normalizeSection(value: unknown): ControlRoomSectionMetric {\n const row = record(value);\n const bookedValue = finite(row.bookedValue, row.bookedRevenue);\n return { ...row, bookedValue, bookedRevenue: bookedValue } as unknown as ControlRoomSectionMetric;\n}\n\nfunction normalizeReportResult(value: unknown): ReportResult {\n const source = record(value);\n const report = record(source.report);\n const byCategory = Array.isArray(report.byCategory)\n ? report.byCategory.map((value) => {\n const row = record(value);\n const bookedValue = finite(row.bookedValue, row.bookedRevenue);\n return { ...row, bookedValue, bookedRevenue: bookedValue } as unknown as ReportCategoryRow;\n })\n : [];\n const bySection = Array.isArray(report.bySection)\n ? report.bySection.map(normalizeSection)\n : undefined;\n return {\n ...source,\n report: { ...report, byCategory, ...(bySection ? { bySection } : {}) },\n } as unknown as ReportResult;\n}\n\nfunction normalizeControlRoomSnapshot(value: unknown): ControlRoomSnapshot {\n const source = record(value);\n const canonical = record(source.bookedValue);\n const legacy = record(source.revenue);\n const selected = Object.keys(canonical).length ? canonical : legacy;\n const bySectionSource = Array.isArray(canonical.bySection)\n ? canonical.bySection\n : Array.isArray(legacy.bySection) ? legacy.bySection : [];\n const bookedValue = {\n ...selected,\n gross: finite(canonical.gross, legacy.gross),\n bySection: bySectionSource.map(normalizeSection),\n };\n const velocity = record(source.velocity);\n const velocityRows = Array.isArray(velocity.bySection)\n ? velocity.bySection.map((value) => {\n const row = record(value);\n const rowValue = finite(row.bookedValue, row.grossRevenue);\n return { ...row, bookedValue: rowValue, grossRevenue: rowValue };\n })\n : [];\n return {\n ...source,\n bookedValue,\n revenue: bookedValue,\n velocity: { ...velocity, bySection: velocityRows },\n } as unknown as ControlRoomSnapshot;\n}\n\nfunction normalizeChannelReportResult(value: unknown): ChannelReportResult {\n const source = record(value);\n const report = record(source.report);\n const includesBookedValue = typeof report.includesBookedValue === 'boolean'\n ? report.includesBookedValue\n : report.includesRevenue === true;\n const rows = Array.isArray(report.rows) ? report.rows.map((value) => {\n const row = record(value);\n const attribution = record(row.attribution);\n const bookedValue = nullableFinite(attribution.bookedValue, attribution.revenue);\n return {\n ...row,\n attribution: { ...attribution, bookedValue, revenue: bookedValue },\n };\n }) : [];\n const totals = record(report.totals);\n const totalBookedValue = nullableFinite(totals.bookedValue, totals.revenue);\n return {\n ...source,\n report: {\n ...report,\n includesBookedValue,\n includesRevenue: includesBookedValue,\n rows,\n totals: { ...totals, bookedValue: totalBookedValue, revenue: totalBookedValue },\n },\n } as unknown as ChannelReportResult;\n}\n\nfunction normalizeChannelReportLink(value: unknown): ChannelReportLinkRecord {\n const link = record(value);\n const includesBookedValue = typeof link.includesBookedValue === 'boolean'\n ? link.includesBookedValue\n : link.includesRevenue === true;\n return {\n ...link,\n includesBookedValue,\n includesRevenue: includesBookedValue,\n } as unknown as ChannelReportLinkRecord;\n}\n\n/**\n * Bound to one apiBase + bearer token. Browser callers use an event-scoped\n * `mse_…` grant. A tenant `sk_…` remains accepted only so trusted server code\n * can use this low-level client; SeatManager rejects it before construction.\n * Rebuild (or `setToken`) when a token is re-minted on 401.\n */\nexport class ManageApi {\n private base: string;\n private token: string;\n\n constructor(apiBase: string, token: string) {\n this.base = apiBase.replace(/\\/+$/, '');\n this.token = token;\n }\n\n /** Swap the Bearer token in place (SeatManager re-mints on 401). */\n setToken(token: string): void {\n this.token = token;\n }\n\n private auth<T>(\n path: string,\n init: { method?: 'GET' | 'POST' | 'PATCH' | 'DELETE'; body?: unknown } = {},\n ): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = { Authorization: `Bearer ${this.token}` };\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n return fetch(`${this.base}${path}`, { method, headers, body, credentials: 'omit' }).then((r) => parse<T>(r));\n }\n\n private async authBlob(path: string): Promise<Blob> {\n const res = await fetch(`${this.base}${path}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${this.token}` },\n credentials: 'omit',\n });\n if (!res.ok) await parse<never>(res);\n return res.blob();\n }\n\n // ---- realtime read ----\n\n /** Event-pinned organizer geometry. A manage token is never sent to `/pub`. */\n chart(key: string): Promise<PubChartResult> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/chart`);\n }\n\n /** Authenticated bytes for an Event-scoped organizer chart asset. */\n asset(key: string, asset: string): Promise<Blob> {\n if (!/^[a-zA-Z0-9._-]+$/.test(asset)) {\n return Promise.reject(new ManageApiError(404, 'not_found', 'not_found'));\n }\n return this.authBlob(\n `/v1/events/${encodeURIComponent(key)}/assets/${encodeURIComponent(asset)}`,\n );\n }\n\n /**\n * The ORGANIZER's seat map: physical state, token-authed.\n *\n * This used to read `/pub/events/:key/objects` with no credential, which\n * answers with the BUYER projection — every unit the caller may not buy\n * collapses to a neutral `blocked`. An anonymous caller may buy only Public\n * sale inventory, so the cockpit rendered every channel-allocated seat as\n * blocked and then computed its KPIs, sell-through and (worse) its\n * block/unblock target sets from that. `/v1/events/:key/objects` returns the\n * unprojected snapshot the control-room read model already trusts.\n */\n objects(key: string): Promise<PubObjectsResult> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/objects`);\n }\n\n /**\n * Exchange the manage token for a one-use organizer socket ticket.\n *\n * A browser `WebSocket` cannot send an Authorization header, so the socket's\n * scope is established here, over ordinary HTTPS. Without it the DO treats a\n * manager socket as an anonymous public buyer and projects its deltas — so a\n * hold inside a private allocation is structurally suppressed and the map\n * drifts away from the truth `objects()` just established.\n *\n * Tickets are single-redemption and expire in ~30s: mint one per connect.\n */\n subscribeTicket(key: string): Promise<SubscribeTicket> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/subscribe-tickets`, { method: 'POST' });\n }\n\n socketUrl(key: string): string {\n return `${this.base.replace(/^http/, 'ws')}/pub/events/${encodeURIComponent(key)}/subscribe?surface=manager`;\n }\n\n // ---- inventory writes (token) ----\n\n /** Take FREE seats off sale in one batched call. Optional `releaseAt` (epoch\n * ms, future) auto-returns them to sale; `reason` tags the block (M3 uses it).\n * Throws ManageApiError 409 (conflicts) if any seat was just taken. */\n block(\n key: string,\n labels: string[],\n opts: { releaseAt?: number; reason?: string } = {},\n ): Promise<{ ok: true; blocked: string[] }> {\n const body: Record<string, unknown> = { labels };\n if (typeof opts.releaseAt === 'number') body.releaseAt = opts.releaseAt;\n if (opts.reason) body.reason = opts.reason;\n return this.auth(`/v1/events/${encodeURIComponent(key)}/block`, { method: 'POST', body });\n }\n\n /** Return specific blocked seats to sale (one batched call). */\n unblock(key: string, labels: string[]): Promise<{ ok: true; unblocked: string[] }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/unblock`, { method: 'POST', body: { labels } });\n }\n\n /** Return every blocked seat to sale; resolves with the freed count. */\n unblockAll(key: string): Promise<{ ok: true; freed: number }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/unblock-all`, { method: 'POST' });\n }\n\n /** Cancel bookings — return BOOKED seats to free (credit not refunded).\n * Guarded by the original booking reference. */\n unbook(key: string, labels: string[], bookingRef: string): Promise<{ ok: true; unbooked: string[] }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/unbook`, { method: 'POST', body: { labels, bookingRef } });\n }\n\n /** Set (ms, clamped 1–60 min server-side) or clear (null) the hold TTL. */\n setHoldTtl(key: string, holdTtlMs: number | null): Promise<{ ok: true; holdTtlMs: number | null }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/hold-ttl`, { method: 'POST', body: { holdTtlMs } });\n }\n\n // ---- Platform inventory booking history (token) ----\n\n /** Inventory lifecycle by stable integrator bookingRef. Absent on Managed. */\n bookings(key: string, query: InventoryBookingsQuery = {}): Promise<InventoryBookingsPage> {\n const params = new URLSearchParams();\n if (query.q) params.set('q', query.q);\n if (query.state) params.set('state', query.state);\n if (query.cursor) params.set('cursor', query.cursor);\n if (query.limit != null) params.set('limit', String(query.limit));\n const qs = params.toString();\n return this.auth(`/v1/events/${encodeURIComponent(key)}/bookings${qs ? `?${qs}` : ''}`);\n }\n\n /** Exact configured-value snapshot plus book/replay/cancellation audit. */\n booking(key: string, bookingRef: string): Promise<InventoryBookingDetail> {\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/bookings/${encodeURIComponent(bookingRef)}`,\n );\n }\n\n /** Alias matching the server SDK vocabulary. */\n listBookings(key: string, query: InventoryBookingsQuery = {}): Promise<InventoryBookingsPage> {\n return this.bookings(key, query);\n }\n\n /** Alias matching the server SDK vocabulary. */\n retrieveBooking(key: string, bookingRef: string): Promise<InventoryBookingDetail> {\n return this.booking(key, bookingRef);\n }\n\n // ---- availability windows (token) ----\n\n /** The organizer's current per section/zone availability windows (needs\n * `event:view`). Ids absent from `rules` are open / on sale. */\n availability(key: string): Promise<{ rules: Record<string, AvailabilityRule> }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/availability`);\n }\n\n /** Replace the availability windows for a set of section/zone ids (needs\n * `event:block`). Ids absent from `rules` become open / on sale; a zone rule\n * cascades to its sections. The worker derives each id's seat labels, so\n * `labels` on the sent rules is best-effort. Resolves with the authoritative\n * effective `hidden` set (a due rule may fire at once) and the server-cleaned\n * `rules` map (fired timed/threshold windows dropped). */\n setAvailability(\n key: string,\n rules: Record<string, AvailabilityRule>,\n ): Promise<{ ok: true; hidden: string[]; rules: Record<string, AvailabilityRule> }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/availability`, { method: 'POST', body: { rules } });\n }\n\n // ---- sales channels (token, capability-gated) ----\n // Reads need `event:channels:view`, mutations `event:channels:manage`.\n // `event:block` grants NEITHER (spec §10), so a Block-only cockpit token gets\n // a 403 here and Channels mode never renders.\n\n /** Allocation list with exact per-channel counts. `includeArchived` adds the\n * read-only archived rows behind the rail's \"Show archived\" control. */\n channels(key: string, opts: { includeArchived?: boolean } = {}): Promise<ChannelListResult> {\n const qs = opts.includeArchived ? '?includeArchived=1' : '';\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels${qs}`);\n }\n\n /** One page of the label → channel map that paints the allocation overlay.\n * Paged by label; follow `nextAfterLabel` until it is null. */\n channelAllocation(\n key: string,\n opts: { afterLabel?: string; limit?: number } = {},\n ): Promise<ChannelAllocationPage> {\n const params = new URLSearchParams();\n if (opts.afterLabel) params.set('afterLabel', opts.afterLabel);\n if (opts.limit != null) params.set('limit', String(opts.limit));\n const qs = params.toString();\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/allocation${qs ? `?${qs}` : ''}`);\n }\n\n channelAudit(key: string, opts: { limit?: number; before?: number } = {}): Promise<ChannelAuditPage> {\n const params = new URLSearchParams();\n if (opts.limit != null) params.set('limit', String(opts.limit));\n if (opts.before != null) params.set('before', String(opts.before));\n const qs = params.toString();\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/audit${qs ? `?${qs}` : ''}`);\n }\n\n createChannel(\n key: string,\n input: { name: string; color?: string | null; marker?: string | null; externalRef?: string | null },\n ): Promise<{ ok: true; channel: ChannelRecord }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels`, { method: 'POST', body: input });\n }\n\n renameChannel(key: string, channelId: string, name: string): Promise<{ ok: true; channel: ChannelRecord }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}`, {\n method: 'PATCH', body: { name },\n });\n }\n\n setChannelPaused(key: string, channelId: string, paused: boolean): Promise<{ ok: true; channel: ChannelRecord }> {\n const path = paused ? 'pause' : 'unpause';\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/${path}`,\n { method: 'POST', body: {} },\n );\n }\n\n /** Archive with a mandatory destination for the remaining allocation.\n * Throws ManageApiError 409 `channel_archive_blocked_by_holds` while any hold\n * is live; `err.details` carries the exact counts + retry window. */\n archiveChannel(\n key: string,\n channelId: string,\n destination: string | null,\n ): Promise<{ ok: true; channel: ChannelRecord; assignmentVersion: number; moved: number }> {\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/archive`,\n { method: 'POST', body: { destination } },\n );\n }\n\n /**\n * Versioned Apply. A stale `assignmentVersion` mutates NOTHING and throws\n * ManageApiError 409 `channel_assignment_conflict` — the caller keeps its\n * selection and offers \"Refresh and review\". There is no dry-run: the review\n * sheet previews locally, this call returns the authoritative buckets.\n */\n applyChannelAssignment(\n key: string,\n input: { targetChannelId: string | null; labels: string[]; assignmentVersion: number },\n ): Promise<AssignmentResult> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/assignments`, {\n method: 'POST',\n body: {\n targetChannelId: input.targetChannelId || null,\n labels: input.labels,\n assignmentVersion: input.assignmentVersion,\n },\n });\n }\n\n /**\n * Read-only buyer projection for an audience (§8.6) — the SAME scoped server\n * view the buyer SDK receives, never a local approximation.\n *\n * Ships on the access-hardening branch. Older workers 404/405 here; callers\n * MUST feature-detect and quietly say the preview needs a newer server rather\n * than faking a projection client-side.\n */\n channelPreview(\n key: string,\n channelIds: string[],\n opts: { includePublic?: boolean } = {},\n ): Promise<ChannelPreviewProjection> {\n const params = new URLSearchParams();\n if (channelIds.length) params.set('channelIds', channelIds.join(','));\n if (opts.includePublic != null) params.set('includePublic', opts.includePublic ? '1' : '0');\n const qs = params.toString();\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/preview${qs ? `?${qs}` : ''}`);\n }\n\n /**\n * Choose which sale route this channel opens.\n *\n * Since the server's 2026-08-06 change this is AUTHORIZATION, not a label:\n * exactly one of the four routes may mint buyer access for the channel and the\n * other three refuse with 409 `channel_access_intent_forbids`. The default is\n * `none`, which refuses all four — so a route has to be declared before any\n * buyer-facing action on the channel can succeed.\n *\n * Switching the route while buyers are already inside the current one is\n * refused with 409 `channel_intent_switch_blocked`, whose `details` name what\n * is live (`liveAccessLinks`, `activeSessions`). Retry with\n * `acknowledgeLiveAccess: true`: hosted links on the channel are revoked,\n * while sessions already minted keep their holds and drain on their own.\n * `intentSwitch` is present on the response ONLY when the switch disturbed\n * something, so the ordinary case stays the two-key body it has always been.\n */\n setChannelAccessIntent(\n key: string,\n channelId: string,\n accessIntent: ChannelAccessIntent,\n opts: { acknowledgeLiveAccess?: boolean; reason?: string } = {},\n ): Promise<{\n ok: true;\n channel: ChannelRecord;\n intentSwitch?: { closedLinks: number; keptSessions: number };\n }> {\n return this.auth(`/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}`, {\n method: 'PATCH',\n body: {\n accessIntent,\n ...(opts.acknowledgeLiveAccess ? { acknowledgeLiveAccess: true } : {}),\n ...(opts.reason ? { reason: opts.reason } : {}),\n },\n });\n }\n\n // ---- hosted access links (M8) ----\n\n /**\n * Mint a hosted access link. The 201 is the ONE and ONLY time `url` and\n * `capability` exist outside the buyer's browser — SeatLayer keeps a hash, so\n * there is no route, cache, or support escalation that can produce this string\n * again. Callers must reveal it immediately and then let it go.\n *\n * Every omitted field takes the server's default: expiry = when the event\n * starts, 100 redemptions, 4 seats per buyer, this channel's allocation only.\n * Platform bounds are enforced server-side and reported as 422 with the rule\n * spelled out in `ManageApiError.serverMessage`.\n *\n * NOT a side effect any more. This used to SET the channel's access intent to\n * `hosted_link`; since 2026-08-06 it REQUIRES it, and a channel declaring any\n * other route refuses with 409 `channel_access_intent_forbids`. Callers must\n * declare the route first — `ChannelsMode` does exactly that before it\n * creates, so a first buyer link on a fresh channel is still one gesture.\n */\n createAccessLink(\n key: string,\n channelId: string,\n input: {\n label?: string | null;\n /** Absolute epoch ms. Omit for \"when the event starts\". */\n expiresAt?: number;\n maxRedemptions?: number;\n maxQuantity?: number;\n includePublic?: boolean;\n } = {},\n ): Promise<AccessLinkReveal> {\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/access-links`,\n { method: 'POST', body: input },\n );\n }\n\n /** Status only — label, expiry, redemptions, per-buyer cap, lineage, and the\n * live session count. Never the url, never the capability. Needs `:view`. */\n accessLinks(key: string, channelId: string): Promise<{ links: AccessLinkStatusRecord[] }> {\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/access-links`,\n );\n }\n\n /**\n * Rotate — the ONLY recovery for a link nobody kept. The old URL stops opening\n * immediately and the response is a fresh one-time reveal.\n *\n * `endActiveSessions` is REQUIRED, not defaulted: the organizer must say\n * whether buyers already inside finish their checkout or lose access now. The\n * server answers 422 `end_active_sessions_required` if it is omitted, and that\n * refusal is correct — a UI must not pick either branch on their behalf.\n */\n rotateAccessLink(\n key: string,\n channelId: string,\n linkId: string,\n endActiveSessions: boolean,\n ): Promise<AccessLinkReveal & { previous: AccessLinkRecord; endedSessions: number }> {\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}`\n + `/access-links/${encodeURIComponent(linkId)}/rotate`,\n { method: 'POST', body: { endActiveSessions } },\n );\n }\n\n /** Revoke. The link stops opening immediately; `endActiveSessions` decides\n * whether the buyers already inside keep their sessions. */\n revokeAccessLink(\n key: string,\n channelId: string,\n linkId: string,\n endActiveSessions = false,\n ): Promise<{ ok: true; link: AccessLinkRecord; endedSessions: number }> {\n const qs = endActiveSessions ? '?endActiveSessions=1' : '';\n return this.auth(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}`\n + `/access-links/${encodeURIComponent(linkId)}${qs}`,\n { method: 'DELETE' },\n );\n }\n\n // ---- reports (token) ----\n\n report(key: string): Promise<ReportResult> {\n return this.auth<unknown>(`/v1/events/${encodeURIComponent(key)}/report`).then(normalizeReportResult);\n }\n\n controlRoom(key: string, windowMinutes = 15): Promise<ControlRoomSnapshot> {\n return this.auth<unknown>(\n `/v1/events/${encodeURIComponent(key)}/control-room?window=${windowMinutes}`,\n ).then(normalizeControlRoomSnapshot);\n }\n\n /** Allocation beside immutable booking-time channel attribution. */\n channelReport(key: string): Promise<ChannelReportResult> {\n return this.auth<unknown>(\n `/v1/events/${encodeURIComponent(key)}/channels/report`,\n ).then(normalizeChannelReportResult);\n }\n\n createChannelReportLink(\n key: string,\n channelId: string,\n input: {\n label?: string;\n includesBookedValue?: boolean;\n /** @deprecated Use `includesBookedValue`. */\n includesRevenue?: boolean;\n expiresAt?: number;\n } = {},\n ): Promise<ChannelReportLinkReveal> {\n return this.auth<unknown>(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/report-links`,\n { method: 'POST', body: input },\n ).then((value) => {\n const reveal = record(value);\n return { ...reveal, link: normalizeChannelReportLink(reveal.link) } as unknown as ChannelReportLinkReveal;\n });\n }\n\n channelReportLinks(key: string, channelId: string): Promise<{ links: ChannelReportLinkRecord[] }> {\n return this.auth<unknown>(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}/report-links`,\n ).then((value) => {\n const result = record(value);\n return {\n links: Array.isArray(result.links) ? result.links.map(normalizeChannelReportLink) : [],\n };\n });\n }\n\n revokeChannelReportLink(\n key: string,\n channelId: string,\n linkId: string,\n ): Promise<{ ok: true; link: ChannelReportLinkRecord }> {\n return this.auth<unknown>(\n `/v1/events/${encodeURIComponent(key)}/channels/${encodeURIComponent(channelId)}`\n + `/report-links/${encodeURIComponent(linkId)}`,\n { method: 'DELETE' },\n ).then((value) => {\n const result = record(value);\n return { ...result, link: normalizeChannelReportLink(result.link) } as unknown as {\n ok: true; link: ChannelReportLinkRecord;\n };\n });\n }\n\n log(key: string, opts: { limit?: number; before?: number } = {}): Promise<LogPage> {\n const params = new URLSearchParams();\n if (opts.limit != null) params.set('limit', String(opts.limit));\n if (opts.before != null) params.set('before', String(opts.before));\n const qs = params.toString();\n return this.auth(`/v1/events/${encodeURIComponent(key)}/log${qs ? `?${qs}` : ''}`);\n }\n\n /** CSV report as a Blob (Bearer auth can't ride a plain <a href>). Host builds\n * an object URL for download. */\n async reportCsv(key: string): Promise<Blob> {\n const res = await fetch(`${this.base}/v1/events/${encodeURIComponent(key)}/report.csv`, {\n headers: { Authorization: `Bearer ${this.token}` },\n credentials: 'omit',\n });\n if (!res.ok) throw new ManageApiError(res.status, `request_failed_${res.status}`);\n return res.blob();\n }\n}\n","/**\n * Sales-channel planning — the pure, DOM-free half of Channels mode.\n *\n * Everything here is deterministic and testable without a canvas: the marker\n * palette, the mixed-source selection summary, the LOCAL staged preview of an\n * assignment, and the bucket rows the Review sheet renders.\n *\n * The local preview deliberately produces the SAME `AssignmentBuckets` shape the\n * server returns from `POST /channels/assignments`. There is no dry-run endpoint,\n * so the review sheet is drawn from this local computation and then REDRAWN from\n * the authoritative server response after Apply. One renderer, two sources —\n * which is why the shapes must match exactly.\n *\n * Spec: sales-channels-product-ux-spec §8.4–8.5.\n */\n\n/**\n * Public sale is a built-in pseudo-channel. The server's sentinel for it is the\n * literal string `'public'` — it is what `GET /channels` returns as\n * `publicSale.id`, what `GET /channels/allocation` reports for an unallocated\n * unit, and what `POST /channels/assignments` accepts (alongside `null`) as the\n * target meaning \"send these back to public sale\".\n *\n * This constant was `''` until 2026-08-02, which silently made every public unit\n * look like an unknown PRIVATE channel to `planAssignment` and `markerOf` — the\n * cause of the Review sheet's phantom \"moved out of another channel\" line and\n * the rail's \"?\" marker. Keep it byte-identical to the server's\n * `eventChannels.PUBLIC_CHANNEL_ID`.\n */\nexport const PUBLIC_CHANNEL_ID = 'public';\nexport const PUBLIC_CHANNEL_NAME = 'Public sale';\n\n/** True for every spelling of \"public sale\" a worker may hand us. */\nexport function isPublicChannelId(id: string | null | undefined): boolean {\n return id == null || id === '' || id === PUBLIC_CHANNEL_ID;\n}\n\nexport type ChannelState = 'active' | 'paused' | 'archived';\n\n/** Physical inventory status, as the manage surface speaks it. */\nexport type ChannelSeatStatus = 'free' | 'held' | 'booked' | 'blocked';\n\nexport interface ChannelCounts {\n allocated: number;\n free: number;\n held: number;\n booked: number;\n blocked: number;\n units: number;\n}\n\n/** Buyer-access intents the server stores per channel. */\nexport type ChannelAccessIntent = 'none' | 'internal' | 'server' | 'hosted_link';\n\n/**\n * Buyer-access summary on a channel row. Shipped by the access hardening branch\n * (merged to app main). Still optional in this type: a worker that predates the\n * merge simply omits it and the rail reads \"—\" rather than inventing a state.\n */\nexport interface ChannelAccessSummary {\n intent?: ChannelAccessIntent | string;\n hasActiveGrants?: boolean;\n lastMintAt?: number | null;\n /** Free-text detail (partner host, who paused it) when the server offers one. */\n detail?: string | null;\n}\n\nexport interface ChannelRecord {\n id: string;\n name: string;\n color: string | null;\n marker: string | null;\n externalRef: string | null;\n state: ChannelState;\n archiveDestination: string | null;\n createdAt: number;\n updatedAt: number;\n archivedAt: number | null;\n counts: ChannelCounts;\n access?: ChannelAccessSummary | null;\n}\n\nexport interface PublicSaleChannel {\n /** `'public'` on every shipped worker; typed loosely so an older build that\n * still answers `''` is normalised rather than rejected. */\n id: string;\n name: string;\n state: 'active';\n counts: ChannelCounts;\n access?: ChannelAccessSummary | null;\n}\n\nexport interface ChannelListResult {\n assignmentVersion: number;\n publicSale: PublicSaleChannel;\n channels: ChannelRecord[];\n}\n\nexport interface AssignmentBucketCount {\n count: number;\n}\n\nexport interface AssignmentSkippedBucket extends AssignmentBucketCount {\n labels: string[];\n truncated: boolean;\n}\n\nexport interface AssignmentBuckets {\n changedFromPublic: AssignmentBucketCount;\n movedFromOtherChannel: AssignmentBucketCount & {\n channels: Array<{ channelId: string; name: string | null; count: number }>;\n };\n alreadyInTarget: AssignmentBucketCount;\n skippedHeld: AssignmentSkippedBucket;\n skippedBooked: AssignmentSkippedBucket;\n /** Requested labels that are not inventory in this event. */\n notFound: AssignmentSkippedBucket;\n}\n\nexport interface AssignmentResult {\n ok: true;\n targetChannelId: string;\n assignmentVersion: number;\n requested: number;\n applied: number;\n buckets: AssignmentBuckets;\n}\n\nexport interface ArchiveBlockedDetails {\n activeHolds?: number;\n heldUnits?: number;\n latestHoldExpiresAt?: number | null;\n retryAfterMs?: number;\n}\n\n/**\n * Administrative colors. Always paired with a LETTER on every surface — the\n * comp's rule and spec §13's: channel identity never rests on hue alone.\n */\nexport const CHANNEL_COLORS = [\n '#a78bfa', '#2dd4bf', '#fb923c', '#60a5fa', '#f472b6',\n '#a3e635', '#f87171', '#38bdf8', '#c084fc', '#facc15',\n] as const;\n\n/** Public sale keeps the cockpit's gold, distinct from every private channel. */\nexport const PUBLIC_CHANNEL_COLOR = '#f4b740';\n\nconst LETTERS = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // no I/O — they read as 1/0\n\n/**\n * Clamp any marker text down to the ONE uppercase character every surface draws.\n *\n * The server stores `marker` as free text (it only length-caps it), so a channel\n * created outside this widget can carry \"star\" or \"VIP\". The comp's marker chip\n * is a single glyph: taking two characters (\"ST\") overflows the 22px chip and\n * stops reading as a letter. Non-letter leading characters (an emoji, a digit,\n * punctuation) are skipped in favour of the first real letter.\n */\nexport function markerLetter(raw: string | null | undefined, fallback: string): string {\n const text = (raw ?? '').trim();\n const letter = /\\p{L}/u.exec(text)?.[0] ?? text[0] ?? '';\n return (letter || fallback).toUpperCase().slice(0, 1);\n}\n\n/**\n * Suggest a marker for a new channel: the first letter of its name when that\n * letter is still free, otherwise the next unused letter. Deterministic so the\n * Create dialog's preview matches what actually gets stored.\n */\nexport function suggestMarker(\n name: string,\n taken: Iterable<string>,\n): { letter: string; color: string } {\n const used = new Set([...taken].map((m) => markerLetter(m, '')).filter(Boolean));\n const first = markerLetter(name, '');\n const letter = LETTERS.includes(first) && !used.has(first)\n ? first\n : ([...LETTERS].find((candidate) => !used.has(candidate)) ?? (first || 'X'));\n return { letter, color: CHANNEL_COLORS[used.size % CHANNEL_COLORS.length] };\n}\n\n/** The letter + color a channel actually renders with (server value wins). */\nexport function markerOf(\n channel: { id: string; name: string; marker?: string | null; color?: string | null },\n index = 0,\n): { letter: string; color: string } {\n if (isPublicChannelId(channel.id)) {\n return {\n letter: markerLetter(channel.marker, 'P'),\n color: channel.color || PUBLIC_CHANNEL_COLOR,\n };\n }\n const letter = markerLetter(channel.marker || channel.name, '?');\n return { letter, color: channel.color || CHANNEL_COLORS[index % CHANNEL_COLORS.length] };\n}\n\n/** One line of the rail's mixed-source selection summary (§8.4). */\nexport interface SelectionSourceRow {\n channelId: string;\n name: string;\n count: number;\n}\n\n/**\n * Group the current selection by the channel each unit is allocated to today.\n * Public sale is listed first; the rest follow in list order so the rail's\n * ordering never jitters as the selection changes.\n */\nexport function selectionSources(\n labels: string[],\n allocation: Map<string, string>,\n list: ChannelListResult | null,\n): SelectionSourceRow[] {\n const counts = new Map<string, number>();\n for (const label of labels) {\n const channelId = normalizeChannelId(allocation.get(label));\n counts.set(channelId, (counts.get(channelId) ?? 0) + 1);\n }\n const order: Array<{ id: string; name: string }> = [\n { id: PUBLIC_CHANNEL_ID, name: list?.publicSale?.name ?? PUBLIC_CHANNEL_NAME },\n ...(list?.channels ?? []).map((channel) => ({ id: channel.id, name: channel.name })),\n ];\n const rows: SelectionSourceRow[] = [];\n for (const entry of order) {\n const count = counts.get(entry.id);\n if (count) rows.push({ channelId: entry.id, name: entry.name, count });\n counts.delete(entry.id);\n }\n // Anything the list does not know about (archived, or a mid-flight rename).\n for (const [channelId, count] of counts) {\n rows.push({\n channelId,\n name: isPublicChannelId(channelId) ? PUBLIC_CHANNEL_NAME : 'Another channel',\n count,\n });\n }\n return rows;\n}\n\n/**\n * Fold every \"this unit is on public sale\" spelling onto ONE id.\n *\n * The allocation map is built from `GET /channels/allocation`, which reports an\n * unallocated unit as the server's `'public'` sentinel; a missing entry means\n * the same thing. Comparing raw values here is what made public units classify\n * as `movedFromOtherChannel` in the staged preview while the server's\n * authoritative reply said `changedFromPublic`.\n */\nfunction normalizeChannelId(id: string | null | undefined): string {\n return isPublicChannelId(id) ? PUBLIC_CHANNEL_ID : id as string;\n}\n\nconst SKIP_SAMPLE = 12;\n\nfunction skipBucket(labels: string[]): AssignmentSkippedBucket {\n return {\n count: labels.length,\n labels: labels.slice(0, SKIP_SAMPLE),\n truncated: labels.length > SKIP_SAMPLE,\n };\n}\n\n/**\n * The LOCAL staged preview of \"move these labels to this channel\".\n *\n * Mirrors the DO's rules exactly (eventChannels.applyAssignment):\n * - a unit already in the target is `alreadyInTarget`, whatever its status;\n * - otherwise held and booked units are skipped and never rewritten;\n * - otherwise a public unit is `changedFromPublic`, a private one is\n * `movedFromOtherChannel` (itemised per source);\n * - a label that is not inventory in this event is `notFound`.\n *\n * Every requested label lands in exactly one bucket — the property the Review\n * sheet's \"every selected seat is in exactly one line\" promise depends on.\n */\nexport function planAssignment(input: {\n labels: string[];\n targetChannelId: string;\n allocation: Map<string, string>;\n statusOf: (label: string) => ChannelSeatStatus | undefined;\n nameOf: (channelId: string) => string | null;\n}): AssignmentBuckets {\n const { labels, allocation, statusOf, nameOf } = input;\n const targetChannelId = normalizeChannelId(input.targetChannelId);\n const seen = new Set<string>();\n let fromPublic = 0;\n let alreadyIn = 0;\n const movedBySource = new Map<string, number>();\n const held: string[] = [];\n const booked: string[] = [];\n const missing: string[] = [];\n\n for (const label of labels) {\n if (seen.has(label)) continue;\n seen.add(label);\n const status = statusOf(label);\n if (!status) { missing.push(label); continue; }\n const current = normalizeChannelId(allocation.get(label));\n if (current === targetChannelId) { alreadyIn += 1; continue; }\n if (status === 'held') { held.push(label); continue; }\n if (status === 'booked') { booked.push(label); continue; }\n if (current === PUBLIC_CHANNEL_ID) fromPublic += 1;\n else movedBySource.set(current, (movedBySource.get(current) ?? 0) + 1);\n }\n\n const channels = [...movedBySource.entries()].map(([channelId, count]) => ({\n channelId,\n name: nameOf(channelId),\n count,\n }));\n return {\n changedFromPublic: { count: fromPublic },\n movedFromOtherChannel: {\n count: channels.reduce((sum, row) => sum + row.count, 0),\n channels,\n },\n alreadyInTarget: { count: alreadyIn },\n skippedHeld: skipBucket(held),\n skippedBooked: skipBucket(booked),\n notFound: skipBucket(missing),\n };\n}\n\n/** Units this plan will actually mutate — what the Apply button counts. */\nexport function mutationCount(buckets: AssignmentBuckets): number {\n return buckets.changedFromPublic.count + buckets.movedFromOtherChannel.count;\n}\n\n/** True when moving inventory out of another PRIVATE channel — §8.5 requires an\n * explicit confirmation line for exactly this case. */\nexport function needsMoveConfirmation(buckets: AssignmentBuckets): boolean {\n return buckets.movedFromOtherChannel.count > 0;\n}\n\nexport interface BucketRow {\n kind: 'add' | 'move' | 'same' | 'skip';\n icon: string;\n count: number;\n text: string;\n why?: string;\n /** Sampled seat labels for a skipped bucket, when the server sent any. */\n peek?: string;\n}\n\n/**\n * Render-ready rows for the Review sheet. The comp shows five lines; the server\n * carries a sixth bucket (`notFound`) which is emitted only when it is non-zero,\n * so a normal review still reads exactly like the approved design.\n *\n * Empty buckets are dropped — a zero line is noise, not honesty.\n */\nexport function bucketRows(buckets: AssignmentBuckets, targetName: string): BucketRow[] {\n const rows: BucketRow[] = [];\n if (buckets.changedFromPublic.count) {\n rows.push({\n kind: 'add', icon: '+', count: buckets.changedFromPublic.count,\n text: `${buckets.changedFromPublic.count.toLocaleString()} from ${PUBLIC_CHANNEL_NAME}`,\n });\n }\n for (const source of buckets.movedFromOtherChannel.channels) {\n rows.push({\n kind: 'move', icon: '⇄', count: source.count,\n text: `${source.count.toLocaleString()} moved out of ${source.name ?? 'another channel'}`,\n why: 'needs this confirmation',\n });\n }\n if (buckets.alreadyInTarget.count) {\n rows.push({\n kind: 'same', icon: '=', count: buckets.alreadyInTarget.count,\n text: `${buckets.alreadyInTarget.count.toLocaleString()} already in ${targetName}`,\n why: 'unchanged',\n });\n }\n if (buckets.skippedHeld.count) {\n rows.push({\n kind: 'skip', icon: '⏸', count: buckets.skippedHeld.count,\n text: `${buckets.skippedHeld.count.toLocaleString()} in a buyer's checkout`,\n why: \"can't move while held\",\n peek: peekOf(buckets.skippedHeld),\n });\n }\n if (buckets.skippedBooked.count) {\n rows.push({\n kind: 'skip', icon: '🔒', count: buckets.skippedBooked.count,\n text: `${buckets.skippedBooked.count.toLocaleString()} already sold`,\n why: 'sales are never rewritten',\n peek: peekOf(buckets.skippedBooked),\n });\n }\n if (buckets.notFound.count) {\n rows.push({\n kind: 'skip', icon: '?', count: buckets.notFound.count,\n text: `${buckets.notFound.count.toLocaleString()} not on this map`,\n why: 'these seats are no longer part of the event',\n peek: peekOf(buckets.notFound),\n });\n }\n return rows;\n}\n\nfunction peekOf(bucket: AssignmentSkippedBucket): string | undefined {\n if (!bucket.labels.length) return undefined;\n const shown = bucket.labels.slice(0, 4).join(', ');\n return bucket.truncated || bucket.labels.length > 4 ? `${shown}…` : shown;\n}\n\n/**\n * \"try again in ~N minutes\" for the archive-blocked-by-holds 409 (§8.8).\n * Rounds up so the organizer never comes back one tick early.\n */\nexport function retryAfterCopy(details: ArchiveBlockedDetails | null | undefined): string {\n const ms = details?.retryAfterMs ?? (details?.latestHoldExpiresAt\n ? Math.max(0, details.latestHoldExpiresAt - Date.now())\n : 0);\n if (!ms) return 'in a moment';\n const minutes = Math.ceil(ms / 60_000);\n if (minutes <= 1) return 'in about a minute';\n return `in about ${minutes} minutes`;\n}\n\n/** The access line under a channel row. Falls back to \"—\" before the hardening\n * branch lands the `access` field, never to a guess. */\nexport function accessLine(access: ChannelAccessSummary | null | undefined): string {\n if (!access || !access.intent) return '—';\n // Every one of the four is a real, enforced answer now (server 2026-08-06), so\n // each gets its own line. 'none' and 'internal' used to collapse into \"not\n // distributed yet\" because nothing read them; today `none` refuses every buyer\n // path and `internal` opens the staff one, and those are different facts.\n const base = access.intent === 'server' ? 'Website integration'\n : access.intent === 'hosted_link' ? 'Buyer link'\n : access.intent === 'internal' ? 'Your staff sell these'\n : 'Protected reserve';\n const grants = access.hasActiveGrants ? 'in use now'\n : access.lastMintAt ? `last used ${new Date(access.lastMintAt).toLocaleDateString()}` : null;\n const detail = access.detail ?? grants;\n return detail ? `${base} · ${detail}` : base;\n}\n\n/**\n * The name of each sale route, WORD FOR WORD as the server says it.\n *\n * `eventChannels.ts` builds its refusal sentences from an `INTENT_LABEL` map\n * with exactly these four strings. Diverging here would mean the picker calls a\n * route one thing and the refusal it produces calls it another, so these are\n * copied deliberately rather than paraphrased.\n */\nexport function accessIntentLabel(intent: ChannelAccessIntent): string {\n return intent === 'internal' ? 'Sell through your own staff'\n : intent === 'server' ? 'Integrate a website or app'\n : intent === 'hosted_link' ? 'Sell with a buyer link'\n : 'Keep as protected reserve';\n}\n\n/**\n * What choosing this route actually DOES, now that the server enforces it.\n *\n * Written against the enforcement matrix, not against intent: each route opens\n * exactly one way to reach a buyer and refuses the other three, so each sentence\n * says both halves. The old copy for these values promised nothing and delivered\n * nothing; it was deleted in 0.42.0 and is not coming back.\n */\nexport function accessIntentDescription(intent: ChannelAccessIntent): string {\n switch (intent) {\n case 'internal':\n return 'Only your own box office can sell these seats, through your secret key. '\n + 'Buyer links and website integrations are refused.';\n case 'server':\n return \"Your website's backend mints each buyer a short-lived session for these seats. \"\n + 'Buyer links are refused; the code lives on the Embed page.';\n case 'hosted_link':\n return 'SeatLayer makes a link you send to a named group. They open it and buy only these seats. '\n + 'No other route can sell them.';\n default:\n return 'Nobody can buy these seats. Every way of letting a buyer in — a buyer link, your website, '\n + 'even your own staff — is refused while this is the route. The seats stay out of public sale.';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Access-intent enforcement refusals (server 2026-08-06)\n// ---------------------------------------------------------------------------\n\n/** `channel_access_intent_forbids` (409) — the route this channel declares is\n * not the one the action needed. */\nexport interface AccessIntentForbidsDetails {\n channelId?: string;\n accessIntent?: ChannelAccessIntent | string;\n /** The route the refused action arrived on: `hosted_link` | `server` | `staff` | `public`. */\n route?: string;\n}\n\n/** Which declaration would have let the refused route through. The server's\n * matrix is one route per intent, so this inverts cleanly. */\nfunction intentForRoute(route: string | undefined): ChannelAccessIntent | null {\n return route === 'hosted_link' ? 'hosted_link'\n : route === 'server' ? 'server'\n : route === 'staff' ? 'internal' : null;\n}\n\n/**\n * The refusal, said as a decision the organizer can act on.\n *\n * The server's own sentence stops at \"…so it cannot be sold through a buyer\n * link\" — true, but it leaves the reader to work out what to do. This adds the\n * second half: which route to switch to. The code itself is never shown.\n */\nexport function intentForbidsCopy(details: AccessIntentForbidsDetails | null | undefined): string {\n const current = parseIntent(details?.accessIntent);\n const wanted = intentForRoute(details?.route);\n const head = `This channel is set to \"${accessIntentLabel(current)}\"`;\n return wanted\n ? `${head}, so it cannot do that. Switch it to \"${accessIntentLabel(wanted)}\" first.`\n : `${head}, so it cannot do that. Choose a different route for this channel first.`;\n}\n\n/** `channel_intent_switch_blocked` (409) — buyers are inside the current route. */\nexport interface IntentSwitchBlockedDetails {\n channelId?: string;\n from?: ChannelAccessIntent | string;\n to?: ChannelAccessIntent | string;\n liveAccessLinks?: number;\n activeSessions?: number;\n acknowledgeWith?: { acknowledgeLiveAccess?: boolean };\n}\n\nfunction parseIntent(value: unknown): ChannelAccessIntent {\n return value === 'internal' || value === 'server' || value === 'hosted_link' || value === 'none'\n ? value : 'none';\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count.toLocaleString()} ${count === 1 ? one : many}`;\n}\n\n/**\n * What is live right now, and what acknowledging would do to it.\n *\n * Both halves are checked against the server rather than guessed: an\n * acknowledged switch REVOKES the channel's hosted links (redemption refuses\n * from that moment, so a link left listed as active would be a door the\n * management surface advertises and the buyer path denies), and deliberately\n * LEAVES buyer sessions and their holds alone — nobody is thrown out of a\n * checkout. Sessions cap at 12 hours (30 minutes by default) and no new ones can\n * be minted, so the old route drains on its own.\n */\nexport function intentSwitchBlockedCopy(\n details: IntentSwitchBlockedDetails | null | undefined,\n): { headline: string; consequences: string[] } {\n const links = Math.max(0, details?.liveAccessLinks ?? 0);\n const sessions = Math.max(0, details?.activeSessions ?? 0);\n const from = parseIntent(details?.from);\n const to = parseIntent(details?.to);\n const live = [\n links ? plural(links, 'buyer link is live', 'buyer links are live') : null,\n sessions ? plural(sessions, 'buyer is in a checkout', 'buyers are in a checkout') : null,\n ].filter(Boolean).join(', and ');\n const headline = `${live || 'Buyers are inside this channel'} on \"${accessIntentLabel(from)}\". `\n + `Moving it to \"${accessIntentLabel(to)}\" changes what happens to them.`;\n const consequences: string[] = [];\n if (links) {\n consequences.push(`${plural(links, 'buyer link closes', 'buyer links close')} immediately. `\n + 'Anyone who has not opened it yet never will — send a new link if you still need one.');\n }\n if (sessions) {\n consequences.push(`${plural(sessions, 'buyer who is already in a checkout keeps', 'buyers who are already in a checkout keep')} `\n + 'their seats and can finish paying. Nobody is thrown out. No new buyers come in this way, '\n + 'so the old route empties on its own within 12 hours.');\n }\n return { headline, consequences };\n}\n\n// ---------------------------------------------------------------------------\n// Hosted access links (M8)\n// ---------------------------------------------------------------------------\n\n/** Lifecycle the server stores. `rotated` means a newer link replaced this one. */\nexport type AccessLinkState = 'active' | 'revoked' | 'rotated';\n\n/** What the organizer surface renders: `state`, unless an active link has run\n * out of time or out of redemptions. Never a capability, never a hash. */\nexport type AccessLinkStatus = AccessLinkState | 'expired' | 'exhausted';\n\n/**\n * One hosted link, exactly as `GET …/access-links` projects it.\n *\n * There is deliberately NO `url` and NO `capability` field here — the listing\n * route does not return them, no other route returns them, and this type must\n * not tempt a caller into believing otherwise. The secret exists in exactly one\n * place for exactly one moment: the create/rotate response (`AccessLinkReveal`).\n */\nexport interface AccessLinkRecord {\n id: string;\n channelId: string;\n label: string | null;\n includePublic: boolean;\n expiresAt: number;\n maxRedemptions: number;\n redemptions: number;\n /** Guest-weighted per-buyer ceiling handed to every session this link mints. */\n maxQuantity: number;\n sessionTtlSeconds: number;\n state: AccessLinkState;\n status: AccessLinkStatus;\n createdAt: number;\n createdBy: string | null;\n revokedAt: number | null;\n lastRedeemedAt: number | null;\n /** Rotation lineage: the link this replaced, and the one that replaced it. */\n rotatedFrom: string | null;\n rotatedTo: string | null;\n}\n\n/** A listed link, with the live session count the rotate dialog needs to state\n * \"N buyers got in with this link and still have access\". */\nexport interface AccessLinkStatusRecord extends AccessLinkRecord {\n activeSessions?: number;\n}\n\n/**\n * The ONE-TIME reveal. `url` and `capability` are on the wire exactly once, in\n * the create/rotate response, and are unrecoverable afterwards: SeatLayer stores\n * only a hash. Nothing may persist this — see `ChannelsMode.revealLink`.\n */\nexport interface AccessLinkReveal {\n link: AccessLinkRecord;\n url: string;\n capability: string;\n revealedOnce: true;\n /** Rotation only: the link that just stopped working, and how many live buyer\n * sessions from it were ended (0 when the organizer let them finish). */\n previous?: AccessLinkRecord;\n endedSessions?: number;\n}\n\n/**\n * Owner-set defaults for a new link. Expiry is NOT here: \"when the event starts\"\n * is the server's own default (it knows `starts_at`; the cockpit does not), so\n * the create form expresses that choice by omitting `expiresAt` entirely rather\n * than by guessing a timestamp the server would then have to correct.\n */\nexport const ACCESS_LINK_DEFAULTS = {\n maxRedemptions: 100,\n maxQuantity: 4,\n} as const;\n\n/** Plain-language state badge for a hosted link (§9: no internal vocabulary). */\nexport function accessLinkBadge(link: Pick<AccessLinkRecord, 'status' | 'state'>): {\n text: string; kind: 'active' | 'paused' | 'archived';\n} {\n switch (link.status ?? link.state) {\n case 'active': return { text: 'Active', kind: 'active' };\n case 'expired': return { text: 'Expired', kind: 'archived' };\n case 'exhausted': return { text: 'All used', kind: 'paused' };\n case 'rotated': return { text: 'Replaced', kind: 'archived' };\n default: return { text: 'Revoked', kind: 'archived' };\n }\n}\n\n/** Only an `active` link can be rotated or revoked; the server agrees (409\n * `access_link_not_active`), so the buttons are absent rather than failing. */\nexport function accessLinkIsLive(link: Pick<AccessLinkRecord, 'status' | 'state'>): boolean {\n return link.state === 'active' && link.status === 'active';\n}\n\nfunction formatMoment(ms: number): string {\n if (!Number.isFinite(ms)) return '—';\n return new Date(ms).toLocaleString(undefined, {\n day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit',\n });\n}\n\n/**\n * The policy an organizer is agreeing to, in one list. Used by BOTH the reveal\n * (what you just created) and the status card (what is live), so the two can\n * never drift into describing the same link differently.\n */\nexport function accessLinkPolicyLines(link: AccessLinkRecord): Array<{ k: string; v: string }> {\n return [\n { k: 'Expires', v: formatMoment(link.expiresAt) },\n {\n k: 'Redemptions',\n v: `${link.redemptions.toLocaleString()} of ${link.maxRedemptions.toLocaleString()} used`,\n },\n {\n k: 'Seats per buyer',\n v: `${link.maxQuantity.toLocaleString()} seat${link.maxQuantity === 1 ? '' : 's'} maximum`,\n },\n {\n k: 'Covers',\n v: link.includePublic\n ? \"This channel's allocation and Public sale seats\"\n : \"This channel's allocation only\",\n },\n ];\n}\n\n/**\n * Plain language for a refused hosted-link call.\n *\n * The PLATFORM BOUNDS live on the server (60s–180d expiry, 1–10 000 redemptions,\n * 1–100 seats per buyer, 20 live links per channel) and the server states them\n * in `message`. We surface that sentence rather than re-encoding the numbers\n * here, so the client can never disagree with the rule it is reporting.\n */\nexport function accessLinkErrorCopy(\n err: {\n code?: string; serverMessage?: string; status?: number; details?: Record<string, unknown>;\n } | null | undefined,\n): string {\n const fromServer = err?.serverMessage?.trim();\n switch (err?.code) {\n case 'invalid_expiry':\n case 'invalid_max_redemptions':\n case 'invalid_max_quantity':\n case 'invalid_session_ttl':\n case 'invalid_label':\n return fromServer || 'That setting is outside what a hosted link allows. Adjust it and try again.';\n case 'too_many_access_links':\n return fromServer\n || 'This channel already has as many live links as it can hold. Revoke one before creating another.';\n case 'access_link_not_active':\n return 'That link is no longer active, so it cannot be rotated or revoked.';\n case 'channel_unavailable':\n return 'This channel is paused or archived, so it cannot let new buyers in. Resume it first.';\n // The channel declares a different sale route. The UI declares `hosted_link`\n // before it creates, so reaching this means the declaration itself was\n // refused or raced — say which route is in the way, not the code.\n case 'channel_access_intent_forbids':\n return intentForbidsCopy(err?.details as AccessIntentForbidsDetails | undefined);\n case 'end_active_sessions_required':\n return 'Choose what happens to the buyers who already came in through this link.';\n case 'not_found':\n return 'That link is no longer here. Refresh and try again.';\n default:\n if (err?.status === 403) return 'Hosted access links need channel-management permission.';\n return fromServer || 'That did not go through. Try again.';\n }\n}\n\n/**\n * The chart-update refusal `channel_assignment_would_drop` (409) deliberately\n * mirrors the Apply skipped buckets, so ONE review component renders both.\n * This adapts it into the same `BucketRow[]` the Review sheet already draws.\n */\nexport interface AssignmentDropDetails {\n droppedUnits?: number;\n channels?: Array<{ channelId: string; name: string | null; count: number; labels?: string[]; truncated?: boolean }>;\n acknowledgeWith?: string;\n}\n\nexport function dropReviewRows(details: AssignmentDropDetails | null | undefined): BucketRow[] {\n return (details?.channels ?? []).map((channel) => ({\n kind: 'skip' as const,\n icon: '⚠',\n count: channel.count,\n text: `${channel.count.toLocaleString()} would leave ${channel.name ?? 'a channel'}`,\n why: 'the new chart no longer has these seats',\n peek: channel.labels?.length\n ? peekOf({ count: channel.count, labels: channel.labels, truncated: channel.truncated ?? false })\n : undefined,\n }));\n}\n\n/** Plain-language state badge text (§9: no internal vocabulary on user surfaces). */\nexport function stateBadge(state: ChannelState | 'builtin'): string {\n return state === 'builtin' ? 'Built-in'\n : state === 'active' ? 'Active'\n : state === 'paused' ? 'Paused' : 'Archived';\n}\n","/**\n * Channels mode — the sales-channel management surface inside the SeatManager\n * cockpit. It ships in the SDK, so every embedding platform (and our own Control\n * Room) gets the same organizer experience.\n *\n * Design contract: `SeatmapUX/05 Event Manager.dc.html` (all 8 desktop states +\n * the mobile artboard). Behaviour: sales-channels-product-ux-spec §8 (states),\n * §9 (language), §13 (a11y + compact detents). Motion: motion-system §2 tokens,\n * mirrored here as `--slm-mo-*` so an embed is self-contained, and §3 cockpit\n * choreography.\n *\n * Boundaries this module keeps:\n *\n * - **Capability gating is fail-closed.** Without `event:channels:view` the\n * cockpit never renders the pill (SeatManager's job). Without\n * `event:channels:manage` every mutation control is ABSENT — not disabled —\n * so a read-only operator is never shown authority they do not have.\n * - **Nothing here mutates physical inventory.** Assignment moves an\n * allocation; held and booked units are never rewritten.\n * - **Staging is local, truth is the server.** There is no dry-run endpoint,\n * so the Review sheet previews the buckets client-side and then re-renders\n * the AUTHORITATIVE bucket counts from the Apply response. A stale\n * `assignmentVersion` mutates nothing: the selection survives and the only\n * action offered is Refresh and review.\n * - **Forward-compatible reads.** The `access` field and the buyer-preview\n * projection land on the access-hardening branch. Both are feature-detected;\n * absent, the access line reads \"—\" and the Preview segment says it needs a\n * newer server. Neither ever blocks allocation work.\n */\nimport {\n ACCESS_LINK_DEFAULTS,\n PUBLIC_CHANNEL_ID,\n PUBLIC_CHANNEL_NAME,\n accessIntentDescription,\n accessIntentLabel,\n accessLine,\n accessLinkBadge,\n accessLinkErrorCopy,\n accessLinkIsLive,\n accessLinkPolicyLines,\n bucketRows,\n isPublicChannelId,\n markerLetter,\n markerOf,\n mutationCount,\n needsMoveConfirmation,\n planAssignment,\n intentForbidsCopy,\n intentSwitchBlockedCopy,\n retryAfterCopy,\n selectionSources,\n stateBadge,\n suggestMarker,\n type AccessIntentForbidsDetails,\n type AccessLinkReveal,\n type AccessLinkStatusRecord,\n type AssignmentBuckets,\n type AssignmentResult,\n type ArchiveBlockedDetails,\n type BucketRow,\n type IntentSwitchBlockedDetails,\n type ChannelAccessIntent,\n type ChannelListResult,\n type ChannelRecord,\n type ChannelSeatStatus,\n} from './channelPlan';\nimport type {\n ChannelAllocationPage,\n ChannelPreviewProjection,\n} from './manageApi';\nimport { ManageApiError } from './manageApi';\n\n/** The seat facts the overlay needs. Chart space, not screen space. */\nexport interface ChannelsSeatView {\n id: string;\n label: string;\n x: number;\n y: number;\n}\n\n/** One row offered to the bulk assignment chooser. A physically segmented row\n * (one label split across several row objects) shares one logical id, so the\n * organizer picks \"Row AA\" once rather than three fragments of it. */\nexport interface ChannelsRowView {\n id: string;\n label: string;\n sectionId: string;\n sectionLabel: string;\n labels: string[];\n}\n\n/** The `ManageApi` subset Channels mode uses — structural so tests can pass a\n * hand-rolled double without constructing a real client. */\nexport interface ChannelsClient {\n channels(key: string, opts?: { includeArchived?: boolean }): Promise<ChannelListResult>;\n channelAllocation(key: string, opts?: { afterLabel?: string; limit?: number }): Promise<ChannelAllocationPage>;\n createChannel(\n key: string,\n input: { name: string; color?: string | null; marker?: string | null; externalRef?: string | null },\n ): Promise<{ ok: true; channel: ChannelRecord }>;\n renameChannel(key: string, channelId: string, name: string): Promise<{ ok: true; channel: ChannelRecord }>;\n setChannelPaused(key: string, channelId: string, paused: boolean): Promise<{ ok: true; channel: ChannelRecord }>;\n archiveChannel(\n key: string,\n channelId: string,\n destination: string | null,\n ): Promise<{ ok: true; channel: ChannelRecord; assignmentVersion: number; moved: number }>;\n applyChannelAssignment(\n key: string,\n input: { targetChannelId: string | null; labels: string[]; assignmentVersion: number },\n ): Promise<AssignmentResult>;\n channelPreview(\n key: string,\n channelIds: string[],\n opts?: { includePublic?: boolean },\n ): Promise<ChannelPreviewProjection>;\n /** Choose the channel's sale route. Authorization since 2026-08-06, so this is\n * a precondition of every buyer-facing action, not a label. `opts` carries the\n * acknowledgement that unblocks a switch with live buyer access. */\n setChannelAccessIntent(\n key: string,\n channelId: string,\n accessIntent: ChannelAccessIntent,\n opts?: { acknowledgeLiveAccess?: boolean; reason?: string },\n ): Promise<{\n ok: true;\n channel: ChannelRecord;\n intentSwitch?: { closedLinks: number; keptSessions: number };\n }>;\n /** 201 with the ONE-TIME reveal. Every omitted field takes the server default\n * (expiry = event start, 100 redemptions, 4 seats per buyer). */\n createAccessLink(\n key: string,\n channelId: string,\n input: {\n label?: string | null;\n expiresAt?: number;\n maxRedemptions?: number;\n maxQuantity?: number;\n includePublic?: boolean;\n },\n ): Promise<AccessLinkReveal>;\n /** Status only. This response has no url and no capability, by contract. */\n accessLinks(key: string, channelId: string): Promise<{ links: AccessLinkStatusRecord[] }>;\n /** `endActiveSessions` is required — the server 422s without it, deliberately. */\n rotateAccessLink(\n key: string,\n channelId: string,\n linkId: string,\n endActiveSessions: boolean,\n ): Promise<AccessLinkReveal>;\n revokeAccessLink(\n key: string,\n channelId: string,\n linkId: string,\n endActiveSessions?: boolean,\n ): Promise<{ ok: true; link: unknown; endedSessions: number }>;\n}\n\nexport interface ChannelsCapabilities {\n view: boolean;\n manage: boolean;\n}\n\n/** Everything Channels mode needs from the cockpit around it. */\nexport interface ChannelsModeHost {\n eventKey: string;\n api: ChannelsClient;\n /** The rail scroll container the mode paints into. */\n rail: HTMLElement;\n /** An absolutely-positioned layer over the map (overlay canvas, flags, bars). */\n mapLayer: HTMLElement;\n /** The widget root — dialogs mount here so they inherit the widget's tokens. */\n root: HTMLElement;\n seats(): ChannelsSeatView[];\n statusOf(label: string): ChannelSeatStatus | undefined;\n selectionLabels(): string[];\n selectByLabels(labels: string[]): void;\n clearSelection(): void;\n selectSection(sectionId: string): void;\n sections(): Array<{ id: string; label: string }>;\n /** Every selectable label inside one section, for the additive scope chooser. */\n labelsInSection(sectionId: string): string[];\n /** Logical rows across the whole chart, grouped by their section. */\n rows(): ChannelsRowView[];\n categories(): Array<{ key: string; label: string; color?: string }>;\n labelsInCategory(key: string): string[];\n sectionOfLabel(label: string): { id: string; label: string } | null;\n /** Chart-space → container pixels. Null when there is no live renderer. */\n worldToScreen(point: { x: number; y: number }): { x: number; y: number } | null;\n /** Approximate on-screen seat size in CSS pixels, for the overlay marks. */\n seatPixelSize(): number;\n /** Whether the live renderer is currently showing individual seats. */\n isSeatDetail(): boolean;\n /** Return a sectional venue to its section-only overview. */\n showSectionOverview(): void;\n /** Focus one section using the renderer's real camera transition. */\n focusSection(sectionId: string): void;\n isCompact(): boolean;\n /** Make the canvas non-interactive behind a full-detent sheet (§13). */\n setMapInert(inert: boolean): void;\n toast(message: string, kind: 'ok' | 'err'): void;\n onError(err: unknown): void;\n /** Fired whenever the staged mutation count changes, for host telemetry. */\n onStagedChange?(staged: number): void;\n}\n\n/**\n * Live-count refresh cadence. Organizer realtime (M5's per-scope socket) plugs\n * in at `applyRealtimeHint`, so this clock is a safety net, not the transport —\n * it was 10s, which cost every idle cockpit six list+allocation walks a minute\n * for counts that rarely move. Ticks are skipped entirely while the tab is\n * hidden and one runs immediately when it comes back.\n */\nconst POLL_MS = 30_000;\nconst MAX_FLAGS = 8;\nconst SEAT_LIST_PAGE = 300;\n\n/**\n * The most seats one Apply may carry. The assignment route rewrites every label\n * in a single transaction, so an unbounded selection is a request that times out\n * halfway and leaves the organizer guessing what moved. The ceiling is stated in\n * the UI *before* Apply — in the staged bar, the selection rail, the scope\n * chooser and the review sheet — so it is never discovered as a failure.\n */\nconst MAX_ASSIGNMENT_UNITS = 5_000;\n\n/**\n * Buyer-preview colours are deliberately independent of a chart's category\n * palette. A channel is an access scope, not a price category: retaining the\n * underlying category colour made a buyer's eligible seats indistinguishable\n * from the rest of a section, while a square grey overlay left a coloured rim\n * around unavailable seats. The two explicit states below make the scope\n * readable without disclosing which other channel owns an unavailable seat.\n */\nconst PREVIEW_ELIGIBLE_FILL = '#6e7bff';\nconst PREVIEW_ELIGIBLE_STROKE = '#b9c0ff';\nconst PREVIEW_UNAVAILABLE_FILL = '#303846';\nconst PREVIEW_UNAVAILABLE_STROKE = '#4b5669';\nconst ALLOCATION_STROKE = '#101723';\n\n/**\n * Motion tokens (motion-system §2) plus Channels choreography (§3). Declared on\n * the widget root as `--slm-mo-*` so an embed never inherits host motion CSS.\n * Every keyframe below has its `prefers-reduced-motion` override in this block.\n * `@sl-css` opts it into build-time minification (cdn/minifyCssLiterals.ts).\n */\nexport const CHANNELS_CSS = /* @sl-css */ `\n.slm{--slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;--slm-mo-ambient:2000ms;\n --slm-mo-out:cubic-bezier(.2,.8,.2,1);--slm-mo-in-out:cubic-bezier(.4,0,.2,1);--slm-mo-exit:cubic-bezier(.4,0,1,1);\n --slm-mo-spring:cubic-bezier(.34,1.3,.64,1)}\n\n/* map overlay: ONE layer, faded in as a whole (never per seat) */\n.slm-ch-layer{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity var(--slm-mo-base) var(--slm-mo-out)}\n.slm-ch-layer.on{opacity:1}\n.slm-ch-canvas{position:absolute;inset:0;width:100%;height:100%}\n.slm-ch-flag{position:absolute;display:flex;align-items:center;gap:5px;padding:3px 8px;border-radius:999px;\n background:rgba(14,16,23,.88);border:1px solid var(--slm-line);font-size:10px;font-weight:800;letter-spacing:.04em;\n transform:translate(-50%,-50%);white-space:nowrap}\n.slm-ch-flag .mk{width:14px;height:14px;border-radius:4px;display:grid;place-items:center;font-size:8.5px;font-weight:800;color:#0e1017}\n.slm-ch-section-target{position:absolute;pointer-events:auto;padding:0;border:0;border-radius:8px;background:transparent;cursor:zoom-in}\n.slm-ch-section-target:focus-visible{outline:2px solid var(--slm-accent);outline-offset:-3px;background:color-mix(in srgb,var(--slm-accent) 12%,transparent)}\n\n/* preview banner — raised with the organizer chrome dim, as one transition */\n.slm-ch-banner{position:absolute;left:50%;top:14px;z-index:6;display:flex;align-items:center;gap:9px;padding:8px 14px;\n border-radius:999px;background:rgba(14,16,23,.92);border:1px solid var(--slm-line);font-size:12px;font-weight:700;\n transform:translate(-50%,-8px);opacity:0;pointer-events:none;\n transition:opacity var(--slm-mo-base) var(--slm-mo-out),transform var(--slm-mo-base) var(--slm-mo-out)}\n.slm-ch-banner.on{opacity:1;transform:translate(-50%,0);pointer-events:auto}\n.slm-ch-banner .dot{width:8px;height:8px;border-radius:50%}\n.slm-ch-banner button{color:var(--slm-accent);font-weight:800;font-size:11.5px;min-height:32px}\n.slm.ch-preview .slm-ch-flag{opacity:0;transition:opacity var(--slm-mo-base) var(--slm-mo-out)}\n\n/* sticky staged bar */\n.slm-ch-staged{position:absolute;left:12px;right:12px;bottom:12px;z-index:6;display:flex;align-items:center;gap:12px;\n padding:10px 14px;min-height:44px;border-radius:12px;background:rgba(24,27,36,.96);border:1px solid var(--slm-line);\n box-shadow:0 12px 34px rgba(0,0,0,.45);font-size:12.5px;pointer-events:auto;\n transform:translateY(calc(100% + 18px));opacity:0;\n transition:transform var(--slm-mo-slow) var(--slm-mo-out),opacity var(--slm-mo-base) var(--slm-mo-out)}\n.slm-ch-staged.on{transform:none;opacity:1}\n.slm-ch-staged.done{background:rgba(31,122,77,.96);border-color:#1f7a4d}\n.slm-ch-staged.shake{animation:slm-ch-shake var(--slm-mo-slow) var(--slm-mo-in-out) 2}\n.slm-ch-staged b{font-variant-numeric:tabular-nums}\n.slm-ch-staged .grow{flex:1}\n.slm-ch-staged .go{padding:9px 16px;min-height:44px;display:inline-flex;align-items:center;border-radius:9px;\n background:#f4b740;color:#1a1200;font-weight:800;font-size:12.5px}\n.slm-ch-staged .go:disabled{opacity:.48;cursor:not-allowed}\n.slm-ch-staged .drop{color:var(--slm-muted);font-weight:700;font-size:11.5px;min-height:44px;padding-inline:8px}\n.slm-ch-tick{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;\n background:#fff;color:#1f7a4d;font-weight:900;font-size:11px;animation:slm-ch-tick var(--slm-mo-base) var(--slm-mo-spring)}\n@keyframes slm-ch-shake{0%,100%{transform:none}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}\n@keyframes slm-ch-tick{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}\n\n/* rail */\n.slm-ch-viewseg{display:flex;gap:3px;padding:3px;border:1px solid var(--slm-line);border-radius:9px;\n background:var(--slm-surface);margin-bottom:12px}\n.slm-ch-viewseg button{flex:1;padding:6px 8px;min-height:34px;border-radius:7px;font-size:11px;font-weight:800;color:var(--slm-muted)}\n.slm-ch-viewseg button.on{background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-ch-viewseg button:disabled{opacity:.5;cursor:not-allowed}\n.slm-ch-mapnav{margin:-2px 0 12px;padding:10px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface)}\n.slm-ch-mapnav-head{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--slm-muted)}\n.slm-ch-mapnav-head button{color:var(--slm-accent);font-size:11px;font-weight:800;letter-spacing:0;text-transform:none;min-height:30px}\n.slm-ch-mapnav .slm-ch-viewseg{margin:8px 0 5px}\n.slm-ch-mapnav p{margin:0;font-size:11px;line-height:1.45;color:var(--slm-muted)}\n.slm-ch-list{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}\n.slm-ch-row{padding:10px 11px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface);\n text-align:left;width:100%;display:block;transition:border-color var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-ch-row:hover{border-color:var(--slm-muted)}\n.slm-ch-row.on{border-color:var(--slm-accent);box-shadow:0 0 0 1px color-mix(in srgb,var(--slm-accent) 40%,transparent)}\n.slm-ch-row.public{background:linear-gradient(100deg,rgba(244,183,64,.09),var(--slm-surface) 60%)}\n.slm-ch-row.archived{opacity:.68}\n.slm-ch-head{display:flex;align-items:center;gap:8px}\n.slm-ch-mk{width:20px;height:20px;border-radius:6px;display:grid;place-items:center;font-size:10px;font-weight:800;\n color:#0e1017;flex:none}\n.slm-ch-mk.dim{opacity:.55}\n.slm-ch-name{flex:1;min-width:0;font-size:13px;font-weight:800;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.slm-ch-badge{flex:none;font-size:9px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;padding:2px 7px;border-radius:999px}\n.slm-ch-badge.active{background:rgba(34,160,107,.16);color:#5bd39b}\n.slm-ch-badge.paused,.slm-ch-badge.builtin{background:rgba(244,183,64,.15);color:#f7ca6b}\n.slm-ch-badge.archived{background:rgba(139,148,172,.18);color:#c2c9d8}\n.slm-ch-counts{display:flex;gap:10px;flex-wrap:wrap;margin-top:7px;font-size:11px;color:var(--slm-muted);\n font-variant-numeric:tabular-nums}\n.slm-ch-counts b{color:var(--slm-text);font-weight:800}\n.slm-ch-counts .free b{color:#5bd39b}\n.slm-ch-counts b.bump{animation:slm-ch-bump var(--slm-mo-base) var(--slm-mo-spring)}\n@keyframes slm-ch-bump{0%,100%{transform:none}35%{transform:translateY(-2px) scale(1.08)}}\n.slm-ch-access{margin-top:6px;font-size:10.5px;color:var(--slm-muted)}\n/* A row that opens its channel must READ as pressable, and be one for a keyboard\n too. It is a role=\"button\" div rather than a <button> because the ⋯ control\n lives inside it, and a button inside a button is not valid HTML. */\n.slm-ch-row.open{cursor:pointer}\n.slm-ch-row.open:hover{border-color:var(--slm-accent);background:color-mix(in srgb,var(--slm-accent) 6%,var(--slm-surface))}\n.slm-ch-row.open:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}\n.slm-ch-row.open:active{border-color:var(--slm-accent)}\n.slm-ch-more{flex:none;color:var(--slm-muted);font-weight:800;padding:0 4px;min-height:28px;border-radius:6px}\n.slm-ch-more:hover{color:var(--slm-text)}\n.slm-ch-more:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px;color:var(--slm-text)}\n.slm-ch-menu{display:flex;flex-direction:column;gap:8px}\n.slm-ch-menu .slm-btn{width:100%}\n/* loading is a state, never a flash of empty: same slot, visibly working */\n.slm-ch-busy{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--slm-muted);padding:12px 0}\n.slm-ch-busy::before{content:\"\";width:9px;height:9px;border-radius:50%;background:var(--slm-accent);flex:none;\n animation:slm-ch-pulse var(--slm-mo-ambient) var(--slm-mo-in-out) infinite}\n@keyframes slm-ch-pulse{0%,100%{opacity:.25;transform:scale(.7)}50%{opacity:1;transform:scale(1)}}\n.slm-ch-selsrc{display:flex;flex-direction:column;gap:5px;margin:8px 0 12px}\n.slm-ch-selsrc-row{display:flex;align-items:center;gap:8px;font-size:12px;font-variant-numeric:tabular-nums}\n.slm-ch-selsrc-row .mk{width:15px;height:15px;border-radius:4px;display:grid;place-items:center;font-size:8px;\n font-weight:800;color:#0e1017}\n.slm-ch-selsrc-row b{min-width:30px;text-align:right;font-weight:800}\n.slm-ch-selsrc-row span{color:var(--slm-muted)}\n.slm-ch-selnum.bump{animation:slm-ch-bump var(--slm-mo-base) var(--slm-mo-spring)}\n.slm-ch-row2{display:flex;gap:8px;margin-top:8px}\n.slm-ch-row2 .slm-btn{flex:1;min-width:0}\n/* distribute routes — four choices, each with the one sentence that explains it.\n The current one is NAMED in its own card, never signalled by colour alone. */\n.slm-ch-dist{display:flex;flex-direction:column;gap:6px;padding:12px;margin-bottom:8px;border:1px solid var(--slm-line);\n border-radius:10px;background:var(--slm-surface)}\n.slm-ch-dist.on{border-color:var(--slm-accent,#8b7cf6)}\n.slm-ch-dist b{font-size:13px;font-weight:800;display:flex;align-items:center;gap:8px;justify-content:space-between}\n.slm-ch-dist b .cur{font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;\n color:var(--slm-accent,#8b7cf6);white-space:nowrap}\n.slm-ch-dist .why{color:var(--slm-muted);font-size:11.5px;line-height:1.45}\n.slm-ch-dist .slm-btn{width:100%;margin-top:2px}\n.slm-ch-alert{display:flex;align-items:flex-start;gap:9px;padding:11px 13px;border-radius:10px;font-size:12.5px;\n line-height:1.5;margin-bottom:12px}\n.slm-ch-alert.warn{background:rgba(244,183,64,.1);border:1px solid rgba(244,183,64,.4);color:#f4d58a}\n.slm-ch-alert.info{background:rgba(110,123,255,.12);border:1px solid rgba(110,123,255,.44);color:#c5cbff}\n.slm-ch-alert.err{background:rgba(229,72,77,.1);border:1px solid rgba(229,72,77,.45);color:#f1a4a6}\n.slm-ch-alert b{color:#fff}\n.slm-ch-alert button{display:block;margin-top:6px;color:#fff;font-weight:800;min-height:36px}\n.slm-ch-legend{display:flex;flex-direction:column;gap:6px;margin-top:10px}\n.slm-ch-legend .r{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--slm-muted)}\n.slm-ch-legend .sw{width:13px;height:13px;border-radius:3.5px;flex:none}\n.slm-ch-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n\n/* dialogs */\n.slm-ch-scrim{position:absolute;inset:0;z-index:12;background:rgba(4,6,12,.62);display:grid;place-items:center;\n padding:18px;animation:slm-ch-fade var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-ch-dialog{width:min(460px,100%);max-height:100%;overflow:auto;overscroll-behavior:contain;background:#12151f;border:1px solid var(--slm-line);\n border-radius:14px;padding:20px;box-shadow:0 24px 70px rgba(0,0,0,.6);\n animation:slm-ch-rise var(--slm-mo-base) var(--slm-mo-out)}\n.slm-ch-dialog h3{margin:0 0 4px;font-size:16px;font-weight:800;letter-spacing:-.01em}\n.slm-ch-dialog .sub{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}\n.slm-ch-dialog .foot{display:flex;gap:8px;margin-top:16px}\n.slm-ch-dialog .foot .slm-btn{flex:1;min-width:0}\n.slm-ch-dialog .foot .quiet{flex:none;padding:10px 14px;min-height:44px;color:var(--slm-muted);font-weight:700;font-size:13px}\n@keyframes slm-ch-fade{from{opacity:0}to{opacity:1}}\n@keyframes slm-ch-rise{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}\n.slm-ch-bucket{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:10px;padding:9px 4px;\n border-top:1px solid var(--slm-line);font-size:12.5px;animation:slm-ch-bucket var(--slm-mo-base) var(--slm-mo-out) both}\n.slm-ch-bucket:first-of-type{border-top:0}\n.slm-ch-bucket .ico{width:20px;height:20px;border-radius:6px;display:grid;place-items:center;font-size:10px;font-weight:800}\n.slm-ch-bucket .ico.add{background:rgba(34,160,107,.18);color:#5bd39b}\n.slm-ch-bucket .ico.move{background:rgba(167,139,250,.18);color:#c4b5fd}\n.slm-ch-bucket .ico.same{background:rgba(139,148,172,.14);color:#aab2c4}\n.slm-ch-bucket .ico.skip{background:rgba(244,183,64,.16);color:#f7ca6b}\n.slm-ch-bucket b{font-variant-numeric:tabular-nums;font-weight:800}\n.slm-ch-bucket .why{color:var(--slm-muted);font-size:11px}\n.slm-ch-bucket .peek{color:var(--slm-muted);font-size:11px;font-variant-numeric:tabular-nums}\n@keyframes slm-ch-bucket{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}\n.slm-ch-secret{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px dashed rgba(244,183,64,.55);\n border-radius:10px;background:rgba(244,183,64,.06);font-family:ui-monospace,Menlo,monospace;font-size:11px;\n overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n.slm-ch-err{color:#f1a4a6;font-size:11.5px;margin-top:6px}\n\n/* buyer links — STATUS only; there is no Copy control on this card */\n.slm-ch-link{padding:10px 11px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface);\n margin-bottom:8px}\n.slm-ch-link .lk-head{display:flex;align-items:center;gap:8px}\n.slm-ch-link .lk-name{flex:1;min-width:0;font-size:12.5px;font-weight:800;overflow:hidden;text-overflow:ellipsis;\n white-space:nowrap}\n.slm-ch-lkrow{display:flex;gap:8px;margin-top:5px;font-size:11px;color:var(--slm-muted)}\n.slm-ch-lkrow .k{flex:none;min-width:104px}\n.slm-ch-lkrow .v{color:var(--slm-text);font-variant-numeric:tabular-nums}\n.slm-ch-meter{height:5px;border-radius:3px;background:rgba(255,255,255,.09);overflow:hidden;margin-top:8px}\n.slm-ch-meter i{display:block;height:100%;background:var(--slm-accent);\n transition:width var(--slm-mo-base) var(--slm-mo-out)}\n.slm-ch-radio{display:flex;gap:9px;align-items:flex-start;padding:11px 12px;border:1px solid var(--slm-line);\n border-radius:10px;margin-top:8px;font-size:12.5px;cursor:pointer;\n transition:border-color var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-ch-radio:hover{border-color:var(--slm-muted)}\n.slm-ch-radio input{flex:none;margin-top:2px}\n.slm-ch-radio b{display:block;font-weight:800;margin-bottom:2px}\n.slm-ch-radio .why{display:block;color:var(--slm-muted);font-size:11.5px;line-height:1.45}\n.slm-ch-seatlist{max-height:44vh;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);\n border-radius:10px;background:var(--slm-surface);margin-top:10px}\n.slm-ch-seatgroup{padding:8px 10px;border-bottom:1px solid var(--slm-line);display:flex;align-items:center;\n justify-content:space-between;gap:8px;font-size:11px;font-weight:800;color:var(--slm-muted);position:sticky;top:0;\n background:var(--slm-surface)}\n.slm-ch-seatgroup button{color:var(--slm-accent);font-weight:800;font-size:11px;min-height:32px}\n.slm-ch-seatitem{display:flex;width:100%;align-items:center;gap:9px;padding:8px 10px;border-bottom:1px solid var(--slm-line);\n text-align:left;font-size:12px}\n.slm-ch-seatitem .box{width:16px;height:16px;border-radius:4px;border:1px solid var(--slm-muted);display:grid;\n place-items:center;font-size:10px;font-weight:900;color:transparent;flex:none}\n.slm-ch-seatitem[aria-checked=\"true\"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-ch-seatitem .meta{margin-left:auto;color:var(--slm-muted);font-size:10.5px}\n\n/* scope chooser: whole sections or many rows in one additive pass */\n.slm-ch-scopebar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:10px;margin-top:12px}\n.slm-ch-scopebar label{display:grid;gap:5px;color:var(--slm-muted);font-size:10.5px;font-weight:800}\n.slm-ch-scopebar input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--slm-line);border-radius:8px;\n background:var(--slm-surface);color:var(--slm-text);font:inherit}\n.slm-ch-scopesummary{padding-bottom:10px;color:var(--slm-muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}\n.slm-ch-scopegroup{position:sticky;top:0;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;\n gap:6px;padding:6px 8px;border-bottom:1px solid var(--slm-line);background:var(--slm-surface)}\n.slm-ch-groupcheck{display:flex;min-width:0;align-items:center;gap:8px;padding:5px 2px;text-align:left;font-size:11px;font-weight:800}\n.slm-ch-groupcheck .box{width:16px;height:16px;flex:none;display:grid;place-items:center;border:1px solid var(--slm-muted);border-radius:4px;\n color:transparent;font-size:10px}\n.slm-ch-groupcheck[aria-checked=\"true\"] .box,.slm-ch-groupcheck[aria-checked=\"mixed\"] .box{border-color:var(--slm-accent);\n background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-ch-groupcheck .meta{min-width:0;margin-left:auto;color:var(--slm-muted);font-size:10.5px;font-weight:600;white-space:nowrap}\n.slm-ch-grouptoggle{min-height:32px;padding:5px 8px;color:var(--slm-accent);font-size:11px;font-weight:800}\n.slm-ch-scopehint{padding:8px 10px;color:var(--slm-muted);font-size:10.5px;border-bottom:1px solid var(--slm-line)}\n.slm-ch-scope-empty{padding:18px 12px;color:var(--slm-muted);font-size:11.5px;text-align:center}\n@media(max-width:560px){.slm-ch-scopebar{grid-template-columns:1fr}.slm-ch-scopesummary{padding-bottom:0}}\n\n/* compact: bottom sheet with three detents (§13) */\n.slm.compact.ch-sheet .slm-rail{position:absolute;left:0;right:0;bottom:0;z-index:8;border-top:1px solid var(--slm-line);\n border-radius:18px 18px 0 0;background:#12151f;\n transition:height var(--slm-mo-slow) var(--slm-mo-in-out)}\n.slm.compact.ch-sheet.detent-collapsed .slm-rail{height:132px}\n.slm.compact.ch-sheet.detent-medium .slm-rail{height:46%}\n.slm.compact.ch-sheet.detent-full .slm-rail{height:92%}\n.slm.compact.ch-sheet .slm-railscroll{padding:8px 14px calc(12px + env(safe-area-inset-bottom,0px))}\n.slm-ch-grab{display:none}\n.slm.compact.ch-sheet .slm-ch-grab{display:flex;align-items:center;gap:10px;width:100%;padding:6px 0 10px}\n.slm-ch-grabbar{width:42px;height:4px;border-radius:2px;background:rgba(255,255,255,.22);margin:0 auto}\n.slm.compact .slm-ch-staged{bottom:auto;top:8px}\n.slm.compact .slm-btn,.slm.compact .slm-ch-row,.slm.compact .slm-ch-viewseg button{min-height:44px}\n.slm-tools{display:none}\n.slm.compact .slm-tools{display:block;width:100%;padding:9px 13px;min-height:44px;border:1px solid var(--slm-line);\n border-radius:10px;background:var(--slm-surface);color:var(--slm-text);font-size:13px;font-weight:800}\n.slm.compact .slm-modes{display:none}\n\n@media (prefers-reduced-motion:reduce){\n .slm-ch-layer,.slm-ch-banner,.slm-ch-staged,.slm-ch-row,.slm.compact.ch-sheet .slm-rail,\n .slm-ch-meter i,.slm-ch-radio{transition:none!important}\n .slm-ch-staged.shake,.slm-ch-tick,.slm-ch-bucket,.slm-ch-scrim,.slm-ch-dialog,\n .slm-ch-counts b.bump,.slm-ch-selnum.bump{animation:none!important}\n .slm-ch-busy::before{animation:none!important;opacity:1}\n .slm-ch-staged.shake{outline:2px solid #e5484d;outline-offset:2px}\n .slm-ch-staged.done{outline:2px solid #5bd39b;outline-offset:2px}\n}\n`;\n\n/**\n * Render bucket rows to markup. Deliberately generic over `BucketRow`, because\n * three different refusals share this exact presentation: the local staged\n * preview, the authoritative Apply response, and the chart-update\n * `channel_assignment_would_drop` review (via `dropReviewRows`). One component,\n * one visual language for \"here is every affected unit, in exactly one line\".\n */\nexport function bucketRowsHtml(rows: BucketRow[]): string {\n return rows.map((row, index) => `\n <div class=\"slm-ch-bucket\" style=\"animation-delay:${Math.min(index, 4) * 30}ms\">\n <span class=\"ico ${row.kind}\" aria-hidden=\"true\">${esc(row.icon)}</span>\n <span><b>${row.count.toLocaleString()}</b> ${esc(row.text.replace(/^[\\d,.\\s]+/, ''))}\n ${row.why ? `<span class=\"why\">— ${esc(row.why)}</span>` : ''}</span>\n ${row.peek ? `<span class=\"peek\">${esc(row.peek)}</span>` : '<span></span>'}\n </div>`).join('');\n}\n\n/**\n * Website integration is a BACKEND integration, so there is no screen to build\n * and this block is deliberately informational.\n *\n * It replaces a disabled \"Configure server integration · Coming soon\" button\n * that promised a wizard which does not exist and is not planned. A control that\n * can never do anything is worse than a sentence explaining why it isn't there:\n * the honest answer is \"nothing to configure here, and here is the guide\".\n *\n * It is shown only once the organizer has chosen this route (`intent: 'server'`),\n * because that is also the flag the dashboard's Embed page reads to offer the\n * snippet. Before that choice it would be an unasked-for wall of backend talk.\n */\nconst SERVER_INTEGRATION_HTML = `\n <p class=\"slm-eyebrow\" style=\"margin-top:18px\">On your website</p>\n <p class=\"slm-hint\">There is nothing more to set up on this screen. Your own server mints a short-lived buyer\n access session for this channel with the SeatLayer server SDK and hands it to the widget. A channel name\n on its own never grants access.</p>\n <p class=\"slm-note\"><a class=\"slm-linkbtn\" href=\"https://docs.seatlayer.io/server-api/channels\"\n target=\"_blank\" rel=\"noreferrer noopener\">Read the website integration guide →</a></p>`;\n\nfunction esc(value: unknown): string {\n return String(value ?? '')\n .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;').replace(/'/g, '&#039;');\n}\n\n/** `<input type=\"datetime-local\">` wants local wall-clock, not an ISO instant. */\nfunction datetimeLocalValue(ms: number): string {\n const local = new Date(ms - new Date(ms).getTimezoneOffset() * 60_000);\n return local.toISOString().slice(0, 16);\n}\n\n/** A whole number from a numeric field, or null when it is not one. This is the\n * ONLY client-side validation on link policy — the ranges belong to the server. */\nfunction intField(root: HTMLElement, selector: string): number | null {\n const raw = root.querySelector<HTMLInputElement>(selector)?.value.trim() ?? '';\n const value = Number(raw);\n return raw !== '' && Number.isInteger(value) ? value : null;\n}\n\n/** Clipboard-less fallback: put the revealed URL under the caret so it can still\n * be copied by hand. Selection dies with the node, like the string itself. */\nfunction selectSecret(dialog: HTMLElement): void {\n const node = dialog.querySelector<HTMLElement>('[data-ch-lk-url]');\n if (!node) return;\n try {\n const range = document.createRange();\n range.selectNodeContents(node);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n } catch { /* selection is a nicety; the URL is on screen regardless */ }\n}\n\ntype Detent = 'collapsed' | 'medium' | 'full';\n\ntype DialogKind =\n | 'create' | 'review' | 'archive' | 'rename' | 'seatlist' | 'scope' | 'menu'\n | 'linkCreate' | 'linkRotate' | 'linkRevoke' | 'intentSwitch';\n\n/** The link the organizer asked for, held while a blocked route switch is\n * reviewed, so acknowledging resumes the SAME gesture instead of making them\n * fill the form in again. It carries no secret — the reveal is still one-time. */\nexport interface PendingLinkInput {\n label: string | null;\n includePublic: boolean;\n expiresAt?: number;\n maxRedemptions: number;\n maxQuantity: number;\n}\n\n/**\n * There is deliberately NO `reveal` dialog kind. A one-time reveal is not a\n * re-renderable state: `renderDialog()` rebuilds a sheet from this object, so\n * anything reachable from here is by definition recoverable. The reveal is\n * mounted directly, holds its URL in a closure, and dies with its DOM node.\n */\ninterface DialogState {\n kind: DialogKind;\n channelId?: string;\n linkId?: string;\n /** Authoritative result rendered after Apply (review dialog only). */\n applied?: AssignmentResult | null;\n archiveBlocked?: ArchiveBlockedDetails | null;\n /** The refused route switch, and where it was headed (intentSwitch only). */\n switchBlocked?: IntentSwitchBlockedDetails | null;\n intentTo?: ChannelAccessIntent;\n /** Set when the blocked switch was the declare half of a declare-then-create,\n * so acknowledging finishes the link the organizer actually asked for. */\n pendingLink?: PendingLinkInput | null;\n /** Which unit the scope chooser is picking (scope dialog only). */\n scope?: 'sections' | 'rows';\n busy?: boolean;\n error?: string | null;\n}\n\nexport class ChannelsMode {\n private readonly host: ChannelsModeHost;\n private caps: ChannelsCapabilities;\n\n private active = false;\n private list: ChannelListResult | null = null;\n private allocation = new Map<string, string>();\n private assignmentVersion = 0;\n private loadError: unknown = null;\n private loading = true;\n\n private view: 'inspect' | 'preview' = 'inspect';\n /** Pan is intentionally the initial desktop interaction. Assignment's\n * marquee is powerful, but must never make an organizer lose map navigation. */\n private mapIntent: 'pan' | 'assign' = 'pan';\n private focusedSectionId: string | null = null;\n private showArchived = false;\n private detailChannelId: string | null = null;\n /**\n * Whether the organizer has asked to assign seats.\n *\n * The list rail leads with the CHANNELS. The assignment tooling — destination\n * picker plus five select-by routes — used to paint unconditionally above that\n * list, so a first-time organizer met a workbench for a job they had not asked\n * to do, with the thing they came for pushed below the fold. It is now\n * disclosed on intent: the \"Assign seats to a channel\" action under the list,\n * the map's own \"Assign seats\" segment, or simply having a selection. The\n * selection rail always shows the tools, because there the intent is proven.\n */\n private assignOpen = false;\n private targetChannelId = '';\n private conflict = false;\n private dialog: DialogState | null = null;\n private detent: Detent = 'medium';\n private seatListLimit = SEAT_LIST_PAGE;\n\n /**\n * Hosted-link STATUS for the channel whose detail panel is open. This is the\n * listing projection — it carries no url and no capability, because no route\n * returns one. `unsupported` is the honest answer for a worker that predates\n * M8, exactly like the buyer-preview probe.\n */\n private links: AccessLinkStatusRecord[] = [];\n private linksChannelId: string | null = null;\n private linksState: 'idle' | 'loading' | 'ready' | 'unsupported' | 'error' = 'idle';\n\n /**\n * Monotonic read generations — one for the channel list + allocation, one for\n * the open channel's links. Reads are concurrent (a 10s poll versus a\n * mutation's own reload), and the network does not promise to answer them in\n * order. Only the NEWEST read of each kind may write to state; an older\n * answer that arrives late is dropped, never painted.\n */\n private listSeq = 0;\n private linksSeq = 0;\n\n private previewAudience: string[] = [];\n private previewIncludePublic = false;\n private previewProjection: ChannelPreviewProjection | null = null;\n /**\n * The buyer-preview read, as one honest state rather than a boolean.\n *\n * `previewSupported: boolean | null` could say \"this worker has no projection\n * route\", but it could not say \"the read is in flight\" or \"the read failed\" —\n * both of those painted an audience picker with no result underneath, which\n * reads as \"this audience can buy nothing\". Loading and error are now states\n * of their own, and the error one offers a retry.\n */\n private previewState: 'idle' | 'loading' | 'ready' | 'unsupported' | 'error' = 'idle';\n\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private layer: HTMLDivElement | null = null;\n private canvas: HTMLCanvasElement | null = null;\n /** undefined = not resolved yet, null = this environment has no 2d canvas. */\n private ctx: CanvasRenderingContext2D | null | undefined = undefined;\n private bannerEl: HTMLDivElement | null = null;\n private stagedEl: HTMLDivElement | null = null;\n private liveEl: HTMLDivElement | null = null;\n private scrimEl: HTMLDivElement | null = null;\n private lastFocus: HTMLElement | null = null;\n private stagedDoneTimer: ReturnType<typeof setTimeout> | null = null;\n private lastSelectionCount = 0;\n private lastCounts = new Map<string, number>();\n /** Rows are structural chart data — they do not move while the organizer is\n * allocating. Deriving them walks every seat, so the view is cached for the\n * lifetime of this mode entry and ordinary selection repaints stay O(1). */\n private assignmentRowsCache: ChannelsRowView[] | null = null;\n /** The markup currently in the rail. An identical repaint is skipped, which is\n * what keeps the organizer's scroll position (and open <select>) alive. */\n private railHtml: string | null = null;\n /**\n * The `assignmentVersion` the allocation map was built from. Walking every\n * allocation page is the expensive half of a refresh and the server already\n * tells us, in the channels response, whether ANY seat moved. Unchanged\n * version, unchanged allocation — so the walk is skipped entirely.\n */\n private allocationVersion: number | null = null;\n private onVisibility: (() => void) | null = null;\n\n constructor(host: ChannelsModeHost, capabilities: ChannelsCapabilities) {\n this.host = host;\n this.caps = capabilities;\n }\n\n // ---- lifecycle ------------------------------------------------------------\n\n /** Called when the cockpit switches into Channels mode. */\n enter(): void {\n if (this.active) return;\n this.active = true;\n this.mapIntent = 'pan';\n this.assignOpen = false; // every entry starts on the channels, not the tools\n this.focusedSectionId = null;\n this.assignmentRowsCache = null; // the chart may have changed since last entry\n this.railHtml = null; // the rail belonged to another mode a moment ago\n this.ensureLayer();\n this.host.root.classList.add('ch-mode');\n this.applySheetClasses();\n // A sectioned venue begins at semantic overview. The renderer owns the\n // camera and turns this into a real section-only rung, not a fake card UI.\n if (this.host.sections().length > 1) this.host.showSectionOverview();\n this.paintRail();\n this.onInteractionChange?.();\n void this.refresh();\n // A hidden tab has no organizer looking at it. Polling it burns the event's\n // rate budget to repaint pixels nobody can see — and browsers throttle the\n // timer anyway, so the ticks that do land arrive in a clump. Skip them, and\n // catch up with exactly one read when the tab comes back.\n this.pollTimer = setInterval(() => {\n if (typeof document !== 'undefined' && document.hidden) return;\n void this.refresh({ quiet: true });\n }, POLL_MS);\n if (typeof document !== 'undefined' && typeof document.addEventListener === 'function') {\n this.onVisibility = () => {\n if (this.active && !document.hidden) void this.refresh({ quiet: true });\n };\n document.addEventListener('visibilitychange', this.onVisibility);\n }\n }\n\n /** Called when the cockpit leaves Channels mode. Everything this mode painted\n * over the map goes with it — no other tool ever inherits a channel overlay. */\n leave(): void {\n if (!this.active) return;\n this.active = false;\n if (this.pollTimer) clearInterval(this.pollTimer);\n this.pollTimer = null;\n if (this.onVisibility && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.onVisibility);\n }\n this.onVisibility = null;\n this.railHtml = null;\n this.closeDialog({ restoreFocus: false });\n // Link status is per-channel and short-lived; nothing about it survives the\n // mode, and there was never a secret in it to survive.\n this.links = [];\n this.linksChannelId = null;\n this.linksState = 'idle';\n this.layer?.classList.remove('on');\n this.host.root.classList.remove('ch-mode', 'ch-preview', 'ch-sheet',\n 'detent-collapsed', 'detent-medium', 'detent-full');\n this.setBanner(false);\n this.setStaged(null);\n }\n\n destroy(): void {\n this.leave();\n if (this.stagedDoneTimer) clearTimeout(this.stagedDoneTimer);\n this.layer?.remove();\n this.layer = null;\n }\n\n /** Capabilities can change when a token rotates. Re-render, fail-closed. */\n setCapabilities(capabilities: ChannelsCapabilities): void {\n this.caps = capabilities;\n if (this.active) this.paintRail();\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n /**\n * Whether the map should accept bulk selection right now. Preview is a\n * read-only simulation of somebody else's view, and a view-only token has no\n * assignment to stage — in both cases the canvas must not offer selection at\n * all rather than collect a selection nothing can act on.\n */\n canSelect(): boolean {\n return this.caps.manage && this.view === 'inspect';\n }\n\n /** Bulk seat assignment is explicit. In Pan map, clicks can still inspect a\n * single seat, while a primary-button drag always moves the camera. */\n usesMarqueeSelection(): boolean {\n return this.canSelect() && this.mapIntent === 'assign';\n }\n\n /** The renderer calls this when the organizer opens a section from overview. */\n handleSectionFocus(sectionId: string): void {\n if (!this.active) return;\n this.focusedSectionId = sectionId;\n this.paintRail();\n }\n\n /**\n * Organizer realtime integration point. M5 ships a per-scope socket for\n * buyers; the organizer channel-count stream is a later milestone. When it\n * arrives, call this from the cockpit's WS handler instead of waiting for the\n * poll — everything downstream already reacts to a fresh list.\n */\n applyRealtimeHint(): void {\n if (this.active) void this.refresh({ quiet: true });\n }\n\n /** The cockpit's selection changed (marquee / click / section / category). */\n handleSelectionChange(): void {\n if (!this.active) return;\n this.paintSelection();\n this.paintStagedBar();\n }\n\n /** Camera moved or the container resized — the overlay is screen-space. */\n handleViewChange(): void {\n if (this.active) this.paintOverlay();\n }\n\n handleLayoutChange(): void {\n if (!this.active) return;\n this.applySheetClasses();\n this.paintOverlay();\n }\n\n // ---- data -----------------------------------------------------------------\n\n private async refresh(opts: { quiet?: boolean } = {}): Promise<void> {\n if (!this.caps.view) return;\n // A ten-second poll runs alongside every mutation, so two refreshes are\n // routinely in flight at once. Without a generation the slower FIRST one\n // lands last and repaints the panel with what the channel looked like\n // BEFORE the mutation — the create/rotate/revoke result silently reverts.\n const seq = ++this.listSeq;\n const superseded = (): boolean => seq !== this.listSeq;\n try {\n const list = await this.host.api.channels(this.host.eventKey, { includeArchived: this.showArchived });\n if (superseded()) return;\n this.list = list;\n this.assignmentVersion = list.assignmentVersion;\n this.loadError = null;\n if (!this.targetChannelId) {\n this.targetChannelId = list.channels.find((c) => c.state === 'active')?.id ?? PUBLIC_CHANNEL_ID;\n }\n // The allocation walk is the expensive half of this refresh (one request\n // per 1,000 seats). `assignmentVersion` is bumped by the server on every\n // assignment, so an unchanged version means an unchanged map — re-reading\n // it would spend an arena's worth of round trips to rebuild an identical\n // Map every poll tick.\n if (this.allocationVersion !== list.assignmentVersion) {\n await this.loadAllocation(seq);\n if (superseded()) return;\n this.allocationVersion = list.assignmentVersion;\n }\n // Redemptions and live-session counts move on their own, so the open\n // channel's link status rides the same clock as its seat counts.\n if (this.detailChannelId) await this.loadLinks(this.detailChannelId);\n if (superseded()) return;\n this.loading = false;\n if (this.active) {\n this.paintRail();\n this.paintOverlay();\n }\n } catch (err) {\n if (superseded()) return;\n this.loading = false;\n // A 403 on a mutation route means the token lost manage authority; a 403\n // here means it lost view. Either way, fail closed rather than guess.\n if (err instanceof ManageApiError && err.status === 403) {\n this.caps = { view: false, manage: false };\n }\n this.loadError = err;\n if (!opts.quiet) this.host.onError(err);\n if (this.active) this.paintRail();\n }\n }\n\n /** Walk every allocation page. Bounded by the event's seat count, and the\n * server caps each page, so an arena is a handful of round trips. */\n private async loadAllocation(seq?: number): Promise<void> {\n const next = new Map<string, string>();\n let afterLabel: string | undefined;\n for (let page = 0; page < 200; page += 1) {\n // A superseded walk stops paging rather than finishing a read nobody will use.\n if (seq !== undefined && seq !== this.listSeq) return;\n const res: ChannelAllocationPage = await this.host.api.channelAllocation(this.host.eventKey, {\n afterLabel, limit: 1000,\n });\n for (const row of res.allocations) {\n // The server names public sale explicitly on every row, so the map holds\n // PRIVATE ids only — absence is what \"on public sale\" means downstream.\n if (!isPublicChannelId(row.channelId)) next.set(row.label, row.channelId);\n }\n this.assignmentVersion = res.assignmentVersion;\n if (!res.nextAfterLabel) break;\n afterLabel = res.nextAfterLabel;\n }\n if (seq !== undefined && seq !== this.listSeq) return;\n this.allocation = next;\n }\n\n // ---- lookups --------------------------------------------------------------\n\n private channelById(id: string): { id: string; name: string; marker: string | null; color: string | null } | null {\n if (isPublicChannelId(id)) {\n return {\n id: PUBLIC_CHANNEL_ID,\n name: this.list?.publicSale?.name ?? PUBLIC_CHANNEL_NAME,\n marker: 'P',\n color: null,\n };\n }\n const found = this.list?.channels.find((channel) => channel.id === id);\n return found ? { id, name: found.name, marker: found.marker, color: found.color } : null;\n }\n\n private nameOf(id: string): string | null {\n return this.channelById(id)?.name ?? null;\n }\n\n private markerFor(id: string): { letter: string; color: string } {\n const index = Math.max(0, this.list?.channels.findIndex((channel) => channel.id === id) ?? 0);\n const channel = this.channelById(id);\n return markerOf(channel ?? { id, name: '?', marker: null, color: null }, index);\n }\n\n /** Channels an organizer may assign INTO: public sale plus every live channel. */\n private assignableChannels(): Array<{ id: string; name: string }> {\n return [\n { id: PUBLIC_CHANNEL_ID, name: this.list?.publicSale.name ?? PUBLIC_CHANNEL_NAME },\n ...(this.list?.channels ?? [])\n .filter((channel) => channel.state !== 'archived')\n .map((channel) => ({ id: channel.id, name: channel.name })),\n ];\n }\n\n private currentPlan(): { labels: string[]; buckets: AssignmentBuckets; target: string } {\n const labels = this.host.selectionLabels();\n const buckets = planAssignment({\n labels,\n targetChannelId: this.targetChannelId,\n allocation: this.allocation,\n statusOf: (label) => this.host.statusOf(label),\n nameOf: (id) => this.nameOf(id),\n });\n return { labels, buckets, target: this.targetChannelId };\n }\n\n // ---- map overlay ----------------------------------------------------------\n\n private ensureLayer(): void {\n if (this.layer) return;\n const layer = document.createElement('div');\n layer.className = 'slm-ch-layer';\n layer.innerHTML = `\n <canvas class=\"slm-ch-canvas\" data-ch=\"canvas\" aria-hidden=\"true\"></canvas>\n <div class=\"slm-ch-banner\" data-ch=\"banner\" role=\"status\"></div>\n <div class=\"slm-ch-staged\" data-ch=\"staged\" role=\"group\" aria-label=\"Staged channel changes\"></div>\n <div class=\"slm-ch-live\" data-ch=\"live\" role=\"status\" aria-live=\"polite\"></div>`;\n this.host.mapLayer.appendChild(layer);\n this.layer = layer;\n this.canvas = layer.querySelector('[data-ch=\"canvas\"]');\n this.bannerEl = layer.querySelector('[data-ch=\"banner\"]');\n this.stagedEl = layer.querySelector('[data-ch=\"staged\"]');\n this.liveEl = layer.querySelector('[data-ch=\"live\"]');\n requestAnimationFrame(() => layer.classList.add('on'));\n }\n\n private announce(message: string): void {\n if (this.liveEl) this.liveEl.textContent = message;\n }\n\n /**\n * Repaint the allocation (or preview) overlay in ONE canvas pass.\n *\n * Channel identity on the map is a fill in the administrative color PLUS the\n * letter flags below — never color alone. In buyer preview the map instead\n * uses two explicit, channel-neutral access states. Physical status keeps its\n * own cue: only FREE units are repainted, so sold/held/blocked seats still\n * read exactly as they do in every other tool.\n */\n private paintOverlay(): void {\n const canvas = this.canvas;\n const layer = this.layer;\n if (!canvas || !layer) return;\n const rect = this.host.mapLayer.getBoundingClientRect();\n const width = Math.max(1, Math.round(rect.width));\n const height = Math.max(1, Math.round(rect.height));\n const dpr = typeof devicePixelRatio === 'number' ? Math.min(3, Math.max(1, devicePixelRatio)) : 1;\n if (canvas.width !== width * dpr || canvas.height !== height * dpr) {\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n }\n // jsdom (and any canvas-less environment) has no 2d context; the overlay is\n // purely decorative there and the rail stays fully functional. Resolve it\n // once so a headless run is not spammed on every repaint.\n if (this.ctx === undefined) {\n try { this.ctx = canvas.getContext('2d'); } catch { this.ctx = null; }\n }\n const ctx = this.ctx;\n if (!ctx) return;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, width, height);\n\n const seatDetail = this.host.isSeatDetail();\n const size = Math.max(3, this.host.seatPixelSize());\n const half = size / 2;\n // A paused/archived audience answers `available:false`: nothing is buyable\n // through it, so every seat takes the one neutral unavailable treatment\n // rather than rendering the allocation as if it were on sale.\n const projection = this.view === 'preview' ? this.previewProjection : null;\n const eligible = projection\n ? new Set(projection.available === false ? [] : projection.eligible ?? [])\n : null;\n const clusters = new Map<string, { x: number; y: number; n: number }>();\n const sectionTargets = !seatDetail && this.host.sections().length > 1\n ? new Map<string, { label: string; minX: number; minY: number; maxX: number; maxY: number }>()\n : null;\n // At a wide zoom the renderer centres section names over the seat field.\n // Re-draw those names above the access marks so visual availability never\n // competes with the section identity the organizer needs to navigate.\n const previewSections = this.view === 'preview' && seatDetail && size <= 15\n ? new Map<string, { label: string; minX: number; minY: number; maxX: number; maxY: number }>()\n : null;\n\n for (const seat of this.host.seats()) {\n const status = this.host.statusOf(seat.label) ?? 'free';\n const channelId = this.allocation.get(seat.label) ?? PUBLIC_CHANNEL_ID;\n if (channelId !== PUBLIC_CHANNEL_ID) {\n const cluster = clusters.get(channelId) ?? { x: 0, y: 0, n: 0 };\n cluster.x += seat.x; cluster.y += seat.y; cluster.n += 1;\n clusters.set(channelId, cluster);\n }\n // The base renderer presents named section shells at the overview rung.\n // Do not redraw thousands of seat dots above those shells; click a\n // section to enter its seats, where the precise allocation paint resumes.\n if (!seatDetail) {\n const section = this.host.sectionOfLabel(seat.label);\n const point = section ? this.host.worldToScreen({ x: seat.x, y: seat.y }) : null;\n if (sectionTargets && section && point) {\n const bounds = sectionTargets.get(section.id) ?? {\n label: section.label, minX: point.x, minY: point.y, maxX: point.x, maxY: point.y,\n };\n bounds.minX = Math.min(bounds.minX, point.x);\n bounds.minY = Math.min(bounds.minY, point.y);\n bounds.maxX = Math.max(bounds.maxX, point.x);\n bounds.maxY = Math.max(bounds.maxY, point.y);\n sectionTargets.set(section.id, bounds);\n }\n continue;\n }\n if (status !== 'free') continue; // physical state always wins the paint\n let fill: string | null = null;\n let stroke: string | null = null;\n if (this.view === 'preview') {\n // ONE neutral unavailable state for everything this audience can't buy —\n // preview must never leak which private channel holds a seat. Both\n // states are painted, rather than leaving eligible seats in their\n // category colour: the exact allocation must be obvious at a glance.\n if (eligible?.has(seat.label)) {\n fill = PREVIEW_ELIGIBLE_FILL;\n stroke = PREVIEW_ELIGIBLE_STROKE;\n } else {\n fill = PREVIEW_UNAVAILABLE_FILL;\n stroke = PREVIEW_UNAVAILABLE_STROKE;\n }\n } else if (channelId !== PUBLIC_CHANNEL_ID) {\n fill = this.markerFor(channelId).color;\n stroke = ALLOCATION_STROKE;\n }\n if (!fill) continue;\n const point = this.host.worldToScreen({ x: seat.x, y: seat.y });\n if (!point) continue;\n if (point.x < -size || point.y < -size || point.x > width + size || point.y > height + size) continue;\n if (previewSections) {\n const section = this.host.sectionOfLabel(seat.label);\n if (section) {\n const bounds = previewSections.get(section.id) ?? {\n label: section.label, minX: point.x, minY: point.y, maxX: point.x, maxY: point.y,\n };\n bounds.minX = Math.min(bounds.minX, point.x);\n bounds.minY = Math.min(bounds.minY, point.y);\n bounds.maxX = Math.max(bounds.maxX, point.x);\n bounds.maxY = Math.max(bounds.maxY, point.y);\n previewSections.set(section.id, bounds);\n }\n }\n ctx.fillStyle = fill;\n if (this.view === 'preview' || channelId !== PUBLIC_CHANNEL_ID) {\n // Seats in the shared 2D renderer are circular. A generously covering\n // circular paint keeps Inspect allocation's channel colour independent\n // of the chart category, and replaces preview's former inner square so\n // there is no coloured rim or distracting grey-box effect.\n // `seatPixelSize` is the renderer's actual seat diameter. Match that\n // geometry (with only the stroke allowance), rather than inflating a\n // little status marker. That preserves the chart's configured row and\n // column gaps at every zoom and prevents category-colour rims leaking\n // through around a buyer-preview state.\n const radius = Math.max(2, half + Math.min(1.5, half * 0.06));\n ctx.globalAlpha = 1;\n ctx.beginPath();\n ctx.arc(point.x, point.y, radius, 0, Math.PI * 2);\n ctx.fill();\n ctx.strokeStyle = stroke ?? fill;\n ctx.lineWidth = this.view === 'preview'\n ? Math.max(1, Math.min(1.75, size * 0.13))\n : Math.max(1, Math.min(1.5, size * 0.1));\n ctx.stroke();\n // The overlay sits above the renderer, so it must restore the chart's\n // real label after painting an eligible buyer seat. Use the source\n // label verbatim and only when it remains legible inside the seat.\n if (this.view === 'preview' && eligible?.has(seat.label) && size >= 22) {\n this.paintPreviewSeatLabel(ctx, seat.label, point.x, point.y, radius);\n }\n } else {\n ctx.globalAlpha = 0.85;\n ctx.fillRect(point.x - half, point.y - half, size, size);\n }\n }\n ctx.globalAlpha = 1;\n if (previewSections) this.paintPreviewSectionLabels(ctx, previewSections);\n this.paintSectionTargets(sectionTargets);\n this.paintFlags(clusters);\n }\n\n /** Draw an eligible seat's actual chart label without inventing a new buyer\n * identifier. Long labels scale down and are omitted rather than overflowing\n * into an adjacent seat. */\n private paintPreviewSeatLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n x: number,\n y: number,\n radius: number,\n ): void {\n const maxWidth = radius * 1.55;\n let fontSize = Math.min(13, Math.max(7, radius * 0.55));\n const minFontSize = 6;\n while (fontSize >= minFontSize) {\n ctx.font = `800 ${fontSize}px var(--slm-font, system-ui, sans-serif)`;\n if (ctx.measureText(label).width <= maxWidth) break;\n fontSize -= 0.5;\n }\n if (fontSize < minFontSize) return;\n ctx.fillStyle = '#ffffff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, x, y);\n }\n\n /** A section overview is a navigation map. These transparent, keyboardable\n * hit areas sit over the renderer's section shells so both mouse and keyboard\n * always take the organizer into the real focused-section camera state. */\n private paintSectionTargets(\n sections: Map<string, { label: string; minX: number; minY: number; maxX: number; maxY: number }> | null,\n ): void {\n const layer = this.layer;\n if (!layer) return;\n layer.querySelectorAll('.slm-ch-section-target').forEach((el) => el.remove());\n if (!sections) return;\n for (const [id, section] of sections) {\n const width = section.maxX - section.minX;\n const height = section.maxY - section.minY;\n if (width < 20 || height < 20) continue;\n const target = document.createElement('button');\n target.type = 'button';\n target.className = 'slm-ch-section-target';\n target.style.left = `${section.minX - 8}px`;\n target.style.top = `${section.minY - 8}px`;\n target.style.width = `${width + 16}px`;\n target.style.height = `${height + 16}px`;\n target.setAttribute('aria-label', `Open ${section.label} seats`);\n target.addEventListener('click', () => {\n this.focusedSectionId = id;\n this.host.focusSection(id);\n this.paintRail();\n });\n layer.appendChild(target);\n }\n }\n\n /** Keep renderer section names legible over a dense, zoomed-out preview. */\n private paintPreviewSectionLabels(\n ctx: CanvasRenderingContext2D,\n sections: Map<string, { label: string; minX: number; minY: number; maxX: number; maxY: number }>,\n ): void {\n for (const section of sections.values()) {\n const width = section.maxX - section.minX;\n const height = section.maxY - section.minY;\n // A single row/seat has no overlaid central renderer label to protect.\n if (width < 52 || height < 26) continue;\n const centerX = (section.minX + section.maxX) / 2;\n const centerY = (section.minY + section.maxY) / 2;\n const fontSize = Math.max(11, Math.min(15, height * 0.16));\n ctx.font = `800 ${fontSize}px var(--slm-font, system-ui, sans-serif)`;\n const labelWidth = Math.min(width - 8, ctx.measureText(section.label).width + 18);\n const labelHeight = fontSize + 10;\n // This small backplate deliberately covers the renderer's original\n // label before the high-contrast replacement is drawn above it.\n ctx.fillStyle = 'rgba(11, 16, 28, .88)';\n ctx.fillRect(centerX - labelWidth / 2, centerY - labelHeight / 2, labelWidth, labelHeight);\n ctx.fillStyle = '#f8fafc';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(section.label, centerX, centerY);\n }\n }\n\n /** Letter flags at each channel's centroid — the non-color identity cue. */\n private paintFlags(clusters: Map<string, { x: number; y: number; n: number }>): void {\n const layer = this.layer;\n if (!layer) return;\n layer.querySelectorAll('.slm-ch-flag').forEach((el) => el.remove());\n if (this.view === 'preview') return;\n const ranked = [...clusters.entries()].sort((a, b) => b[1].n - a[1].n).slice(0, MAX_FLAGS);\n for (const [channelId, cluster] of ranked) {\n const channel = this.list?.channels.find((item) => item.id === channelId);\n if (!channel) continue;\n const point = this.host.worldToScreen({ x: cluster.x / cluster.n, y: cluster.y / cluster.n });\n if (!point) continue;\n const marker = this.markerFor(channelId);\n const flag = document.createElement('span');\n flag.className = 'slm-ch-flag';\n flag.style.left = `${point.x}px`;\n flag.style.top = `${point.y}px`;\n flag.innerHTML = `<span class=\"mk\" style=\"background:${esc(marker.color)}\">${esc(marker.letter)}</span>`\n + `${esc(channel.name)}${channel.state === 'paused' ? ' · Paused' : ''}`;\n layer.appendChild(flag);\n }\n }\n\n // ---- staged bar -----------------------------------------------------------\n\n private setStaged(html: string | null, cls = ''): void {\n const bar = this.stagedEl;\n if (!bar) return;\n if (!html) {\n bar.classList.remove('on', 'done', 'shake');\n bar.innerHTML = '';\n return;\n }\n bar.innerHTML = html;\n bar.className = `slm-ch-staged on${cls ? ` ${cls}` : ''}`;\n }\n\n private paintStagedBar(): void {\n if (!this.active || this.view === 'preview' || !this.caps.manage) { this.setStaged(null); return; }\n const { labels, buckets } = this.currentPlan();\n this.host.onStagedChange?.(mutationCount(buckets));\n if (!labels.length) { this.setStaged(null); return; }\n const target = this.nameOf(this.targetChannelId) ?? PUBLIC_CHANNEL_NAME;\n const mutations = mutationCount(buckets);\n const tooLarge = labels.length > MAX_ASSIGNMENT_UNITS;\n const skipped = buckets.skippedHeld.count + buckets.skippedBooked.count;\n const parts = [\n `<b>${labels.length.toLocaleString()}</b> selected`,\n `<b>+${mutations.toLocaleString()}</b> to ${esc(target)}`,\n ];\n if (buckets.alreadyInTarget.count) parts.push(`<b>${buckets.alreadyInTarget.count.toLocaleString()}</b> already in`);\n if (skipped) parts.push(`<b>${skipped.toLocaleString()}</b> can't move now`);\n this.setStaged(`\n <span>${parts.join(' · ')}</span>\n <span class=\"grow\"></span>\n <button type=\"button\" class=\"drop\" data-ch-act=\"discard\">Discard</button>\n <button type=\"button\" class=\"go\" data-ch-act=\"review\"${tooLarge ? ' disabled' : ''}>\n ${tooLarge ? `Maximum ${MAX_ASSIGNMENT_UNITS.toLocaleString()} seats` : 'Review changes'}\n </button>`);\n this.stagedEl?.querySelectorAll<HTMLElement>('[data-ch-act]').forEach((button) => {\n button.addEventListener('click', () => {\n if (button.dataset.chAct === 'discard') this.host.clearSelection();\n else this.openDialog({ kind: 'review' });\n });\n });\n }\n\n private setBanner(on: boolean, name = '', eligibleSeats?: number): void {\n const banner = this.bannerEl;\n if (!banner) return;\n this.host.root.classList.toggle('ch-preview', on);\n if (!on) { banner.classList.remove('on'); banner.innerHTML = ''; return; }\n const marker = this.previewAudience.length === 1\n ? this.markerFor(this.previewAudience[0])\n : { color: 'var(--slm-accent)', letter: '' };\n const availability = eligibleSeats == null\n ? ''\n : ` · ${eligibleSeats.toLocaleString()} ${eligibleSeats === 1 ? 'seat' : 'seats'} available now`;\n banner.innerHTML = `<span class=\"dot\" style=\"background:${esc(marker.color)}\"></span>\n Previewing buyer access · ${esc(name)}${availability} · read-only\n <button type=\"button\" data-ch-act=\"exit-preview\">Exit preview</button>`;\n banner.classList.add('on');\n banner.querySelector('[data-ch-act=\"exit-preview\"]')\n ?.addEventListener('click', () => this.setView('inspect'));\n }\n\n // ---- rail -----------------------------------------------------------------\n\n private setView(view: 'inspect' | 'preview'): void {\n this.view = view;\n if (view === 'inspect') {\n this.previewProjection = null;\n this.previewState = 'idle';\n this.setBanner(false);\n } else {\n if (!this.previewAudience.length) {\n const first = this.list?.channels.find((channel) => channel.state === 'active');\n this.previewAudience = [first ? first.id : PUBLIC_CHANNEL_ID];\n }\n void this.loadPreview();\n }\n this.paintRail();\n this.paintOverlay();\n this.paintStagedBar();\n this.onInteractionChange?.();\n }\n\n /** Set by the cockpit so a view switch can re-arm canvas selection. */\n onInteractionChange?: () => void;\n\n private async loadPreview(): Promise<void> {\n const audience = [...this.previewAudience];\n const names = audience.map((id) => this.nameOf(id) ?? PUBLIC_CHANNEL_NAME).join(' + ');\n this.setBanner(true, names);\n // Switching audience must not leave the previous audience's projection on\n // screen under the new name — that is a wrong answer, not a stale one.\n this.previewProjection = null;\n this.previewState = 'loading';\n if (this.active) this.paintRail();\n try {\n this.previewProjection = await this.host.api.channelPreview(this.host.eventKey, audience, {\n // Naming Public sale as the audience IS asking for public inventory; the\n // route filters the 'public' sentinel out of `channelIds`, so without\n // this the request would resolve to an empty scope and 422.\n includePublic: this.previewIncludePublic || audience.some(isPublicChannelId),\n });\n this.previewState = 'ready';\n // `eligible` is the server's exact current buyer scope. Older workers may\n // omit its redundant aggregate count, so use the returned label count\n // rather than hiding the organiser's most useful confirmation.\n const eligibleSeats = this.previewProjection.available === false\n ? undefined\n : this.previewProjection.counts?.eligible ?? this.previewProjection.eligible?.length;\n this.setBanner(true, names, eligibleSeats);\n } catch (err) {\n // 404/405 = the projection endpoint has not shipped on this worker yet.\n // Say so plainly; never substitute a local approximation for a server view.\n const status = err instanceof ManageApiError ? err.status : 0;\n this.previewState = status === 404 || status === 405 || status === 501 ? 'unsupported' : 'error';\n this.previewProjection = null;\n if (this.previewState === 'error') this.host.onError(err);\n }\n if (this.active) { this.paintRail(); this.paintOverlay(); }\n }\n\n /**\n * Replace the rail's markup — but only when it actually differs, and never at\n * the cost of where the organizer had scrolled to.\n *\n * The rail repaints on a clock, on every selection change and after every\n * mutation. Rewriting `innerHTML` each time resets `scrollTop`, which is\n * exactly what \"the rail gets stuck\" was: scroll down to Create channel, the\n * poll ticks, and the list snaps back to the top under the cursor. So skip the\n * write when the markup is byte-identical, and restore the offset when it is\n * not.\n *\n * Returns whether the DOM was rewritten. Callers must only re-wire listeners\n * when it was — a skipped paint keeps the old nodes AND their listeners, so\n * re-wiring would double every handler.\n */\n private setRailHtml(html: string): boolean {\n if (html === this.railHtml) return false;\n const rail = this.host.rail;\n const scrollTop = rail.scrollTop;\n rail.innerHTML = html;\n this.railHtml = html;\n if (scrollTop) rail.scrollTop = scrollTop;\n return true;\n }\n\n paintRail(): void {\n if (!this.active) return;\n const rail = this.host.rail;\n if (!this.caps.view) {\n this.setRailHtml(`<p class=\"slm-eyebrow\">Sales channels</p>\n <p class=\"slm-hint\">You need channel-management permission on this event to see allocations.</p>`);\n return;\n }\n if (this.loading && !this.list) {\n this.setRailHtml(`<p class=\"slm-eyebrow\">Sales channels</p>\n <div class=\"slm-ch-busy\" role=\"status\" data-ch-state=\"list-loading\">Loading channels and allocations…</div>`);\n return;\n }\n if (!this.list && this.loadError) {\n if (this.setRailHtml(`<p class=\"slm-eyebrow\">Sales channels</p>\n <div class=\"slm-ch-alert err\" role=\"alert\" data-ch-state=\"list-error\"><span>⚠</span>\n <span><b>Couldn't load sales channels.</b> This event may well have channels — we could not read them.\n Everything else on this event still works.\n <button type=\"button\" data-ch-act=\"retry\">Try again</button></span></div>`)) {\n rail.querySelector('[data-ch-act=\"retry\"]')?.addEventListener('click', () => { void this.refresh(); });\n }\n return;\n }\n\n const selection = this.host.selectionLabels();\n const grab = this.host.isCompact()\n ? `<div class=\"slm-ch-grab\"><span class=\"slm-ch-grabbar\"></span></div>`\n : '';\n const segment = this.viewSegmentHtml();\n const body = this.view === 'preview'\n ? this.previewRailHtml()\n : this.detailChannelId\n ? this.detailRailHtml(this.detailChannelId)\n : selection.length && this.caps.manage\n ? this.selectionRailHtml(selection)\n : this.listRailHtml();\n if (this.setRailHtml(`${grab}${segment}${body}`)) this.wireRail();\n this.paintStagedBar();\n }\n\n private viewSegmentHtml(): string {\n // The preview segment is offered even before the projection endpoint exists —\n // choosing it explains the gap rather than hiding the concept.\n const inspectOn = this.view === 'inspect' ? ' on' : '';\n const previewOn = this.view === 'preview' ? ' on' : '';\n return `<div class=\"slm-ch-viewseg\" role=\"group\" aria-label=\"Channels view\">\n <button type=\"button\" class=\"${inspectOn.trim()}\" data-ch-view=\"inspect\"\n aria-pressed=\"${this.view === 'inspect'}\">Inspect allocation</button>\n <button type=\"button\" class=\"${previewOn.trim()}\" data-ch-view=\"preview\"\n aria-pressed=\"${this.view === 'preview'}\">Preview buyer access</button>\n </div>${this.mapNavigationHtml()}`;\n }\n\n private mapNavigationHtml(): string {\n if (this.host.sections().length < 2) return '';\n const focused = this.focusedSectionId\n ? this.host.sections().find((section) => section.id === this.focusedSectionId)?.label ?? 'section'\n : null;\n const panOn = this.mapIntent === 'pan' ? ' on' : '';\n const assignOn = this.mapIntent === 'assign' ? ' on' : '';\n const intent = this.view === 'inspect' && this.caps.manage\n ? `<div class=\"slm-ch-viewseg\" role=\"group\" aria-label=\"Map interaction\">\n <button type=\"button\" class=\"${panOn.trim()}\" data-ch-map=\"pan\" aria-pressed=\"${this.mapIntent === 'pan'}\">Pan map</button>\n <button type=\"button\" class=\"${assignOn.trim()}\" data-ch-map=\"assign\" aria-pressed=\"${this.mapIntent === 'assign'}\">Assign seats</button>\n </div>\n <p>${this.mapIntent === 'pan'\n ? 'Drag to explore. Click a section to open its seats.'\n : 'Drag across seats to select them for allocation.'}</p>`\n : '<p>Drag to explore. Click a section to open its seats.</p>';\n return `<div class=\"slm-ch-mapnav\">\n <div class=\"slm-ch-mapnav-head\"><span>${focused ? `Viewing ${esc(focused)}` : 'Section overview'}</span>\n <button type=\"button\" data-ch-act=\"sections\">All sections</button></div>\n ${intent}\n </div>`;\n }\n\n private countsHtml(counts: { allocated: number; free: number; booked: number; held: number }, key: string): string {\n const cell = (id: string, value: number, label: string, cls = ''): string => {\n const previous = this.lastCounts.get(`${key}:${id}`);\n const bump = previous != null && previous !== value ? ' bump' : '';\n this.lastCounts.set(`${key}:${id}`, value);\n return `<span class=\"${cls}\"><b class=\"${bump.trim()}\">${value.toLocaleString()}</b> ${label}</span>`;\n };\n return `<span class=\"slm-ch-counts\">\n ${cell('allocated', counts.allocated, 'allocated')}\n ${cell('free', counts.free, 'free', 'free')}\n ${cell('booked', counts.booked, 'sold')}\n ${counts.held ? cell('held', counts.held, 'held') : ''}\n </span>`;\n }\n\n private channelRowHtml(\n channel: { id: string; name: string; state: string; counts: ChannelRecord['counts']; access?: ChannelRecord['access'] },\n opts: { builtin?: boolean; index?: number } = {},\n ): string {\n const marker = this.markerFor(channel.id);\n const badgeKind = opts.builtin ? 'builtin' : channel.state;\n const dim = channel.state === 'paused' || channel.state === 'archived' ? ' dim' : '';\n // The whole row opens the channel. It is only a control where there is a\n // channel to open and authority to act on it: Public sale is built in and\n // has no detail panel, and the detail panel is where every mutation lives,\n // so a view-only token is shown a card, not a door it cannot use.\n const opens = !opts.builtin && this.caps.manage && this.detailChannelId !== channel.id;\n const cls = `slm-ch-row${opts.builtin ? ' public' : ''}${channel.state === 'archived' ? ' archived' : ''}`\n + `${this.detailChannelId === channel.id ? ' on' : ''}${opens ? ' open' : ''}`;\n // Mutation affordances are ABSENT for a view-only token, never disabled.\n // ⋯ is now the SECONDARY route: rename, pause and archive live behind it,\n // while opening the channel is the row itself.\n const more = !opts.builtin && this.caps.manage\n ? `<button type=\"button\" class=\"slm-ch-more\" data-ch-menu=\"${esc(channel.id)}\"\n aria-label=\"More actions for ${esc(channel.name)}\" aria-haspopup=\"dialog\">⋯</button>`\n : '';\n const rowAttrs = opens\n ? ` role=\"button\" tabindex=\"0\" data-ch-open=\"${esc(channel.id)}\"\n aria-label=\"Open ${esc(channel.name)}\"`\n : '';\n return `<div class=\"${cls}\"${rowAttrs}>\n <span class=\"slm-ch-head\">\n <span class=\"slm-ch-mk${dim}\" style=\"background:${esc(marker.color)}\" aria-hidden=\"true\">${esc(marker.letter)}</span>\n <span class=\"slm-ch-name\">${esc(channel.name)}</span>\n <span class=\"slm-ch-badge ${badgeKind}\">${esc(stateBadge(opts.builtin ? 'builtin' : channel.state as 'active'))}</span>\n ${more}\n </span>\n ${this.countsHtml(channel.counts, channel.id || 'public')}\n ${opts.builtin ? '' : `<span class=\"slm-ch-access\">${esc(accessLine(channel.access))}</span>`}\n </div>`;\n }\n\n private listRailHtml(): string {\n const list = this.list!;\n const archivedCount = list.channels.filter((channel) => channel.state === 'archived').length;\n const visible = list.channels.filter((channel) => this.showArchived || channel.state !== 'archived');\n const rows = [\n this.channelRowHtml(list.publicSale, { builtin: true }),\n ...visible.map((channel, index) => this.channelRowHtml(channel, { index })),\n ].join('');\n // An event with no private channel is not an error and not a blank slot: every\n // seat is on public sale, which is a real and correct answer. Say that, and\n // put the one action that changes it directly underneath.\n const empty = visible.length ? '' : `<p class=\"slm-note\" data-ch-state=\"list-empty\">${\n archivedCount && !this.showArchived\n ? `No open channels — every seat is on public sale. ${archivedCount.toLocaleString()} archived channel${archivedCount === 1 ? ' is' : 's are'} hidden below.`\n : 'No private channels yet — every seat is on public sale.'}</p>`;\n const create = this.caps.manage\n ? `<button type=\"button\" class=\"slm-btn ghost\" style=\"width:100%\" data-ch-act=\"create\">+ Create channel</button>`\n : '';\n const readOnly = this.caps.manage ? '' :\n `<p class=\"slm-note\">You can see how inventory is allocated. Changing it needs channel-management permission.</p>`;\n return `\n <p class=\"slm-eyebrow\">Sales channels</p>\n <p class=\"slm-hint\">Channel colours and names are only visible to organizers, never to buyers.</p>\n <div class=\"slm-ch-list\">${rows}</div>\n ${empty}\n ${create}\n ${readOnly}\n ${this.assignEntryHtml()}\n <p class=\"slm-note\" style=\"margin-top:10px\">\n <button type=\"button\" class=\"slm-linkbtn\" data-ch-act=\"toggle-archived\" aria-pressed=\"${this.showArchived}\"\n style=\"text-align:left\">${this.showArchived ? 'Hide' : 'Show'} archived${archivedCount ? ` (${archivedCount})` : ''}</button>\n </p>`;\n }\n\n /**\n * The assignment entry point on the list rail.\n *\n * Collapsed it is ONE plain-language action, so the channels the organizer came\n * for stay at the top of the panel. Opened it is the same tool set that has\n * always worked, in the same order, plus the way back out — and opening it is\n * also what the map's \"Assign seats\" segment does, so the two routes into the\n * job cannot disagree about whether it is running.\n */\n private assignEntryHtml(): string {\n if (!this.caps.manage) return '';\n if (!this.assignOpen) {\n return `\n <button type=\"button\" class=\"slm-btn ghost\" style=\"width:100%;margin-top:8px\"\n data-ch-act=\"assign-open\" aria-expanded=\"false\">Assign seats to a channel</button>\n <p class=\"slm-note\">Move whole sections, rows, a dragged area or single seats out of public sale\n and into a channel. Nothing moves until you review and apply.</p>`;\n }\n return `<div style=\"margin-top:8px\">${this.assignmentToolsHtml({ collapsible: true })}</div>`;\n }\n\n /**\n * Destination-first assignment controls.\n *\n * These used to live only inside the selection rail, which meant every route\n * into them was gated behind \"select a seat on the map first\" — the section,\n * row and category choosers were invisible until the organizer had already\n * done the work by hand. They are still reachable before a seat is selected,\n * but they are no longer the first thing in the panel: on the list rail they\n * are disclosed by `assignEntryHtml`, and there they carry a way back out\n * (`collapsible`). In the selection rail there is nothing to disclose — a\n * selection IS the intent — so they paint unconditionally and without Done.\n */\n private assignmentToolsHtml(opts: { collapsible?: boolean } = {}): string {\n const options = this.assignableChannels()\n .map((channel) => `<option value=\"${esc(channel.id)}\"${channel.id === this.targetChannelId ? ' selected' : ''}>${esc(channel.name)}</option>`)\n .join('');\n const sections = this.host.sections().length\n ? '<button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"pick-sections\">Sections</button>' : '';\n const rows = this.assignmentRows().length\n ? '<button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"pick-rows\">Rows</button>' : '';\n // Drag box is a map INTENT, not a dialog: it arms the marquee, so it shows\n // its armed state the same way the map-navigation segment does.\n const dragClass = this.mapIntent === 'assign' ? 'slm-btn' : 'slm-btn ghost';\n const done = opts.collapsible\n ? `<button type=\"button\" class=\"slm-linkbtn\" data-ch-act=\"assign-close\"\n aria-expanded=\"true\" style=\"float:right;font-weight:800\">Done</button>`\n : '';\n return `\n <p class=\"slm-eyebrow\">${done}Assign inventory</p>\n <div class=\"slm-field\">\n <label for=\"slm-ch-target\">Assign to</label>\n <select class=\"slm-select\" id=\"slm-ch-target\" data-ch-target>${options}</select>\n </div>\n <p class=\"slm-eyebrow\" style=\"margin-top:12px\">Select by</p>\n <div class=\"slm-ch-row2\" style=\"margin-top:2px\">\n ${sections}${rows}\n <button type=\"button\" class=\"${dragClass}\" data-ch-act=\"drag-select\">Drag box</button>\n </div>\n <div class=\"slm-ch-row2\">\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"pick-category\">Category</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"seatlist\">Seat list ⌨</button>\n </div>\n <p class=\"slm-note\" style=\"margin-bottom:18px\">Choose a destination, then add whole sections,\n multiple rows, a dragged area, or individual seats.</p>`;\n }\n\n private selectionRailHtml(selection: string[]): string {\n const sources = selectionSources(selection, this.allocation, this.list);\n const conflict = this.conflict\n ? `<div class=\"slm-ch-alert err\" role=\"alert\"><span>⚠</span>\n <span><b>Assignments changed while you were editing.</b> Nothing was applied.\n Your ${selection.length.toLocaleString()}-seat selection is kept.\n <button type=\"button\" data-ch-act=\"refresh-review\">Refresh and review →</button></span></div>`\n : '';\n const bump = selection.length !== this.lastSelectionCount ? ' bump' : '';\n this.lastSelectionCount = selection.length;\n const tooLarge = selection.length > MAX_ASSIGNMENT_UNITS;\n const sourceRows = sources.map((row) => {\n const marker = this.markerFor(row.channelId);\n return `<div class=\"slm-ch-selsrc-row\">\n <span class=\"mk\" style=\"background:${esc(marker.color)}\" aria-hidden=\"true\">${esc(marker.letter)}</span>\n <b>${row.count.toLocaleString()}</b><span>${esc(row.name)}</span></div>`;\n }).join('');\n return `\n ${conflict}\n ${this.assignmentToolsHtml()}\n <div class=\"slm-selbar\"><span class=\"slm-selnum slm-ch-selnum${bump}\">${selection.length.toLocaleString()}</span>\n <span class=\"slm-sellabel\">selected</span></div>\n <div class=\"slm-ch-selsrc\" aria-live=\"polite\" aria-label=\"Selection sources\">${sourceRows}</div>\n ${tooLarge ? `<div class=\"slm-ch-alert warn\" role=\"alert\"><span>ℹ</span><span>\n <b>This selection is too large to apply at once.</b> Choose at most ${MAX_ASSIGNMENT_UNITS.toLocaleString()}\n seats, for example by splitting the venue into row groups.</span></div>` : ''}\n <p class=\"slm-note\">Changes are staged — nothing moves until you review and apply.\n Seats in checkout or already sold are never moved.</p>\n <div class=\"slm-ch-row2\">\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"discard\">Clear selection</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-act=\"review\"${tooLarge ? ' disabled' : ''}>Review changes</button>\n </div>\n <p class=\"slm-note\">The seat list offers the same selection with checkboxes for keyboard and screen-reader use.</p>`;\n }\n\n private detailRailHtml(channelId: string): string {\n const back = `<p class=\"slm-eyebrow\">\n <button type=\"button\" class=\"slm-linkbtn\" data-ch-act=\"back\" style=\"text-align:left\">‹ All channels</button>\n </p>`;\n const channel = this.list?.channels.find((item) => item.id === channelId);\n // Silently falling back to the list here was a lie of omission: an organizer\n // who opened a channel that has since been archived (by them elsewhere, or by\n // a colleague) was returned to the list with no explanation, as though the\n // press had missed. The channel is gone; say so, and leave the way back.\n if (!channel) {\n return `${back}\n <div class=\"slm-ch-alert warn\" role=\"status\" data-ch-state=\"detail-gone\"><span>ℹ</span>\n <span><b>This channel is no longer on this event.</b> It was archived or removed while you had it open.\n ${this.showArchived ? '' : 'Archived channels are hidden — use “Show archived” on the list to see it.'}</span></div>`;\n }\n const lifecycle = this.caps.manage ? `\n <p class=\"slm-eyebrow\" style=\"margin-top:18px\">Lifecycle</p>\n <div class=\"slm-ch-row2\" style=\"margin-top:2px\">\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"rename\">Rename</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"pause\">${channel.state === 'paused' ? 'Resume' : 'Pause'}</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-act=\"archive\">Archive…</button>\n </div>\n <p class=\"slm-note\">Archive returns the allocation to a destination you choose. Nothing is ever deleted silently.</p>` : '';\n const access = this.caps.manage ? this.distributeHtml(channel) : '';\n return `\n ${back}\n <p class=\"slm-eyebrow\">Channel · ${esc(channel.name)}</p>\n <div class=\"slm-ch-list\">${this.channelRowHtml(channel)}</div>\n ${access}\n ${lifecycle}`;\n }\n\n /**\n * \"Distribute\" — the ONE way this channel's seats reach a buyer.\n *\n * All four routes are here, and this is a real chooser again. It was cut down\n * to two actions in 0.42.0 for a good reason: `access_intent` was stored,\n * audited, and read by nothing, so \"Keep as protected reserve\" and \"Sell\n * through your own staff\" were labels an organizer could set and then wait\n * forever for something to happen. The server closed that hole on 2026-08-06 —\n * each declaration now opens exactly one route and REFUSES the other three —\n * so all four are honest choices and belong on the surface.\n *\n * None of the old copy came back with them. These sentences are written\n * against the enforcement matrix (`accessIntentDescription`), which is why\n * each one says what the route refuses as well as what it allows.\n *\n * The current route is stated, not merely styled: a chooser whose selection\n * you have to infer from a border is not a chooser. Its card carries a\n * \"Current route\" marker and drops its own select button, because pressing it\n * would do nothing.\n */\n private distributeHtml(channel: ChannelRecord): string {\n const intent = (channel.access?.intent ?? 'none') as ChannelAccessIntent;\n const live = channel.access?.hasActiveGrants === true;\n // A worker that predates buyer links answers 404 on the listing route, and\n // would answer 404 on the create too. Offering the action there would be a\n // button that can only fail; the status block below says why it is absent.\n const linksSupported = this.linksState !== 'unsupported';\n const hasLiveLink = this.links.some(accessLinkIsLive);\n // What is true RIGHT NOW — the route plus whether anyone has actually come\n // through it. \"Seats stay reserved\" is not a consolation: an allocated seat\n // is withheld from public sale either way, and that IS the useful fact.\n const state = intent === 'none'\n ? 'Protected reserve — no route can sell these seats. Every buyer path is refused.'\n : intent === 'internal'\n ? 'Your staff sell these seats. No buyer-facing route is open.'\n : live\n ? intent === 'server'\n ? 'Your website is letting buyers in. Only they can buy these seats.'\n : 'A buyer link is live. Only people with that link can buy these seats.'\n : intent === 'server'\n ? 'Set up for your website — no buyer has come through yet. Seats stay reserved.'\n : 'Set up for buyer links — no buyer has come through yet. Seats stay reserved.';\n const option = (\n route: ChannelAccessIntent, action: string, cta: string, primary: boolean,\n ): string => {\n const current = route === intent;\n return `<div class=\"slm-ch-dist${current ? ' on' : ''}\" data-ch-route=\"${esc(route)}\">\n <b>${esc(accessIntentLabel(route))}${current ? '<span class=\"cur\">Current route</span>' : ''}</b>\n <span class=\"why\">${esc(accessIntentDescription(route))}</span>\n ${current && !cta ? '' : `<button type=\"button\" class=\"slm-btn${primary && !current ? '' : ' ghost'}\"\n data-ch-act=\"${esc(action)}\">${esc(cta)}</button>`}\n </div>`;\n };\n return `\n <p class=\"slm-eyebrow\" style=\"margin-top:14px\">Distribute</p>\n <p class=\"slm-hint\">${esc(state)}</p>\n ${linksSupported ? option(\n 'hosted_link', 'link-create',\n hasLiveLink ? 'Create another buyer link' : 'Create buyer link', true,\n ) : ''}\n ${option('server', 'embed-code', intent === 'server' ? 'Get embed code' : 'Use a website or app', false)}\n ${option('internal', 'route-internal', intent === 'internal' ? '' : 'Hand to your staff', false)}\n ${option('none', 'route-none', intent === 'none' ? '' : 'Keep as reserve', false)}\n ${this.hostedLinksHtml()}\n ${intent === 'server' ? SERVER_INTEGRATION_HTML : ''}`;\n }\n\n // ---- buyer links ----------------------------------------------------------\n\n /**\n * Read the status projection for the open channel. Never paints — the caller\n * decides when the rail repaints, so a poll-driven reload does not fight a\n * user-driven one. A worker without M8 answers 404/405 and gets the honest\n * \"needs a newer server\" line rather than an error toast.\n */\n private async loadLinks(channelId: string): Promise<void> {\n if (!this.caps.view) return;\n const seq = ++this.linksSeq;\n // Superseded by a newer read of the same channel — a poll that started\n // before the mutation must not overwrite the mutation's own answer.\n const superseded = (): boolean => seq !== this.linksSeq || this.linksChannelId !== channelId;\n if (this.linksChannelId !== channelId) {\n this.links = [];\n this.linksChannelId = channelId;\n this.linksState = 'loading';\n }\n try {\n const res = await this.host.api.accessLinks(this.host.eventKey, channelId);\n if (superseded()) return; // the organizer moved on, or a fresher read won\n this.links = res.links ?? [];\n this.linksState = 'ready';\n } catch (err) {\n if (superseded()) return;\n const status = err instanceof ManageApiError ? err.status : 0;\n this.links = [];\n this.linksState = status === 404 || status === 405 || status === 501 ? 'unsupported' : 'error';\n if (this.linksState === 'error') this.host.onError(err);\n }\n }\n\n /**\n * The buyer-link status section of the detail panel.\n *\n * STATUS ONLY, by design (comp 06 `hosted`): label, state, expiry,\n * redemptions, seats per buyer, live sessions. There is no Copy control here\n * and no field to hang one on — the URL was shown once at creation and cannot\n * be produced again. Rotation is the recovery path, and it says so.\n *\n * Creating a link is the Distribute card's action, not this section's, so a\n * channel with no links renders nothing here rather than an empty heading and\n * a second button saying the same thing.\n */\n private hostedLinksHtml(): string {\n const eyebrow = `<p class=\"slm-eyebrow\" style=\"margin-top:18px\">Buyer links</p>`;\n if (this.linksState === 'unsupported') {\n return `${eyebrow}<div class=\"slm-ch-alert warn\" data-ch-state=\"links-unsupported\"><span>ℹ</span>\n <span><b>Buyer links need a newer server.</b> Everything else on this channel works normally.</span></div>`;\n }\n if (this.linksState === 'error') {\n return `${eyebrow}<div class=\"slm-ch-alert err\" role=\"alert\" data-ch-state=\"links-error\"><span>⚠</span>\n <span><b>Couldn't load this channel's links.</b> This is a failed read, not an empty list —\n any live link is still working.\n <button type=\"button\" data-ch-act=\"link-reload\">Try again</button></span></div>`;\n }\n // `idle` is the first paint of a channel the organizer has only just opened —\n // `openChannel` paints before `loadLinks` has even been awaited. Rendering\n // nothing there was a flash of empty that reads as \"this channel has no\n // links\", one tick before the real answer arrives.\n if (this.linksState === 'idle' || (this.linksState === 'loading' && !this.links.length)) {\n return `${eyebrow}<div class=\"slm-ch-busy\" role=\"status\" data-ch-state=\"links-loading\">Loading buyer links…</div>`;\n }\n if (!this.links.length) return '';\n return `${eyebrow}\n ${this.links.map((link) => this.linkCardHtml(link)).join('')}\n <p class=\"slm-note\">A link is shown once, when you create it. SeatLayer keeps only a fingerprint of it, so it\n can never be shown again — if a link is lost, rotate it and send the fresh one.</p>`;\n }\n\n private linkCardHtml(link: AccessLinkStatusRecord): string {\n const badge = accessLinkBadge(link);\n const used = link.maxRedemptions > 0\n ? Math.min(100, Math.round((link.redemptions / link.maxRedemptions) * 100))\n : 0;\n const rows = accessLinkPolicyLines(link)\n .map((row) => `<div class=\"slm-ch-lkrow\"><span class=\"k\">${esc(row.k)}</span>\n <span class=\"v\">${esc(row.v)}</span></div>`).join('');\n const sessions = link.activeSessions\n ? `<div class=\"slm-ch-lkrow\"><span class=\"k\">Buyers inside now</span>\n <span class=\"v\">${link.activeSessions.toLocaleString()}</span></div>`\n : '';\n const lastUsed = link.lastRedeemedAt\n ? `<div class=\"slm-ch-lkrow\"><span class=\"k\">Last opened</span>\n <span class=\"v\">${esc(new Date(link.lastRedeemedAt).toLocaleString())}</span></div>`\n : '';\n const actions = this.caps.manage && accessLinkIsLive(link)\n ? `<div class=\"slm-ch-row2\">\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-rotate=\"${esc(link.id)}\">Rotate</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-revoke=\"${esc(link.id)}\">Revoke</button>\n </div>`\n : '';\n return `<div class=\"slm-ch-link\">\n <span class=\"lk-head\">\n <span class=\"lk-name\">${esc(link.label || 'Buyer link')}</span>\n <span class=\"slm-ch-badge ${badge.kind}\">${esc(badge.text)}</span>\n </span>\n <div class=\"slm-ch-meter\" role=\"img\"\n aria-label=\"${link.redemptions.toLocaleString()} of ${link.maxRedemptions.toLocaleString()} redemptions used\">\n <i style=\"width:${used}%\"></i></div>\n ${rows}${sessions}${lastUsed}\n <div class=\"slm-ch-lkrow\"><span class=\"k\">The URL</span>\n <span class=\"v\">Revealed once at creation — not recoverable</span></div>\n ${actions}\n </div>`;\n }\n\n private previewRailHtml(): string {\n const audienceOptions = [\n { id: PUBLIC_CHANNEL_ID, name: this.list?.publicSale.name ?? PUBLIC_CHANNEL_NAME },\n ...(this.list?.channels ?? [])\n .filter((channel) => channel.state !== 'archived')\n .map((channel) => ({ id: channel.id, name: channel.name })),\n ];\n const current = this.previewAudience[0] ?? PUBLIC_CHANNEL_ID;\n const options = audienceOptions\n .map((entry) => `<option value=\"${esc(entry.id)}\"${entry.id === current ? ' selected' : ''}>${esc(entry.name)}</option>`)\n .join('');\n const unsupported = this.previewState === 'unsupported'\n ? `<div class=\"slm-ch-alert warn\" data-ch-state=\"preview-unsupported\"><span>ℹ</span>\n <span><b>Preview needs a newer server.</b> Allocation management works normally;\n the buyer-view simulation will appear once this event's API is updated.</span></div>`\n : '';\n // Loading and failure are distinct from \"this audience can buy nothing\",\n // which is what an empty result area used to imply for all three.\n const busy = this.previewState === 'loading'\n ? `<div class=\"slm-ch-busy\" role=\"status\" data-ch-state=\"preview-loading\">Asking the server what this audience sees…</div>`\n : '';\n const failed = this.previewState === 'error'\n ? `<div class=\"slm-ch-alert err\" role=\"alert\" data-ch-state=\"preview-error\"><span>⚠</span>\n <span><b>Couldn't load the buyer preview.</b> Nothing is wrong with this audience's seats —\n the simulation itself failed to load.\n <button type=\"button\" data-ch-act=\"preview-retry\">Try again</button></span></div>`\n : '';\n // The server decides an audience is unpreviewable, not the client: a paused\n // or archived channel comes back `available:false` and we show the landing\n // state a real buyer would hit.\n const unavailable = this.previewProjection?.available === false\n ? `<div class=\"slm-ch-alert warn\" role=\"status\"><span>⏸</span>\n <span><b>This private sale is not available.</b> ${esc((this.previewProjection.unavailable ?? [])\n .map((entry) => `${this.nameOf(entry.channelId) ?? 'This channel'} is ${entry.state}`)\n .join('; ') || 'The audience cannot buy right now')}.\n A buyer arriving with this access sees this message, not these seats.</span></div>`\n : '';\n const eligibleSeats = this.previewProjection?.counts?.eligible ?? this.previewProjection?.eligible?.length;\n const summary = eligibleSeats != null && this.previewProjection?.available !== false\n ? `<div class=\"slm-ch-alert info\"><span>✓</span><span><b>${eligibleSeats.toLocaleString()} ${eligibleSeats === 1 ? 'seat is' : 'seats are'} available now.</b>\n This is the exact buyer-visible allocation.${this.previewProjection?.includePublic === false\n ? ' Public sale seats are <b>not</b> included in this access.' : ''}</span></div>`\n : '';\n const includePublic = isPublicChannelId(current) ? '' : `\n <label class=\"slm-note\" style=\"display:flex;gap:8px;align-items:center;margin:10px 0\">\n <input type=\"checkbox\" data-ch-includepublic ${this.previewIncludePublic ? 'checked' : ''} />\n Also include Public sale seats in this grant\n </label>`;\n return `\n <p class=\"slm-eyebrow\">Preview buyer access</p>\n <div class=\"slm-field\">\n <label for=\"slm-ch-audience\">Audience</label>\n <select class=\"slm-select\" id=\"slm-ch-audience\" data-ch-audience>${options}</select>\n </div>\n ${includePublic}\n <p class=\"slm-hint\">This is the same projection the buyer SDK receives for this audience — not a local\n approximation. It is read-only: clicks open seat details, and no holds are created.</p>\n ${busy}${failed}${unsupported}${unavailable}\n <div class=\"slm-ch-legend\">\n <div class=\"r\"><span class=\"sw\" style=\"background:#6e7bff\"></span> Eligible &amp; free — buyable by this audience</div>\n <div class=\"r\"><span class=\"sw\" style=\"background:#3a4051\"></span> Unavailable to this audience (one neutral state)</div>\n <div class=\"r\"><span class=\"sw\" style=\"background:#22a06b\"></span> Sold — same as any buyer sees</div>\n </div>\n ${summary}`;\n }\n\n private paintSelection(): void {\n // A selection proves the intent the disclosure was waiting for, so clearing\n // it later returns the organizer to the tools rather than to the collapsed\n // action they would have to press again.\n if (this.caps.manage && this.host.selectionLabels().length) this.assignOpen = true;\n // A selection change swaps the rail between list and staged-selection bodies,\n // so repaint rather than patch — the rail is small and this keeps one path.\n if (this.view === 'inspect' && !this.detailChannelId) this.paintRail();\n }\n\n private wireRail(): void {\n const rail = this.host.rail;\n rail.querySelectorAll<HTMLElement>('[data-ch-view]').forEach((button) => {\n button.addEventListener('click', () => this.setView(button.dataset.chView as 'inspect' | 'preview'));\n });\n rail.querySelectorAll<HTMLElement>('[data-ch-map]').forEach((button) => {\n button.addEventListener('click', () => {\n this.mapIntent = button.dataset.chMap === 'assign' ? 'assign' : 'pan';\n // Arming the marquee IS asking to assign, so the tools that finish the\n // job come with it. This is the discoverable route for an organizer who\n // never pressed \"Assign seats to a channel\" under the list.\n if (this.mapIntent === 'assign') this.assignOpen = true;\n this.paintRail();\n this.onInteractionChange?.();\n });\n });\n // The whole row is the door. It is a role=\"button\" element, so it owes the\n // keyboard the two keys a real button answers to — and Space must not scroll\n // the rail on the way.\n rail.querySelectorAll<HTMLElement>('[data-ch-open]').forEach((row) => {\n const open = (): void => this.openChannel(row.dataset.chOpen!);\n row.addEventListener('click', open);\n row.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' && event.key !== ' ' && event.key !== 'Spacebar') return;\n event.preventDefault();\n open();\n });\n });\n // ⋯ sits INSIDE that door, so it must not also open it.\n rail.querySelectorAll<HTMLElement>('[data-ch-menu]').forEach((button) => {\n button.addEventListener('click', (event) => {\n event.stopPropagation();\n this.openDialog({ kind: 'menu', channelId: button.dataset.chMenu! });\n });\n button.addEventListener('keydown', (event) => { event.stopPropagation(); });\n });\n rail.querySelectorAll<HTMLElement>('[data-ch-rotate]').forEach((button) => {\n button.addEventListener('click', () => this.openDialog({\n kind: 'linkRotate', channelId: this.detailChannelId!, linkId: button.dataset.chRotate!,\n }));\n });\n rail.querySelectorAll<HTMLElement>('[data-ch-revoke]').forEach((button) => {\n button.addEventListener('click', () => this.openDialog({\n kind: 'linkRevoke', channelId: this.detailChannelId!, linkId: button.dataset.chRevoke!,\n }));\n });\n const target = rail.querySelector<HTMLSelectElement>('[data-ch-target]');\n target?.addEventListener('change', () => {\n this.targetChannelId = target.value;\n this.conflict = false;\n this.paintRail();\n });\n const audience = rail.querySelector<HTMLSelectElement>('[data-ch-audience]');\n audience?.addEventListener('change', () => {\n this.previewAudience = [audience.value];\n void this.loadPreview();\n });\n const includePublic = rail.querySelector<HTMLInputElement>('[data-ch-includepublic]');\n includePublic?.addEventListener('change', () => {\n this.previewIncludePublic = includePublic.checked;\n void this.loadPreview();\n });\n const grab = rail.querySelector<HTMLElement>('.slm-ch-grab');\n grab?.addEventListener('click', () => this.cycleDetent());\n rail.querySelectorAll<HTMLElement>('[data-ch-act]').forEach((button) => {\n button.addEventListener('click', () => this.railAction(button.dataset.chAct!));\n });\n }\n\n /** Open a channel's detail panel and start its buyer-link read. */\n private openChannel(channelId: string): void {\n this.detailChannelId = channelId;\n // Paint the panel FIRST so the organizer lands on the channel immediately,\n // with the links section showing its own loading state, rather than waiting\n // on a network read behind an unchanged rail.\n this.paintRail();\n void this.loadLinks(channelId).then(() => this.paintRail());\n }\n\n private railAction(action: string): void {\n switch (action) {\n case 'sections':\n this.focusedSectionId = null;\n this.host.showSectionOverview();\n this.paintRail();\n break;\n case 'create': this.openDialog({ kind: 'create' }); break;\n case 'review': this.openDialog({ kind: 'review' }); break;\n case 'rename': this.openDialog({ kind: 'rename', channelId: this.detailChannelId! }); break;\n case 'archive': this.openDialog({ kind: 'archive', channelId: this.detailChannelId! }); break;\n case 'seatlist': this.openDialog({ kind: 'seatlist' }); break;\n case 'pause': void this.togglePause(); break;\n case 'discard': this.host.clearSelection(); break;\n case 'back':\n this.detailChannelId = null;\n this.linksChannelId = null;\n this.links = [];\n this.linksState = 'idle';\n this.paintRail();\n break;\n // Choosing the buyer-link route IS creating the first link — the dialog\n // declares the route on submit (see `createLink`), so this stays one\n // gesture whether the channel is already on `hosted_link` or not.\n case 'link-create':\n this.openDialog({ kind: 'linkCreate', channelId: this.detailChannelId! });\n break;\n // The one thing this screen can actually do for a website integration is\n // record that the channel is meant for one — and since 2026-08-06 that\n // record is what AUTHORIZES the integration to mint buyer sessions at all,\n // so it is the substantive half of the job, not a flag.\n case 'embed-code': void this.chooseWebsiteIntegration(); break;\n case 'route-internal': void this.setAccessIntent('internal'); break;\n case 'route-none': void this.setAccessIntent('none'); break;\n case 'link-reload':\n if (this.detailChannelId) void this.reloadLinks();\n break;\n case 'retry': void this.refresh(); break;\n case 'toggle-archived':\n this.showArchived = !this.showArchived;\n void this.refresh();\n break;\n case 'refresh-review':\n this.conflict = false;\n void this.refresh().then(() => this.openDialog({ kind: 'review' }));\n break;\n case 'pick-sections': this.openDialog({ kind: 'scope', scope: 'sections' }); break;\n case 'pick-rows': this.openDialog({ kind: 'scope', scope: 'rows' }); break;\n case 'drag-select':\n this.mapIntent = 'assign';\n this.paintRail();\n this.onInteractionChange?.();\n break;\n case 'pick-category': this.pickCategory(); break;\n case 'assign-open':\n this.assignOpen = true;\n this.paintRail();\n break;\n // Collapsing the tools must also disarm the marquee. Leaving it armed\n // would hide a mode the map is still in — the organizer would drag to pan\n // and select seats instead, with no control on screen saying why.\n case 'assign-close':\n this.assignOpen = false;\n this.mapIntent = 'pan';\n this.paintRail();\n this.onInteractionChange?.();\n break;\n case 'preview-retry': void this.loadPreview(); break;\n default: break;\n }\n }\n\n // ---- selection helpers ----------------------------------------------------\n\n /** Derived once per mode entry — see `assignmentRowsCache`. */\n private assignmentRows(): ChannelsRowView[] {\n if (!this.assignmentRowsCache) this.assignmentRowsCache = this.host.rows();\n return this.assignmentRowsCache;\n }\n\n private pickCategory(): void {\n const categories = this.host.categories();\n if (!categories.length) return;\n this.promptChoice('Select a whole category', categories.map((c) => ({ value: c.key, label: c.label })), (value) => {\n this.host.selectByLabels(this.host.labelsInCategory(value));\n });\n }\n\n /** A tiny modal chooser reusing the dialog primitive (focus trap + Escape). */\n private promptChoice(\n title: string,\n options: Array<{ value: string; label: string }>,\n onPick: (value: string) => void,\n ): void {\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">${esc(title)}</h3>\n <div class=\"slm-field\">\n <label for=\"slm-ch-choice\">Choose one</label>\n <select class=\"slm-select\" id=\"slm-ch-choice\">\n ${options.map((option) => `<option value=\"${esc(option.value)}\">${esc(option.label)}</option>`).join('')}\n </select>\n </div>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-confirm>Select</button>\n </div>`, (root) => {\n root.querySelector('[data-ch-confirm]')?.addEventListener('click', () => {\n const select = root.querySelector<HTMLSelectElement>('#slm-ch-choice');\n const value = select?.value;\n this.closeDialog();\n if (value) onPick(value);\n });\n });\n }\n\n /**\n * Add several whole sections, or several whole rows, in one operation.\n *\n * ADDITIVE by contract: the chooser starts from the labels already selected\n * and only ever grows that set, so opening it never destroys a hard-won\n * marquee or seat-list selection. The confirm button always states the net\n * number of seats it will add, and refuses to exceed `MAX_ASSIGNMENT_UNITS`.\n *\n * Rows get the richer variant. A large venue has thousands of them, so they\n * arrive collapsed under their section, with a section-level tri-state\n * checkbox, a search across every row, and a render cap — the flat list used\n * for sections would be an unusable wall of buttons.\n */\n private renderScopeDialog(state: DialogState): void {\n const scope = state.scope === 'rows' ? 'rows' : 'sections';\n const options = scope === 'sections'\n ? this.host.sections().map((section) => ({\n id: section.id,\n label: section.label,\n group: 'Sections',\n labels: this.host.labelsInSection(section.id),\n }))\n : this.assignmentRows().map((row) => ({\n id: row.id,\n label: row.label,\n group: row.sectionLabel,\n labels: row.labels,\n }));\n // A section or row with nothing selectable in it is a dead entry, not a\n // choice — offering it would produce an \"Add 0 seats\" button.\n const available = options.filter((option) => option.labels.length > 0);\n const grouped = new Map<string, typeof available>();\n for (const option of available) {\n const group = grouped.get(option.group) ?? [];\n group.push(option);\n grouped.set(option.group, group);\n }\n\n if (scope === 'rows') {\n const groups = [...grouped.entries()];\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Add multiple rows</h3>\n <p class=\"sub\">Sections stay collapsed for speed. Select a whole section, expand only the rows you need, or search across every row.</p>\n <div class=\"slm-ch-scopebar\">\n <label>Find section or row<input type=\"search\" data-ch-scope-search placeholder=\"e.g. Orchestra or AA\"></label>\n <span class=\"slm-ch-scopesummary\" data-ch-scope-summary aria-live=\"polite\">0 rows selected</span>\n </div>\n <p class=\"slm-ch-scopehint\" data-ch-scope-filter>Showing section groups. Expand one or search to see rows.</p>\n <div class=\"slm-ch-seatlist\" data-ch-scope-list></div>\n <p class=\"slm-ch-err\" data-ch-error hidden></p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-add-scope disabled>Add seats</button>\n </div>`, (dialog) => {\n const byId = new Map(available.map((option) => [option.id, option]));\n const picked = new Set<string>();\n const expanded = new Set<number>();\n const current = new Set(this.host.selectionLabels());\n const confirm = dialog.querySelector<HTMLButtonElement>('[data-ch-add-scope]')!;\n const error = dialog.querySelector<HTMLElement>('[data-ch-error]')!;\n const list = dialog.querySelector<HTMLElement>('[data-ch-scope-list]')!;\n const search = dialog.querySelector<HTMLInputElement>('[data-ch-scope-search]')!;\n const summary = dialog.querySelector<HTMLElement>('[data-ch-scope-summary]')!;\n const filterHint = dialog.querySelector<HTMLElement>('[data-ch-scope-filter]')!;\n const renderLimit = 200;\n let query = '';\n\n const selectedLabels = (): Set<string> => {\n const labels = new Set(current);\n for (const id of picked) for (const label of byId.get(id)?.labels ?? []) labels.add(label);\n return labels;\n };\n const update = (): void => {\n const labels = selectedLabels();\n const added = labels.size - current.size;\n const tooLarge = labels.size > MAX_ASSIGNMENT_UNITS;\n confirm.disabled = added === 0 || tooLarge;\n confirm.textContent = tooLarge\n ? `Maximum ${MAX_ASSIGNMENT_UNITS.toLocaleString()} seats`\n : `Add ${added.toLocaleString()} seat${added === 1 ? '' : 's'}`;\n error.hidden = !tooLarge;\n error.textContent = tooLarge\n ? `That would make ${labels.size.toLocaleString()} selected seats. Choose fewer rows or sections.`\n : '';\n summary.textContent = `${picked.size.toLocaleString()} row${picked.size === 1 ? '' : 's'} · ${added.toLocaleString()} seat${added === 1 ? '' : 's'} added`;\n };\n const renderList = (): void => {\n const blocks: string[] = [];\n let totalMatches = 0;\n let rendered = 0;\n groups.forEach(([group, items], groupIndex) => {\n const normalizedGroup = group.toLocaleLowerCase();\n const matches = query\n ? items.filter((item) => `${normalizedGroup} ${item.label.toLocaleLowerCase()}`.includes(query))\n : items;\n if (query && !matches.length) return;\n totalMatches += matches.length;\n const allPicked = items.every((item) => picked.has(item.id));\n const somePicked = !allPicked && items.some((item) => picked.has(item.id));\n const open = Boolean(query) || expanded.has(groupIndex);\n const room = Math.max(0, renderLimit - rendered);\n const visible = open ? matches.slice(0, room) : [];\n rendered += visible.length;\n const seatCount = items.reduce((sum, item) => sum + item.labels.length, 0);\n blocks.push(`<div class=\"slm-ch-scopegroup\">\n <button type=\"button\" class=\"slm-ch-groupcheck\" role=\"checkbox\" aria-checked=\"${allPicked ? 'true' : somePicked ? 'mixed' : 'false'}\"\n aria-label=\"Select all ${items.length.toLocaleString()} rows in ${esc(group)}\" data-ch-scope-group=\"${groupIndex}\">\n <span class=\"box\" aria-hidden=\"true\">✓</span><span>${esc(group)}</span>\n <span class=\"meta\">${items.length.toLocaleString()} rows · ${seatCount.toLocaleString()} seats</span>\n </button>\n <button type=\"button\" class=\"slm-ch-grouptoggle\" aria-expanded=\"${open}\" aria-label=\"${open ? 'Hide' : 'Show'} rows in ${esc(group)}\"\n data-ch-scope-toggle=\"${groupIndex}\">${open ? 'Hide' : 'Show'}</button>\n </div>`);\n blocks.push(...visible.map((option) => `<button type=\"button\" class=\"slm-ch-seatitem\" role=\"checkbox\"\n aria-checked=\"${picked.has(option.id)}\" data-ch-scope-id=\"${esc(option.id)}\">\n <span class=\"box\" aria-hidden=\"true\">✓</span><span>${esc(option.label)}</span>\n <span class=\"meta\">${option.labels.length.toLocaleString()} seat${option.labels.length === 1 ? '' : 's'}</span>\n </button>`));\n if (open && matches.length > visible.length) {\n blocks.push(`<p class=\"slm-ch-scopehint\">${(matches.length - visible.length).toLocaleString()} more row${matches.length - visible.length === 1 ? '' : 's'}. Search to narrow the list.</p>`);\n }\n });\n // Two different nothings: nothing matched the search, versus this chart\n // has no assignable rows at all. The second one is not a search result.\n list.innerHTML = blocks.join('')\n || (query\n ? `<div class=\"slm-ch-scope-empty\" data-ch-state=\"scope-nomatch\">No sections or rows match “${esc(query)}”.</div>`\n : `<div class=\"slm-ch-scope-empty\" data-ch-state=\"scope-empty\">This chart has no rows with selectable seats.\n Use Drag box or the seat list instead.</div>`);\n filterHint.textContent = query\n ? `Showing ${rendered.toLocaleString()} of ${totalMatches.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`\n : 'Showing section groups. Expand one or search to see rows.';\n list.querySelectorAll<HTMLElement>('[data-ch-scope-group]').forEach((button) => button.addEventListener('click', () => {\n const items = groups[Number(button.dataset.chScopeGroup)]?.[1] ?? [];\n const remove = items.every((item) => picked.has(item.id));\n for (const item of items) remove ? picked.delete(item.id) : picked.add(item.id);\n renderList();\n update();\n }));\n list.querySelectorAll<HTMLElement>('[data-ch-scope-toggle]').forEach((button) => button.addEventListener('click', () => {\n const index = Number(button.dataset.chScopeToggle);\n if (expanded.has(index)) expanded.delete(index);\n else expanded.add(index);\n renderList();\n }));\n list.querySelectorAll<HTMLElement>('[data-ch-scope-id]').forEach((button) => button.addEventListener('click', () => {\n const id = button.dataset.chScopeId!;\n if (picked.has(id)) picked.delete(id);\n else picked.add(id);\n renderList();\n update();\n }));\n };\n\n search.addEventListener('input', () => {\n query = search.value.trim().toLocaleLowerCase();\n renderList();\n update();\n });\n confirm.addEventListener('click', () => {\n const labels = [...selectedLabels()];\n if (!picked.size || labels.length > MAX_ASSIGNMENT_UNITS) return;\n this.closeDialog();\n this.host.selectByLabels(labels);\n });\n renderList();\n update();\n });\n return;\n }\n\n const body = [...grouped.entries()].map(([group, items]) => `\n <div class=\"slm-ch-seatgroup\"><span>${esc(group)}</span></div>\n ${items.map((option) => `<button type=\"button\" class=\"slm-ch-seatitem\" role=\"checkbox\"\n aria-checked=\"false\" data-ch-scope-id=\"${esc(option.id)}\">\n <span class=\"box\" aria-hidden=\"true\">✓</span>\n <span>${esc(option.label)}</span>\n <span class=\"meta\">${option.labels.length.toLocaleString()} seat${option.labels.length === 1 ? '' : 's'}</span>\n </button>`).join('')}`).join('');\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Add whole sections</h3>\n <p class=\"sub\">Choose one or more. They are added to the seats already selected on the map.</p>\n <div class=\"slm-ch-seatlist\">${body || `<div class=\"slm-ch-scope-empty\" data-ch-state=\"scope-empty\">This chart has no sections with selectable seats.\n Use Drag box or the seat list instead.</div>`}</div>\n <p class=\"slm-ch-err\" data-ch-error hidden></p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-add-scope disabled>Add seats</button>\n </div>`, (dialog) => {\n const byId = new Map(available.map((option) => [option.id, option]));\n const picked = new Set<string>();\n const current = new Set(this.host.selectionLabels());\n const confirm = dialog.querySelector<HTMLButtonElement>('[data-ch-add-scope]')!;\n const error = dialog.querySelector<HTMLElement>('[data-ch-error]')!;\n const selectedLabels = (): Set<string> => {\n const labels = new Set(current);\n for (const id of picked) for (const label of byId.get(id)?.labels ?? []) labels.add(label);\n return labels;\n };\n const update = (): void => {\n const labels = selectedLabels();\n const added = labels.size - current.size;\n const tooLarge = labels.size > MAX_ASSIGNMENT_UNITS;\n confirm.disabled = added === 0 || tooLarge;\n confirm.textContent = tooLarge\n ? `Maximum ${MAX_ASSIGNMENT_UNITS.toLocaleString()} seats`\n : `Add ${added.toLocaleString()} seat${added === 1 ? '' : 's'}`;\n error.hidden = !tooLarge;\n error.textContent = tooLarge\n ? `That would make ${labels.size.toLocaleString()} selected seats. Choose fewer rows or sections.`\n : '';\n };\n dialog.querySelectorAll<HTMLElement>('[data-ch-scope-id]').forEach((button) => {\n button.addEventListener('click', () => {\n const id = button.dataset.chScopeId!;\n if (picked.has(id)) picked.delete(id);\n else picked.add(id);\n button.setAttribute('aria-checked', String(picked.has(id)));\n update();\n });\n });\n confirm.addEventListener('click', () => {\n const labels = [...selectedLabels()];\n if (!picked.size || labels.length > MAX_ASSIGNMENT_UNITS) return;\n this.closeDialog();\n this.host.selectByLabels(labels);\n });\n update();\n });\n }\n\n // ---- dialogs --------------------------------------------------------------\n\n private openDialog(state: DialogState): void {\n this.dialog = state;\n this.renderDialog();\n }\n\n private renderDialog(): void {\n const state = this.dialog;\n if (!state) return;\n if (state.kind === 'create') this.renderCreateDialog(state);\n else if (state.kind === 'review') this.renderReviewDialog(state);\n else if (state.kind === 'scope') this.renderScopeDialog(state);\n else if (state.kind === 'archive') this.renderArchiveDialog(state);\n else if (state.kind === 'rename') this.renderRenameDialog(state);\n else if (state.kind === 'seatlist') this.renderSeatListDialog();\n else if (state.kind === 'menu') this.renderMenuDialog(state);\n else if (state.kind === 'linkCreate') this.renderLinkCreateDialog(state);\n else if (state.kind === 'linkRotate') this.renderLinkRotateDialog(state);\n else if (state.kind === 'linkRevoke') this.renderLinkRevokeDialog(state);\n else if (state.kind === 'intentSwitch') this.renderIntentSwitchDialog(state);\n }\n\n /**\n * `channel_intent_switch_blocked` — buyers are inside the route being left.\n *\n * The same review-then-acknowledge shape as the archive and chart-drop guards,\n * because it is the same kind of decision: the server refuses once, names\n * exactly what is at stake, and only a deliberate second press goes through.\n * What acknowledging does is spelled out per consequence — links close now,\n * checkouts already running survive and drain — rather than hidden behind a\n * word like \"force\".\n */\n private renderIntentSwitchDialog(state: DialogState): void {\n const channel = this.list?.channels.find((item) => item.id === state.channelId);\n const to = state.intentTo;\n if (!channel || !to || !this.caps.manage) { this.closeDialog(); return; }\n const { headline, consequences } = intentSwitchBlockedCopy(state.switchBlocked);\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Change how ${esc(channel.name)} reaches buyers?</h3>\n <p class=\"sub\">${esc(headline)}</p>\n <div class=\"slm-ch-alert warn\" role=\"alert\"><span>⚠</span><span>\n ${consequences.map((line) => `<span style=\"display:block;margin-bottom:6px\">${esc(line)}</span>`).join('')}\n </span></div>\n ${state.pendingLink ? `<p class=\"slm-note\">Your new buyer link is created as soon as\n the route changes — you will not have to fill the form in again.</p>` : ''}\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Leave it as it is</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-intent-ack${state.busy ? ' disabled' : ''}>\n ${state.busy ? 'Changing…' : `Change to \"${esc(accessIntentLabel(to))}\"`}</button>\n </div>`, (dialog) => {\n dialog.querySelector('[data-ch-intent-ack]')?.addEventListener('click', () => {\n void this.acknowledgeIntentSwitch(to, state.pendingLink ?? null);\n });\n });\n }\n\n /**\n * The acknowledged retry. The declare and the create stay one gesture across\n * the sheet: if this switch was the first half of a declare-then-create, the\n * held form finishes on the far side of the acknowledgement.\n */\n private async acknowledgeIntentSwitch(\n intent: ChannelAccessIntent, pendingLink: PendingLinkInput | null,\n ): Promise<void> {\n const channelId = this.detailChannelId;\n if (!channelId) { this.closeDialog(); return; }\n if (this.dialog) { this.dialog.busy = true; this.renderDialog(); }\n const ok = await this.setAccessIntent(intent, { acknowledgeLiveAccess: true });\n if (!ok) {\n // `setAccessIntent` has already said why, through the toast lane or by\n // re-opening this sheet with fresher counts. Never leave a stuck spinner.\n if (this.dialog?.kind === 'intentSwitch') { this.dialog.busy = false; this.renderDialog(); }\n return;\n }\n if (!pendingLink) { this.closeDialog(); return; }\n // Un-busy BEFORE the create: `showDialogError` paints into the mounted\n // sheet without re-rendering it, so a create that fails here would otherwise\n // report itself under a permanently disabled \"Changing…\" button. Pressing\n // again re-acknowledges (idempotent) and retries the link.\n if (this.dialog?.kind === 'intentSwitch') { this.dialog.busy = false; this.renderDialog(); }\n await this.mintLink(channelId, pendingLink);\n }\n\n /**\n * Mount a modal: `aria-modal` dialog, programmatic name, focus moved inside,\n * Tab trapped, Escape closes WITHOUT mutating, focus restored on close (§13).\n */\n private renderScrim(inner: string, wire: (dialog: HTMLElement) => void): void {\n const existing = this.scrimEl;\n if (!existing) this.lastFocus = (document.activeElement as HTMLElement | null) ?? null;\n existing?.remove();\n const scrim = document.createElement('div');\n scrim.className = 'slm-ch-scrim';\n scrim.innerHTML = `<div class=\"slm-ch-dialog\" role=\"dialog\" aria-modal=\"true\"\n aria-labelledby=\"slm-ch-dlg-title\" tabindex=\"-1\">${inner}</div>`;\n this.host.root.appendChild(scrim);\n this.scrimEl = scrim;\n const dialog = scrim.firstElementChild as HTMLElement;\n dialog.querySelectorAll<HTMLElement>('[data-ch-close]').forEach((button) => {\n button.addEventListener('click', () => this.closeDialog());\n });\n scrim.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') { event.stopPropagation(); this.closeDialog(); return; }\n if (event.key !== 'Tab') return;\n const focusable = [...dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]),select,input,textarea,a[href],[tabindex]:not([tabindex=\"-1\"])',\n )];\n if (!focusable.length) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }\n });\n wire(dialog);\n const autofocus = dialog.querySelector<HTMLElement>('input,select,button');\n (autofocus ?? dialog).focus();\n }\n\n private closeDialog(opts: { restoreFocus?: boolean } = {}): void {\n this.dialog = null;\n this.scrimEl?.remove();\n this.scrimEl = null;\n if (opts.restoreFocus !== false) this.lastFocus?.focus?.();\n this.lastFocus = null;\n }\n\n private renderCreateDialog(state: DialogState): void {\n // Markers are compared as the single letter each one RENDERS as, so a stored\n // \"star\" occupies 'S' and the next channel is offered a free letter instead.\n const taken = (this.list?.channels ?? []).map((channel) => markerLetter(channel.marker || channel.name, ''));\n const suggestion = suggestMarker('', taken);\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Create channel</h3>\n <p class=\"sub\">A named allocation only the right audience can buy from. You'll pick the seats next.</p>\n <div class=\"slm-field\">\n <label for=\"slm-ch-name\">Name</label>\n <input class=\"slm-input\" id=\"slm-ch-name\" maxlength=\"80\" />\n <p class=\"slm-note\">Shown to your team and in reports — never to buyers.</p>\n </div>\n <div class=\"slm-field\">\n <label>Marker</label>\n <div style=\"display:flex;gap:8px;align-items:center\">\n <span class=\"slm-ch-mk\" data-ch-marker style=\"background:${esc(suggestion.color)};width:28px;height:28px;font-size:13px\">${esc(suggestion.letter)}</span>\n <span class=\"slm-note\" style=\"margin:0\">Letter comes from the name; colour is chosen automatically from the next available palette. Buyers never see either.</span>\n </div>\n </div>\n <div class=\"slm-field\">\n <label for=\"slm-ch-ref\">Reference <span style=\"text-transform:none;font-weight:500\">(optional)</span></label>\n <input class=\"slm-input\" id=\"slm-ch-ref\" maxlength=\"120\" placeholder=\"e.g. travel-agency-a\" />\n <p class=\"slm-note\">A stable ID for your own system and webhooks.</p>\n </div>\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-create=\"plain\">Create without allocating</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-create=\"allocate\">Create and allocate seats</button>\n </div>`, (dialog) => {\n const name = dialog.querySelector<HTMLInputElement>('#slm-ch-name')!;\n const marker = dialog.querySelector<HTMLElement>('[data-ch-marker]')!;\n name.addEventListener('input', () => {\n const next = suggestMarker(name.value, taken);\n marker.textContent = next.letter;\n marker.style.background = next.color;\n });\n dialog.querySelectorAll<HTMLElement>('[data-ch-create]').forEach((button) => {\n button.addEventListener('click', () => {\n const allocate = button.dataset.chCreate === 'allocate';\n void this.createChannel(\n name.value,\n marker.textContent ?? '',\n marker.style.background,\n dialog.querySelector<HTMLInputElement>('#slm-ch-ref')?.value ?? '',\n allocate,\n );\n });\n });\n });\n }\n\n private async createChannel(\n name: string,\n letter: string,\n color: string,\n externalRef: string,\n allocate: boolean,\n ): Promise<void> {\n const trimmed = name.trim();\n if (!trimmed) {\n this.showDialogError('Give the channel a name your team will recognise.');\n return;\n }\n try {\n const res = await this.host.api.createChannel(this.host.eventKey, {\n name: trimmed,\n // The column is free text; we only ever store what the chip can draw.\n marker: markerLetter(letter, '') || null,\n color: color || null,\n externalRef: externalRef.trim() || null,\n });\n this.closeDialog();\n await this.refresh();\n this.targetChannelId = res.channel.id;\n this.detailChannelId = allocate ? null : res.channel.id;\n this.announce(`Channel ${trimmed} created with 0 seats allocated.`);\n this.host.toast(allocate\n ? `${trimmed} created. Select seats on the map to allocate them.`\n : `${trimmed} created.`, 'ok');\n this.paintRail();\n } catch (err) {\n const code = err instanceof ManageApiError ? err.code : undefined;\n this.showDialogError(code === 'channel_name_taken'\n ? 'That name is already used on this event. Pick another.'\n : \"Couldn't create the channel. Try again.\");\n this.host.onError(err);\n }\n }\n\n private showDialogError(message: string): void {\n const field = this.scrimEl?.querySelector<HTMLElement>('[data-ch-error]');\n if (!field) return;\n field.textContent = message;\n field.hidden = false;\n }\n\n private renderReviewDialog(state: DialogState): void {\n const { labels, buckets } = this.currentPlan();\n const authoritative = state.applied;\n const shown = authoritative ? authoritative.buckets : buckets;\n // An authoritative result names the channel the SERVER moved seats into.\n // Reading `targetChannelId` off the mode would relabel a completed result\n // if the organizer changed the destination picker before opening Details.\n const targetName = this.nameOf(authoritative?.targetChannelId ?? this.targetChannelId) ?? PUBLIC_CHANNEL_NAME;\n const rows = bucketRows(shown, targetName);\n const mutations = authoritative ? authoritative.applied : mutationCount(buckets);\n const allSkipped = !authoritative && labels.length > 0 && mutations === 0;\n const tooLarge = !authoritative && labels.length > MAX_ASSIGNMENT_UNITS;\n const rowsHtml = bucketRowsHtml(rows);\n\n const foot = authoritative\n ? `<div class=\"foot\"><button type=\"button\" class=\"slm-btn\" data-ch-close>Done</button></div>`\n : `<div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Back</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-apply ${allSkipped || tooLarge || state.busy ? 'disabled' : ''}>\n ${state.busy ? 'Applying…' : `Apply ${mutations.toLocaleString()} change${mutations === 1 ? '' : 's'}`}\n </button>\n </div>`;\n const confirmNote = !authoritative && needsMoveConfirmation(buckets)\n ? `<p class=\"slm-note\">Applying moves inventory out of another private channel. That is the line marked above.</p>`\n : '';\n const skippedNote = allSkipped\n ? `<div class=\"slm-ch-alert warn\"><span>ℹ</span><span>Nothing in this selection can move right now —\n every seat is in a buyer's checkout, already sold, or already in ${esc(targetName)}.</span></div>`\n : '';\n const limitNote = tooLarge\n ? `<div class=\"slm-ch-alert warn\" role=\"alert\"><span>ℹ</span><span><b>Choose fewer seats.</b>\n One Apply can cover at most ${MAX_ASSIGNMENT_UNITS.toLocaleString()} seats.</span></div>`\n : '';\n\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">${authoritative\n ? `Moved ${authoritative.applied.toLocaleString()} seat${authoritative.applied === 1 ? '' : 's'} to ${esc(targetName)}`\n : `Move ${labels.length.toLocaleString()} selected seat${labels.length === 1 ? '' : 's'} to ${esc(targetName)}`}</h3>\n <p class=\"sub\">${authoritative\n ? 'These are the exact counts the server applied.'\n : 'Every selected seat is in exactly one line below.'}</p>\n ${skippedNote}\n ${limitNote}\n ${rowsHtml || '<div class=\"slm-empty\">Nothing selected.</div>'}\n ${confirmNote}\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n ${foot}`, (dialog) => {\n dialog.querySelector('[data-ch-apply]')?.addEventListener('click', () => void this.apply());\n });\n if (authoritative) {\n this.announce(`Applied ${authoritative.applied} change${authoritative.applied === 1 ? '' : 's'} to ${targetName}.`);\n }\n }\n\n /**\n * Apply. On success the sheet CLOSES and the staged bar confirms what moved,\n * naming the destination and any skipped seats, with the AUTHORITATIVE server\n * buckets still one Details press away. Leaving the modal up on success made\n * the organizer dismiss a sheet to get back to a map they had just changed.\n * On a stale version the server mutated nothing: keep the selection, shake\n * the bar once, and offer exactly one action — Refresh and review.\n */\n private async apply(): Promise<void> {\n if (!this.dialog || !this.caps.manage) return;\n const { labels } = this.currentPlan();\n if (!labels.length) return;\n if (labels.length > MAX_ASSIGNMENT_UNITS) {\n this.showDialogError(`Choose at most ${MAX_ASSIGNMENT_UNITS.toLocaleString()} seats for one Apply.`);\n return;\n }\n this.dialog = { ...this.dialog, busy: true, error: null };\n this.renderDialog();\n try {\n const result = await this.host.api.applyChannelAssignment(this.host.eventKey, {\n // `null` is the wire spelling of \"back to public sale\" every worker\n // accepts, including ones that predate the 'public' sentinel.\n targetChannelId: isPublicChannelId(this.targetChannelId) ? null : this.targetChannelId,\n labels,\n assignmentVersion: this.assignmentVersion,\n });\n this.assignmentVersion = result.assignmentVersion;\n this.conflict = false;\n await this.refresh({ quiet: true });\n this.closeDialog({ restoreFocus: false });\n this.host.clearSelection();\n this.showApplied(result);\n } catch (err) {\n const conflict = err instanceof ManageApiError && err.status === 409\n && err.code === 'channel_assignment_conflict';\n if (conflict) {\n this.conflict = true;\n this.closeDialog();\n this.shakeStaged();\n this.paintRail();\n this.announce('Assignments changed while you were editing. Nothing was applied and your selection is kept.');\n return;\n }\n if (err instanceof ManageApiError && err.status === 403) {\n this.caps = { view: this.caps.view, manage: false };\n this.closeDialog();\n this.paintRail();\n this.host.toast('Changing channels needs channel-management permission.', 'err');\n return;\n }\n this.dialog = { kind: 'review', busy: false, error: \"Couldn't apply those changes. Try again.\" };\n this.renderDialog();\n this.host.onError(err);\n }\n }\n\n /**\n * The success receipt, now that the review sheet closes on Apply. It names the\n * destination and the seats that could not move, keeps the authoritative\n * buckets reachable through Details, and stays up long enough to be read —\n * 1.2s was tuned for a confirmation the organizer was already looking at.\n */\n private showApplied(result: AssignmentResult): void {\n const targetName = this.nameOf(result.targetChannelId) ?? PUBLIC_CHANNEL_NAME;\n const skipped = result.buckets.skippedHeld.count + result.buckets.skippedBooked.count\n + result.buckets.notFound.count;\n this.setStaged(`<span class=\"slm-ch-tick\" aria-hidden=\"true\">✓</span>\n <span>Assigned <b>${result.applied.toLocaleString()}</b> seat${result.applied === 1 ? '' : 's'} to ${esc(targetName)}\n ${skipped ? ` · ${skipped.toLocaleString()} skipped` : ''}</span>\n <span class=\"grow\"></span>\n <button type=\"button\" class=\"drop\" data-ch-applied-details>Details</button>`, 'done');\n this.stagedEl?.querySelector<HTMLElement>('[data-ch-applied-details]')?.addEventListener('click', () => {\n this.openDialog({ kind: 'review', applied: result });\n });\n this.announce(`Assigned ${result.applied} seat${result.applied === 1 ? '' : 's'} to ${targetName}${skipped ? `; ${skipped} skipped` : ''}.`);\n if (this.stagedDoneTimer) clearTimeout(this.stagedDoneTimer);\n this.stagedDoneTimer = setTimeout(() => this.setStaged(null), 5_000);\n }\n\n private shakeStaged(): void {\n const bar = this.stagedEl;\n if (!bar || !bar.classList.contains('on')) return;\n bar.classList.remove('shake');\n void bar.offsetWidth; // restart the animation\n bar.classList.add('shake');\n }\n\n /**\n * The ⋯ menu.\n *\n * Opening a channel is the ROW's job now, so ⋯ carries what is left: the\n * secondary and destructive lifecycle actions. It is rendered through the same\n * scrim primitive as every other sheet, which is what gives it a focus trap,\n * Escape, and a name — a bare absolutely-positioned popup would have had none\n * of those. Archive keeps its own confirmation dialog; this menu never\n * destroys anything by itself.\n */\n private renderMenuDialog(state: DialogState): void {\n const channel = this.list?.channels.find((item) => item.id === state.channelId);\n if (!channel || !this.caps.manage) { this.closeDialog(); return; }\n const paused = channel.state === 'paused';\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">${esc(channel.name)}</h3>\n <p class=\"sub\">Open the channel to allocate seats and hand out buyer access.\n These are the rest of its actions.</p>\n <div class=\"slm-ch-menu\">\n <button type=\"button\" class=\"slm-btn\" data-ch-menu-act=\"open\">Open channel</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-menu-act=\"rename\">Rename</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-menu-act=\"pause\">${paused ? 'Resume selling' : 'Pause selling'}</button>\n <button type=\"button\" class=\"slm-btn ghost\" data-ch-menu-act=\"archive\">Archive…</button>\n </div>\n <p class=\"slm-note\">Pausing stops new buyer access; checkouts already running can finish.\n Archiving closes the channel for good and returns its free seats to a destination you choose.\n Nothing is ever deleted silently.</p>\n <div class=\"foot\"><button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button></div>`, (dialog) => {\n dialog.querySelectorAll<HTMLElement>('[data-ch-menu-act]').forEach((button) => {\n button.addEventListener('click', () => {\n const act = button.dataset.chMenuAct;\n if (act === 'open') { this.closeDialog(); this.openChannel(channel.id); return; }\n if (act === 'rename') { this.openDialog({ kind: 'rename', channelId: channel.id }); return; }\n if (act === 'archive') { this.openDialog({ kind: 'archive', channelId: channel.id }); return; }\n this.closeDialog();\n void this.togglePause(channel.id);\n });\n });\n });\n }\n\n private renderRenameDialog(state: DialogState): void {\n const channel = this.list?.channels.find((item) => item.id === state.channelId);\n if (!channel) { this.closeDialog(); return; }\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Rename ${esc(channel.name)}</h3>\n <p class=\"sub\">Only your team and your reports see this name.</p>\n <div class=\"slm-field\">\n <label for=\"slm-ch-newname\">Name</label>\n <input class=\"slm-input\" id=\"slm-ch-newname\" maxlength=\"80\" value=\"${esc(channel.name)}\" />\n </div>\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-rename>Save name</button>\n </div>`, (dialog) => {\n dialog.querySelector('[data-ch-rename]')?.addEventListener('click', () => {\n const value = dialog.querySelector<HTMLInputElement>('#slm-ch-newname')?.value ?? '';\n if (!value.trim()) { this.showDialogError('A channel needs a name.'); return; }\n void this.host.api.renameChannel(this.host.eventKey, channel.id, value.trim())\n .then(() => { this.closeDialog(); return this.refresh(); })\n .catch((err) => {\n this.showDialogError(err instanceof ManageApiError && err.code === 'channel_name_taken'\n ? 'That name is already used on this event.'\n : \"Couldn't rename the channel.\");\n this.host.onError(err);\n });\n });\n });\n }\n\n /**\n * \"Use a website or app\" — declare the channel's route as `server`.\n *\n * This is no longer a flag the Embed page happens to read: since 2026-08-06 it\n * is what AUTHORIZES `POST /v1/events/:key/buyer-access-sessions` to mint for\n * this channel at all. Without it, an integration that is otherwise perfectly\n * wired up gets a 409 on every buyer.\n */\n private async chooseWebsiteIntegration(): Promise<void> {\n const channelId = this.detailChannelId;\n if (!channelId) return;\n await this.setAccessIntent('server');\n }\n\n /**\n * Declare this channel's sale route.\n *\n * Reports through the toast lane the rest of the rail's direct actions use.\n * The two enforcement refusals get real answers rather than a generic failure:\n * `channel_intent_switch_blocked` opens the review sheet (there is a decision\n * to make, and a sheet is where decisions live), and\n * `channel_access_intent_forbids` — which the organizer can hit by racing\n * their own second tab — says which route is in the way.\n */\n private async setAccessIntent(\n accessIntent: ChannelAccessIntent,\n opts: { acknowledgeLiveAccess?: boolean } = {},\n ): Promise<boolean> {\n const channelId = this.detailChannelId;\n if (!channelId || !this.caps.manage) return false;\n try {\n // `intentSwitch` is present only when the switch actually disturbed\n // something, and the whole response is read defensively because the client\n // is host-supplied — a thin proxy that resolves void must not crash the rail.\n const result = await this.host.api.setChannelAccessIntent(\n this.host.eventKey, channelId, accessIntent, opts,\n ) as { intentSwitch?: { closedLinks: number; keptSessions: number } } | undefined;\n await this.refresh();\n this.host.toast(this.intentSavedCopy(accessIntent, result?.intentSwitch), 'ok');\n return true;\n } catch (err) {\n if (err instanceof ManageApiError && err.code === 'channel_intent_switch_blocked') {\n this.openDialog({\n kind: 'intentSwitch',\n channelId,\n intentTo: accessIntent,\n switchBlocked: err.details as IntentSwitchBlockedDetails,\n });\n return false;\n }\n if (err instanceof ManageApiError && err.code === 'channel_access_intent_forbids') {\n this.host.toast(intentForbidsCopy(err.details as AccessIntentForbidsDetails), 'err');\n return false;\n }\n this.host.toast(\"Couldn't change how this channel reaches buyers.\", 'err');\n this.host.onError(err);\n return false;\n }\n }\n\n /** What just happened, including anything the switch took down with it — the\n * server reports `intentSwitch` only when it actually disturbed something. */\n private intentSavedCopy(\n intent: ChannelAccessIntent,\n disturbed: { closedLinks: number; keptSessions: number } | undefined,\n ): string {\n const head = intent === 'server'\n ? 'Set to your website or app. The embed code is on the Embed page.'\n : intent === 'internal'\n ? 'Only your own staff can sell this channel now.'\n : intent === 'hosted_link'\n ? 'Set to buyer links. Create one to let buyers in.'\n : 'Kept as a protected reserve. No route can sell these seats.';\n if (!disturbed) return head;\n const closed = disturbed.closedLinks\n ? ` ${disturbed.closedLinks.toLocaleString()} buyer link${disturbed.closedLinks === 1 ? '' : 's'} closed.` : '';\n const kept = disturbed.keptSessions\n ? ` ${disturbed.keptSessions.toLocaleString()} buyer${disturbed.keptSessions === 1 ? '' : 's'} already in a checkout can still finish.` : '';\n return `${head}${closed}${kept}`;\n }\n\n /** `channelId` is explicit because this is reachable from the ⋯ menu on a row\n * that is NOT the open channel, as well as from the detail panel itself. */\n private async togglePause(channelId = this.detailChannelId): Promise<void> {\n const channel = this.list?.channels.find((item) => item.id === channelId);\n if (!channel || !this.caps.manage) return;\n const paused = channel.state !== 'paused';\n try {\n await this.host.api.setChannelPaused(this.host.eventKey, channel.id, paused);\n await this.refresh();\n this.host.toast(paused\n ? `${channel.name} paused. Existing checkouts can finish; no new buyer access is issued.`\n : `${channel.name} resumed.`, 'ok');\n } catch (err) {\n this.host.toast(\"Couldn't change that channel.\", 'err');\n this.host.onError(err);\n }\n }\n\n private renderArchiveDialog(state: DialogState): void {\n const channel = this.list?.channels.find((item) => item.id === state.channelId);\n if (!channel) { this.closeDialog(); return; }\n // The server is the authority on whether archive is possible. The rail's\n // poll can be seconds stale, so a local hold count is a WARNING; only the\n // server's 409 (which carries the exact retry window) disables the action.\n const blocked = state.archiveBlocked ?? null;\n const heads_up = !blocked && channel.counts.held > 0;\n const destinations = this.assignableChannels().filter((entry) => entry.id !== channel.id);\n const blockedAlert = blocked\n ? `<div class=\"slm-ch-alert warn\" role=\"alert\"><span>⏳</span>\n <span><b>${(blocked.heldUnits ?? blocked.activeHolds ?? 0).toLocaleString()} seats are in a buyer's checkout right now.</b>\n Archive is unavailable while seats are held — try again ${esc(retryAfterCopy(blocked))}.</span></div>`\n : heads_up\n ? `<div class=\"slm-ch-alert warn\"><span>⏳</span>\n <span>${channel.counts.held.toLocaleString()} seats are in a buyer's checkout right now.\n Archive is refused while any seat is held — you can try, and we'll tell you when to come back.</span></div>`\n : '';\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Archive ${esc(channel.name)}</h3>\n <p class=\"sub\">The channel closes for good. Its seats move to a destination you choose;\n sales history keeps its attribution.</p>\n ${blockedAlert}\n <div class=\"slm-field\">\n <label for=\"slm-ch-dest\">Move the ${channel.counts.free.toLocaleString()} remaining free seats to</label>\n <select class=\"slm-select\" id=\"slm-ch-dest\">\n ${destinations.map((entry) => `<option value=\"${esc(entry.id)}\">${esc(entry.name)}</option>`).join('')}\n </select>\n </div>\n <p class=\"slm-note\">${channel.counts.booked.toLocaleString()} sold seats keep \"${esc(channel.name)}\" on their sale\n record. If one is cancelled later it returns to the destination above. Any buyer access for this channel\n stops working.</p>\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn danger\" data-ch-archive ${blocked ? 'disabled' : ''}>Archive channel</button>\n </div>`, (dialog) => {\n dialog.querySelector('[data-ch-archive]')?.addEventListener('click', () => {\n const destination = dialog.querySelector<HTMLSelectElement>('#slm-ch-dest')?.value ?? '';\n void this.archive(channel.id, destination || null);\n });\n });\n }\n\n private async archive(channelId: string, destination: string | null): Promise<void> {\n try {\n await this.host.api.archiveChannel(this.host.eventKey, channelId, destination);\n this.closeDialog();\n this.detailChannelId = null;\n await this.refresh();\n this.host.toast('Channel archived. Its remaining seats moved to the destination you chose.', 'ok');\n } catch (err) {\n if (err instanceof ManageApiError && err.status === 409\n && err.code === 'channel_archive_blocked_by_holds') {\n this.dialog = {\n kind: 'archive',\n channelId,\n archiveBlocked: (err.details ?? {}) as ArchiveBlockedDetails,\n };\n this.renderDialog();\n return;\n }\n this.showDialogError(\"Couldn't archive that channel. Try again.\");\n this.host.onError(err);\n }\n }\n\n /**\n * The synchronized inventory list (§13): the keyboard and screen-reader\n * equivalent of canvas click / marquee / brush, grouped by section with\n * per-section select actions.\n */\n private renderSeatListDialog(): void {\n const selected = new Set(this.host.selectionLabels());\n const groups = new Map<string, { label: string; seats: Array<{ label: string; status: string }> }>();\n let total = 0;\n for (const seat of this.host.seats()) {\n total += 1;\n if (total > this.seatListLimit) break;\n const section = this.host.sectionOfLabel(seat.label);\n const key = section?.id ?? '';\n const group = groups.get(key) ?? { label: section?.label ?? 'Other seats', seats: [] };\n group.seats.push({ label: seat.label, status: this.host.statusOf(seat.label) ?? 'free' });\n groups.set(key, group);\n }\n const body = [...groups.entries()].map(([id, group]) => `\n <div class=\"slm-ch-seatgroup\">\n <span>${esc(group.label)}</span>\n ${id ? `<button type=\"button\" data-ch-section=\"${esc(id)}\">Select section</button>` : ''}\n </div>\n ${group.seats.map((seat) => {\n const channelId = this.allocation.get(seat.label) ?? PUBLIC_CHANNEL_ID;\n const channelName = this.nameOf(channelId) ?? PUBLIC_CHANNEL_NAME;\n return `<button type=\"button\" class=\"slm-ch-seatitem\" role=\"checkbox\"\n aria-checked=\"${selected.has(seat.label)}\" data-ch-seat=\"${esc(seat.label)}\">\n <span class=\"box\" aria-hidden=\"true\">✓</span>\n <span>${esc(seat.label)}</span>\n <span class=\"meta\">${esc(channelName)} · ${esc(seat.status)}</span>\n </button>`;\n }).join('')}`).join('');\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Seat list</h3>\n <p class=\"sub\">The same selection as the map, with checkboxes. Space or Enter toggles a seat.</p>\n <div class=\"slm-ch-seatlist\">${body || '<div class=\"slm-empty\">No seats on this chart.</div>'}</div>\n ${total > this.seatListLimit\n ? `<div class=\"foot\"><button type=\"button\" class=\"slm-btn ghost\" data-ch-more>Show more seats</button></div>` : ''}\n <div class=\"foot\"><button type=\"button\" class=\"slm-btn\" data-ch-close>Done</button></div>`, (dialog) => {\n dialog.querySelectorAll<HTMLElement>('[data-ch-seat]').forEach((button) => {\n button.addEventListener('click', () => {\n const label = button.dataset.chSeat!;\n const next = new Set(this.host.selectionLabels());\n if (next.has(label)) next.delete(label);\n else next.add(label);\n this.host.clearSelection();\n if (next.size) this.host.selectByLabels([...next]);\n this.renderSeatListDialog();\n });\n });\n dialog.querySelectorAll<HTMLElement>('[data-ch-section]').forEach((button) => {\n button.addEventListener('click', () => {\n this.host.selectSection(button.dataset.chSection!);\n this.renderSeatListDialog();\n });\n });\n dialog.querySelector('[data-ch-more]')?.addEventListener('click', () => {\n this.seatListLimit += SEAT_LIST_PAGE;\n this.renderSeatListDialog();\n });\n });\n }\n\n // ---- buyer-link dialogs ---------------------------------------------------\n\n private async reloadLinks(): Promise<void> {\n const channelId = this.detailChannelId;\n if (!channelId) return;\n this.linksState = this.links.length ? this.linksState : 'loading';\n await this.loadLinks(channelId);\n this.paintRail();\n }\n\n /**\n * The reload EVERY link mutation owes the panel.\n *\n * A create/rotate/revoke changes two things the detail panel renders: the\n * channel's access line (the server sets `access.intent` on create, and clears\n * it when the last live link goes) and the link status list. Both are re-read\n * here and the rail repainted, so the panel the organizer is already looking\n * at is current the moment the mutation lands — no reload, and no dependence\n * on HOW the one-time reveal was dismissed (the button, Escape, or never).\n */\n private async reloadAfterLinkChange(channelId: string): Promise<void> {\n // `refresh` re-reads the links of the OPEN channel as part of its pass, so\n // the common case is one round of reads, not two.\n if (this.detailChannelId === channelId) {\n await this.refresh({ quiet: true });\n return;\n }\n await this.loadLinks(channelId);\n if (this.active) this.paintRail();\n }\n\n private linkById(linkId: string | undefined): AccessLinkStatusRecord | null {\n return this.links.find((link) => link.id === linkId) ?? null;\n }\n\n /**\n * Create. The three policy fields carry the owner's defaults and every one of\n * them is editable; the PLATFORM bounds (60s–180d, 1–10 000, 1–100, 20 live\n * links) are the server's to enforce and the server's to explain, so this form\n * checks only that a number is a number and surfaces the server's sentence for\n * everything else.\n */\n private renderLinkCreateDialog(state: DialogState): void {\n const channel = this.list?.channels.find((item) => item.id === state.channelId);\n if (!channel || !this.caps.manage) { this.closeDialog(); return; }\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Create a buyer link for ${esc(channel.name)}</h3>\n <p class=\"sub\">Anyone who opens the link can buy from this channel's allocation — and only from it.\n You'll see the link once, right after you create it.</p>\n <div class=\"slm-field\">\n <label for=\"slm-ch-lk-label\">Label <span style=\"text-transform:none;font-weight:500\">(optional)</span></label>\n <input class=\"slm-input\" id=\"slm-ch-lk-label\" maxlength=\"80\" placeholder=\"e.g. VIP list Nov 14\" />\n <p class=\"slm-note\">So you can tell your links apart later. Buyers never see it.</p>\n </div>\n <div class=\"slm-field\">\n <label for=\"slm-ch-lk-expiry\">Stops working</label>\n <select class=\"slm-select\" id=\"slm-ch-lk-expiry\" data-ch-lk-expiry>\n <option value=\"event\" selected>When the event starts</option>\n <option value=\"custom\">On a date I choose</option>\n </select>\n </div>\n <div class=\"slm-field\" data-ch-lk-when-field hidden>\n <label for=\"slm-ch-lk-when\">Date and time</label>\n <input class=\"slm-input\" type=\"datetime-local\" id=\"slm-ch-lk-when\" />\n </div>\n <div class=\"slm-field\">\n <label for=\"slm-ch-lk-redemptions\">How many people can use it</label>\n <input class=\"slm-input\" type=\"number\" id=\"slm-ch-lk-redemptions\" inputmode=\"numeric\"\n value=\"${ACCESS_LINK_DEFAULTS.maxRedemptions}\" />\n <p class=\"slm-note\">Each buyer who opens the link uses one.</p>\n </div>\n <div class=\"slm-field\">\n <label for=\"slm-ch-lk-quantity\">Seats per buyer</label>\n <input class=\"slm-input\" type=\"number\" id=\"slm-ch-lk-quantity\" inputmode=\"numeric\"\n value=\"${ACCESS_LINK_DEFAULTS.maxQuantity}\" />\n </div>\n <label class=\"slm-note\" style=\"display:flex;gap:8px;align-items:center;margin:2px 0 6px\">\n <input type=\"checkbox\" id=\"slm-ch-lk-public\" />\n Also let this link buy Public sale seats\n </label>\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-lk-create>Create link</button>\n </div>`, (dialog) => {\n const expiry = dialog.querySelector<HTMLSelectElement>('[data-ch-lk-expiry]')!;\n const whenField = dialog.querySelector<HTMLElement>('[data-ch-lk-when-field]')!;\n const when = dialog.querySelector<HTMLInputElement>('#slm-ch-lk-when')!;\n expiry.addEventListener('change', () => {\n const custom = expiry.value === 'custom';\n whenField.hidden = !custom;\n if (custom && !when.value) when.value = datetimeLocalValue(Date.now() + 7 * 86_400_000);\n });\n dialog.querySelector('[data-ch-lk-create]')?.addEventListener('click', () => {\n const maxRedemptions = intField(dialog, '#slm-ch-lk-redemptions');\n const maxQuantity = intField(dialog, '#slm-ch-lk-quantity');\n if (maxRedemptions == null || maxQuantity == null) {\n this.showDialogError('Those two settings need to be whole numbers.');\n return;\n }\n let expiresAt: number | undefined;\n if (expiry.value === 'custom') {\n expiresAt = Date.parse(when.value);\n if (!Number.isFinite(expiresAt)) {\n this.showDialogError('Pick the date and time the link should stop working.');\n return;\n }\n }\n void this.createLink(channel.id, {\n label: dialog.querySelector<HTMLInputElement>('#slm-ch-lk-label')?.value.trim() || null,\n includePublic: dialog.querySelector<HTMLInputElement>('#slm-ch-lk-public')?.checked ?? false,\n ...(expiresAt === undefined ? {} : { expiresAt }),\n maxRedemptions,\n maxQuantity,\n });\n });\n });\n }\n\n /**\n * DECLARE, then create.\n *\n * `createAccessLink` used to set the channel's route to `hosted_link` as a\n * side effect, which is exactly why the picker could never refuse anything.\n * The server took that side effect away and now REQUIRES the declaration —\n * and channels default to `none`, so a create that did not declare first\n * would 409 on the organizer's very first \"Create buyer link\".\n *\n * So the route is declared here, immediately before the create. It stays ONE\n * gesture: nothing is declared while the organizer is still filling the form\n * in (cancelling changes nothing), and if the declaration is the part that is\n * refused, the review sheet holds this form and finishes the job on the far\n * side of the acknowledgement.\n */\n private async createLink(channelId: string, input: PendingLinkInput): Promise<void> {\n if (!(await this.ensureHostedLinkRoute(channelId, input))) return;\n await this.mintLink(channelId, input);\n }\n\n /**\n * The create half, on its own.\n *\n * Separate from `createLink` because the acknowledge path has ALREADY declared\n * the route — with the very acknowledgement the plain declaration was refused\n * for. Sending it back through `ensureHostedLinkRoute` would re-derive the\n * route from a channel list that has not necessarily caught up, and could\n * refuse the organizer a second time for a decision they just made.\n */\n private async mintLink(channelId: string, input: PendingLinkInput): Promise<void> {\n try {\n const reveal = await this.host.api.createAccessLink(this.host.eventKey, channelId, input);\n this.revealLink(reveal, { channelId });\n await this.reloadAfterLinkChange(channelId);\n } catch (err) {\n this.showDialogError(accessLinkErrorCopy(err instanceof ManageApiError ? err : undefined));\n if (!(err instanceof ManageApiError)) this.host.onError(err);\n }\n }\n\n /**\n * Make sure the channel declares the buyer-link route before a link is minted.\n *\n * Returns false when the create must NOT proceed — either it was refused, or\n * the decision has been handed to the switch-review sheet, which resumes it.\n * A channel already on `hosted_link` costs no request at all, so creating a\n * second link is the same single call it has always been.\n */\n private async ensureHostedLinkRoute(channelId: string, pendingLink: PendingLinkInput): Promise<boolean> {\n const channel = this.list?.channels.find((item) => item.id === channelId);\n if ((channel?.access?.intent ?? 'none') === 'hosted_link') return true;\n try {\n await this.host.api.setChannelAccessIntent(this.host.eventKey, channelId, 'hosted_link');\n await this.refresh();\n return true;\n } catch (err) {\n if (err instanceof ManageApiError && err.code === 'channel_intent_switch_blocked') {\n this.openDialog({\n kind: 'intentSwitch',\n channelId,\n intentTo: 'hosted_link',\n switchBlocked: err.details as IntentSwitchBlockedDetails,\n pendingLink,\n });\n return false;\n }\n this.showDialogError(err instanceof ManageApiError && err.code === 'channel_access_intent_forbids'\n ? intentForbidsCopy(err.details as AccessIntentForbidsDetails)\n : \"Couldn't set this channel up for buyer links. Try again.\");\n if (!(err instanceof ManageApiError)) this.host.onError(err);\n return false;\n }\n }\n\n /**\n * The ONE-TIME reveal.\n *\n * Three things make this unrecoverable rather than merely \"not shown twice\":\n *\n * 1. `url` is a local const. It is never assigned to a field on this class,\n * never handed to the host, never put in a `DialogState`.\n * 2. `this.dialog` is cleared FIRST, so `renderDialog()` — the only function\n * that rebuilds a sheet — has nothing to rebuild this one from.\n * 3. The string exists in exactly one DOM node inside the scrim. Dismissing\n * the dialog removes the scrim, and the closure goes with it.\n *\n * The server holds only a hash, so even a compromised client cannot ask for it\n * again. Rotation is the recovery path, and the copy says so.\n */\n private revealLink(reveal: AccessLinkReveal, opts: { channelId: string; rotated?: boolean }): void {\n const url = reveal.url;\n this.dialog = null;\n const rotated = opts.rotated\n ? `<div class=\"slm-ch-alert warn\" role=\"status\"><span>⚠</span><span>\n <b>The old link has stopped working.</b> ${reveal.endedSessions\n ? `${reveal.endedSessions.toLocaleString()} buyer${reveal.endedSessions === 1 ? '' : 's'} lost access immediately.`\n : 'Buyers who already came in can finish; every new visit needs this link.'}</span></div>`\n : '';\n const policy = accessLinkPolicyLines(reveal.link)\n .map((row) => `<div class=\"slm-ch-lkrow\"><span class=\"k\">${esc(row.k)}</span>\n <span class=\"v\">${esc(row.v)}</span></div>`).join('');\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Copy this link now</h3>\n <p class=\"sub\">This is the only time SeatLayer can show it. We keep just a fingerprint, so it cannot be\n shown again — if it is lost, rotate the link for a fresh one.</p>\n ${rotated}\n <div class=\"slm-ch-secret\" data-ch-lk-url>${esc(url)}</div>\n <div class=\"slm-ch-row2\" style=\"margin-top:8px\">\n <button type=\"button\" class=\"slm-btn\" data-ch-lk-copy>Copy link</button>\n </div>\n <div class=\"slm-ch-alert warn\" style=\"margin-top:12px\"><span>⚠</span>\n <span>Anyone who opens this link can buy from this allocation. Send it only to the people it is meant\n for — forwarding it hands on the same access, and SeatLayer cannot tell the difference.</span></div>\n <p class=\"slm-eyebrow\" style=\"margin-top:14px\">What this link allows</p>\n ${policy}\n <div class=\"foot\">\n <button type=\"button\" class=\"slm-btn\" data-ch-close data-ch-lk-done>I've copied it</button>\n </div>`, (dialog) => {\n const copy = dialog.querySelector<HTMLElement>('[data-ch-lk-copy]');\n copy?.addEventListener('click', () => {\n const ok = (): void => {\n copy.textContent = 'Copied';\n this.announce('Buyer link copied.');\n };\n const clipboard = typeof navigator === 'undefined' ? null : navigator.clipboard;\n if (clipboard?.writeText) {\n clipboard.writeText(url).then(ok, () => selectSecret(dialog));\n return;\n }\n // No clipboard API (older embeds, insecure context): select the text so\n // the organizer can copy it by hand rather than lose it entirely.\n selectSecret(dialog);\n });\n // Dismissal only dismisses. The mutation that opened this sheet already\n // owns the reload (`reloadAfterLinkChange`), so the panel behind the scrim\n // is current whichever way the organizer leaves — including Escape.\n });\n this.announce('Your buyer link is ready and is shown once.');\n }\n\n /**\n * Rotate. The organizer must SAY what happens to the buyers already inside —\n * the confirm stays disabled until one of the two choices is picked, because\n * the gentle branch and the destructive branch are both real decisions and the\n * server refuses (422 `end_active_sessions_required`) to guess either.\n */\n private renderLinkRotateDialog(state: DialogState): void {\n const link = this.linkById(state.linkId);\n if (!link || !this.caps.manage) { this.closeDialog(); return; }\n const sessions = link.activeSessions ?? 0;\n const warning = sessions\n ? `<div class=\"slm-ch-alert warn\"><span>⚠</span>\n <span><b>${sessions.toLocaleString()} buyer${sessions === 1 ? '' : 's'}</b> got in with the current link\n and still ${sessions === 1 ? 'has' : 'have'} active access.</span></div>`\n : '';\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Rotate the ${esc(link.label || 'buyer')} link?</h3>\n <p class=\"sub\">The current link stops opening immediately and cannot be restored. You will get a new\n link to copy — shown once.</p>\n ${warning}\n <label class=\"slm-ch-radio\">\n <input type=\"radio\" name=\"slm-ch-rot\" value=\"keep\" data-ch-rot />\n <span><b>Let them finish</b><span class=\"why\">Access already handed out expires on its own; seats in\n checkout are untouched. Every new visit needs the new link.</span></span>\n </label>\n <label class=\"slm-ch-radio\">\n <input type=\"radio\" name=\"slm-ch-rot\" value=\"end\" data-ch-rot />\n <span><b>End their access now</b><span class=\"why\">All access from the old link ends immediately.\n Buyers part-way through choosing seats lose access.</span></span>\n </label>\n <p class=\"slm-note\">Choose one — SeatLayer will not decide this for you.</p>\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn\" data-ch-lk-rotate disabled>Rotate and copy new link</button>\n </div>`, (dialog) => {\n const confirm = dialog.querySelector<HTMLButtonElement>('[data-ch-lk-rotate]')!;\n dialog.querySelectorAll<HTMLInputElement>('[data-ch-rot]').forEach((radio) => {\n radio.addEventListener('change', () => { confirm.disabled = false; });\n });\n confirm.addEventListener('click', () => {\n const picked = [...dialog.querySelectorAll<HTMLInputElement>('[data-ch-rot]')]\n .find((radio) => radio.checked);\n // Belt and braces: the button is disabled until a choice exists, and a\n // programmatic path still cannot skip the decision.\n if (!picked) {\n this.showDialogError(accessLinkErrorCopy({ code: 'end_active_sessions_required' }));\n return;\n }\n void this.rotateLink(state.channelId!, link.id, picked.value === 'end');\n });\n });\n }\n\n private async rotateLink(channelId: string, linkId: string, endActiveSessions: boolean): Promise<void> {\n try {\n const reveal = await this.host.api.rotateAccessLink(\n this.host.eventKey, channelId, linkId, endActiveSessions,\n );\n this.revealLink(reveal, { channelId, rotated: true });\n await this.reloadAfterLinkChange(channelId);\n } catch (err) {\n this.showDialogError(accessLinkErrorCopy(err instanceof ManageApiError ? err : undefined));\n if (!(err instanceof ManageApiError)) this.host.onError(err);\n }\n }\n\n private renderLinkRevokeDialog(state: DialogState): void {\n const link = this.linkById(state.linkId);\n if (!link || !this.caps.manage) { this.closeDialog(); return; }\n const sessions = link.activeSessions ?? 0;\n this.renderScrim(`\n <h3 id=\"slm-ch-dlg-title\">Revoke the ${esc(link.label || 'buyer')} link?</h3>\n <p class=\"sub\">It stops opening immediately and cannot be restored — there is no undo, and no way to\n bring the same URL back. Seats already bought through it keep their sale.</p>\n ${sessions ? `<label class=\"slm-ch-radio\">\n <input type=\"checkbox\" data-ch-lk-endsessions />\n <span><b>Also end access for the ${sessions.toLocaleString()}\n buyer${sessions === 1 ? '' : 's'} already inside</b><span class=\"why\">Leave this off and they can\n finish what they started; new visits are refused either way.</span></span>\n </label>` : ''}\n <p class=\"slm-ch-err\" data-ch-error ${state.error ? '' : 'hidden'}>${esc(state.error ?? '')}</p>\n <div class=\"foot\">\n <button type=\"button\" class=\"quiet\" data-ch-close>Cancel</button>\n <button type=\"button\" class=\"slm-btn danger\" data-ch-lk-revoke>Revoke link</button>\n </div>`, (dialog) => {\n dialog.querySelector('[data-ch-lk-revoke]')?.addEventListener('click', () => {\n const end = dialog.querySelector<HTMLInputElement>('[data-ch-lk-endsessions]')?.checked ?? false;\n void this.revokeLink(state.channelId!, link.id, end);\n });\n });\n }\n\n private async revokeLink(channelId: string, linkId: string, endActiveSessions: boolean): Promise<void> {\n try {\n const res = await this.host.api.revokeAccessLink(\n this.host.eventKey, channelId, linkId, endActiveSessions,\n );\n this.closeDialog();\n await this.reloadAfterLinkChange(channelId);\n this.host.toast(res.endedSessions\n ? `Link revoked. ${res.endedSessions.toLocaleString()} buyer${res.endedSessions === 1 ? '' : 's'} lost access.`\n : 'Link revoked. It no longer opens for anyone.', 'ok');\n } catch (err) {\n this.showDialogError(accessLinkErrorCopy(err instanceof ManageApiError ? err : undefined));\n if (!(err instanceof ManageApiError)) this.host.onError(err);\n }\n }\n\n // ---- compact detents ------------------------------------------------------\n\n private applySheetClasses(): void {\n const root = this.host.root;\n const compact = this.host.isCompact();\n root.classList.toggle('ch-sheet', compact && this.active);\n for (const detent of ['collapsed', 'medium', 'full'] as Detent[]) {\n root.classList.toggle(`detent-${detent}`, compact && this.active && this.detent === detent);\n }\n // At the full detent the map behind the sheet is inert: selection is\n // preserved, but the background cannot be touched until Back/Close.\n this.host.setMapInert(compact && this.active && this.detent === 'full');\n }\n\n private cycleDetent(): void {\n const order: Detent[] = ['collapsed', 'medium', 'full'];\n this.detent = order[(order.indexOf(this.detent) + 1) % order.length];\n this.applySheetClasses();\n }\n\n /** Back/Close from the full detent returns to the previous one and keeps the\n * selection — losing a hard-won selection to a Back press is unforgivable. */\n handleBack(): boolean {\n if (this.scrimEl) { this.closeDialog(); return true; }\n if (this.host.isCompact() && this.detent === 'full') {\n this.detent = 'medium';\n this.applySheetClasses();\n return true;\n }\n return false;\n }\n}\n","/**\n * `@seatlayer/js/manager` — the organizer cockpit, and nothing else.\n *\n * WHY THIS ENTRY EXISTS\n *\n * The main barrel (`@seatlayer/js`) is buyer-only at runtime. Organizer values\n * live here so importing `SeatPicker` never statically reaches SeatManager,\n * ChannelsMode, channel planning helpers, or ManageApi.\n *\n * Bundlers cannot fix that from the outside. The published `dist/index.js` is\n * one file, and the classes in it are not provably side-effect-free at the\n * granularity a tree-shaker needs, so the buyer half survives even an import\n * that names one symbol.\n *\n * So the split is made HERE, where the module graph is still real: a separate\n * tsup entry whose graph reaches the cockpit and the engine it renders with,\n * and stops. `SeatManager` is imported from its own module rather than through\n * the barrel — going through the barrel would re-admit everything this entry\n * exists to exclude.\n *\n * The main barrel retains organizer TYPES for source compatibility; JavaScript\n * values must be imported from this subpath.\n */\nexport { SeatManager } from './SeatManager';\nexport type {\n SeatManagerOptions,\n SeatManagerMode,\n EventScopedManageToken,\n SeatManagerCapability,\n SeatManagerTallies,\n SeatManagerActivity,\n SeatManagerActionResult,\n SeatManagerConnection,\n} from './SeatManager';\n// Sales channels — the cockpit mode plus pure planning helpers used by review\n// UIs. Keeping every organizer value on this entry is the buyer-graph boundary.\nexport { ChannelsMode, bucketRowsHtml } from './channelsMode';\nexport type {\n ChannelsCapabilities, ChannelsClient, ChannelsModeHost, ChannelsRowView,\n ChannelsSeatView,\n} from './channelsMode';\nexport {\n ACCESS_LINK_DEFAULTS,\n PUBLIC_CHANNEL_ID,\n PUBLIC_CHANNEL_NAME,\n accessIntentDescription,\n accessIntentLabel,\n accessLine,\n accessLinkBadge,\n accessLinkErrorCopy,\n accessLinkIsLive,\n accessLinkPolicyLines,\n bucketRows,\n dropReviewRows,\n intentForbidsCopy,\n intentSwitchBlockedCopy,\n isPublicChannelId,\n markerLetter,\n markerOf,\n mutationCount,\n needsMoveConfirmation,\n planAssignment,\n retryAfterCopy,\n selectionSources,\n stateBadge,\n suggestMarker,\n} from './channelPlan';\nexport type {\n AccessIntentForbidsDetails,\n AccessLinkRecord,\n AccessLinkReveal,\n AccessLinkState,\n AccessLinkStatus,\n AccessLinkStatusRecord,\n ArchiveBlockedDetails,\n AssignmentBuckets,\n AssignmentDropDetails,\n AssignmentResult,\n BucketRow,\n ChannelAccessIntent,\n ChannelAccessSummary,\n ChannelCounts,\n ChannelListResult,\n ChannelRecord,\n ChannelSeatStatus,\n ChannelState,\n IntentSwitchBlockedDetails,\n SelectionSourceRow,\n} from './channelPlan';\nexport { ManageApi, ManageApiError } from './manageApi';\nexport type {\n ChannelAllocationPage,\n ChannelAuditEntry,\n ChannelAuditPage,\n ChannelPreviewProjection,\n ChannelAttribution,\n ChannelReportRow,\n ChannelReport,\n ChannelReportResult,\n ChannelReportLinkRecord,\n ChannelReportLinkReveal,\n ReportByStatus,\n ReportCategoryRow,\n ReportCategoryMeta,\n ControlRoomActivityEntry,\n ControlRoomSectionMetric,\n ControlRoomSnapshot,\n InventoryBookingState,\n InventoryBookingObject,\n InventoryBooking,\n InventoryBookingsQuery,\n InventoryBookingsPage,\n InventoryBookingActivity,\n InventoryBookingDetail,\n LogEntry,\n LogPage,\n ReportResult,\n} from './manageApi';\nexport type { ExpandedSeat, SeatHoverDetails } from '@seatlayer/core';\n","/**\n * SeatManager — the organizer manage surface, packaged for the SDK.\n *\n * Productizes the SeatLayer dashboard's ManageEventPage into a framework-\n * agnostic class (mirrors how SeatPicker productized the buyer flow). It mounts\n * the shared engine in `manageMode`, subscribes to the event's realtime channel\n * and drives three control-room tools on one persistent canvas:\n *\n * - **view** — a live board: realtime seat repaint (flash on hold/book),\n * live KPI tallies + configured booked value, and a streaming activity\n * feed derived from the delta stream + audit log. Read-only.\n * - **inspect** — select one seat to read its live inventory context.\n * - **block** — bulk-first block/unblock: marquee-drag, ⌘A select-all,\n * whole-category / whole-section select, single-seat fallback →\n * one batched block/unblock (optimistic, reconciled by the WS),\n * and timed auto-release.\n *\n * Auth: organizer chart/media, inventory, realtime and reports all carry a\n * short-lived event-scoped browser grant (`mse_…`) via {@link ManageApi}.\n * Tenant secret keys are unsupported in this browser surface, and organizer\n * authority is never downgraded to buyer `/pub`.\n */\nimport {\n SeatmapRenderer,\n expandChart,\n computeSections,\n gaAreasOf,\n gaUnitLabels,\n UNGROUPED_ID,\n type AvailabilityRule,\n type ChartDoc,\n type ChartTheme,\n type ExpandedSeat,\n type SeatStatus,\n type SectionNode,\n} from '@seatlayer/core';\n// TYPE-ONLY, and it has to stay that way. Channels mode is a ~95 KB (minified)\n// sub-app that most cockpit visits never open, so it is reached through\n// `import('./channelsMode')` in `ensureChannels()`. A single value import here\n// would fold the whole thing back into first paint with nothing failing to say\n// so. Its stylesheet travels with it too: `CHANNELS_CSS` is injected by the\n// lazy load rather than concatenated into `MANAGER_CSS`.\nimport type {\n ChannelsMode, ChannelsCapabilities, ChannelsRowView,\n} from './channelsMode';\nimport type { ChannelSeatStatus } from './channelPlan';\nimport {\n ManageApi,\n ManageApiError,\n type ControlRoomActivityEntry,\n type ControlRoomSnapshot,\n type LogEntry,\n type ReportResult,\n} from './manageApi';\nimport { OrganizerAssetObjectUrls } from './manageAssets';\n\nexport type SeatManagerMode = 'view' | 'inspect' | 'block' | 'sections' | 'channels';\n\n/** Short-lived, event-scoped browser credential minted by a trusted backend. */\nexport type EventScopedManageToken = `mse_${string}`;\n\n/**\n * Capabilities the cockpit's token was minted with. Channels mode is gated on\n * these and fails CLOSED: no `event:channels:view` ⇒ no Channels pill at all;\n * view without `event:channels:manage` ⇒ read-only inspection with every\n * mutation control absent, not merely disabled.\n */\nexport type SeatManagerCapability =\n | 'event:view' | 'event:block' | 'event:cancel' | 'event:reports'\n | 'event:channels:view' | 'event:channels:manage';\n\n/** The select-state of a Sections-mode availability row. An absent rule is\n * `open` (on sale); otherwise the rule's own mode. */\nexport type AvailabilityMode = 'open' | 'closed' | 'hidden' | 'timed' | 'threshold';\n\n/** One row of the Sections rail — a zone header or a single section. */\ninterface SectionRow {\n kind: 'zone' | 'section';\n id: string;\n label: string;\n seatCount: number;\n /** Seat labels the id governs (sent as the rule's `labels`). */\n seatLabels: string[];\n rule: AvailabilityRule | null;\n /** Effective-hidden right now (manual hide, or a timed/threshold window not yet due). */\n hidden: boolean;\n /** Effective-closed right now — visible to buyers but off sale. */\n closed: boolean;\n /** A section whose parent zone carries a rule — its own control is a muted \"Follows zone\". */\n followsZone: boolean;\n}\n\n/** Map an availability rule to its Sections-rail select value (null rule = on sale). */\nexport function availabilityModeOf(rule: AvailabilityRule | null | undefined): AvailabilityMode {\n return rule ? rule.mode : 'open';\n}\n\n/**\n * Build the rule a chosen select mode implies for a set of seat labels, reusing\n * an existing rule's tuning where it carries over (a timed reveal time, a\n * threshold percent). `open` clears the rule (returns null → id dropped from the\n * map). Wire-identical to the EventDO's accepted rule shapes.\n */\nexport function availabilityRuleForMode(\n mode: AvailabilityMode,\n seatLabels: string[],\n prev?: AvailabilityRule | null,\n): AvailabilityRule | null {\n switch (mode) {\n case 'open':\n return null;\n case 'hidden':\n return { mode: 'hidden', labels: seatLabels };\n case 'closed':\n return { mode: 'closed', labels: seatLabels };\n case 'timed':\n return { mode: 'timed', revealAt: prev?.revealAt ?? Date.now() + 3_600_000, labels: seatLabels };\n case 'threshold':\n return { mode: 'threshold', thresholdPct: prev?.thresholdPct ?? 80, labels: seatLabels };\n }\n}\n\n/** epoch ms → a `datetime-local` input value (local time, minute precision). */\nfunction toLocalInput(ms: number): string {\n const d = new Date(ms - new Date().getTimezoneOffset() * 60_000);\n return d.toISOString().slice(0, 16);\n}\n\n/** DO seat status — 'blocked' has no engine analogue (→ 'not_for_sale'). */\ntype DoStatus = 'free' | 'held' | 'booked' | 'blocked';\n\n/** Live KPI snapshot pushed to `onTallies` on every state change. */\nexport interface SeatManagerTallies {\n free: number;\n held: number;\n booked: number;\n blocked: number;\n /** Total seats on the chart. */\n total: number;\n /** booked / total, 0–100. */\n capacityPct: number;\n /** booked / (total − blocked), 0–100 — sell-through of sellable inventory. */\n sellThroughPct: number;\n /** Exact Σ booked unit_price snapshots from the authenticated report. */\n bookedValue: number;\n /** @deprecated Use `bookedValue`. */\n grossRevenue: number;\n /** Booked value is never reconstructed from the chart's current list price. */\n bookedValueStatus: 'loading' | 'current' | 'stale';\n /** @deprecated Use `bookedValueStatus`. */\n revenueStatus: 'loading' | 'current' | 'stale';\n /** ISO-4217 currency for `bookedValue`. */\n currency: string;\n}\n\n/** One streamed activity line for the live feed. */\nexport interface SeatManagerActivity {\n id: string;\n at: number;\n label: string;\n /** Full labels affected by this one backend/realtime operation. */\n labels: string[];\n count: number;\n /** Human verb: held / booked / released / blocked / unblocked. */\n verb: string;\n status: DoStatus;\n /** Spatial context for grouped activity when the chart defines sections. */\n sectionIds?: string[];\n sectionLabels?: string[];\n}\n\n/** Fired after a successful organizer action, for host toasts/telemetry. */\nexport interface SeatManagerActionResult {\n action: 'block' | 'unblock' | 'unblockAll' | 'cancelBooking' | 'setHoldTtl';\n labels: string[];\n count: number;\n}\n\nexport interface SeatManagerOptions {\n /** CSS selector or element to mount into. */\n container: string | HTMLElement;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Event key (e.g. `ev_xxx` / `west-end-p3`). */\n eventKey: string;\n /**\n * Short-lived, event-scoped `mse_…` browser grant minted by your backend.\n * Tenant secret keys are unsupported in SeatManager and must stay server-side.\n */\n token: EventScopedManageToken;\n /** Absolute token expiry (epoch ms). Enables proactive in-place rotation. */\n tokenExpiresAt?: number;\n /** Initial mode. Default 'view'. */\n mode?: SeatManagerMode;\n /**\n * The capability set this token was minted with. Supply it whenever you mint\n * an `mse_…` grant — it is the only way the widget can know a delegated token\n * carries `event:channels:manage`, and without it Channels mode stays\n * read-only (fail-closed).\n */\n capabilities?: SeatManagerCapability[] | string[];\n /** ISO-4217 fallback currency for configured booked value (chart/event wins). */\n currency?: string;\n /** Chart theme override for the chrome (rails/bar). Chart colors come from the doc. */\n theme?: ChartTheme;\n /**\n * Keep the canvas painting even when the tab is hidden/backgrounded (a war-room\n * board on a second monitor). Calls `forceDraw()` after each delta so Chrome's\n * rAF throttling on occluded tabs never leaves the board stale. Default true.\n */\n keepLiveWhileHidden?: boolean;\n /**\n * Opt in to camera-following for new buyer holds/bookings. Off by default so\n * a live event never steals an operator's current map context.\n */\n followLive?: boolean;\n /** Chart + first snapshot are loaded and the board is live. */\n onReady?: () => void;\n /** Live KPI tallies changed. */\n onTallies?: (tallies: SeatManagerTallies) => void;\n /** A grouped live/audit activity item arrived. */\n onActivity?: (activity: SeatManagerActivity) => void;\n /** Exact private control-room projection changed. */\n onControlRoom?: (snapshot: ControlRoomSnapshot) => void;\n /** Called before token expiry. The manager swaps the result without remounting. */\n onTokenRefresh?: () => Promise<{ token: EventScopedManageToken; expiresAt: number }>;\n /** Tool/mode changed from inside the shared cockpit. */\n onModeChange?: (mode: SeatManagerMode) => void;\n /** Follow-live preference changed from inside the cockpit. */\n onFollowLiveChange?: (enabled: boolean) => void;\n /** Block-mode selection changed (marquee / ⌘A / category / section / tap). */\n onSelectionChange?: (seats: ExpandedSeat[]) => void;\n /** A block/unblock/cancel action completed successfully. */\n onActionComplete?: (result: SeatManagerActionResult) => void;\n /**\n * The realtime link connected or dropped, with the moment the numbers on\n * screen were last known good.\n *\n * A host embedding this cockpit renders its own chrome around it, and until\n * now had no way to know the board had gone stale: the manager tracked the\n * drop internally (its own LIVE/RECONNECTING pill) and told nobody. A host\n * that polls on a timer and pauses while the tab is hidden therefore showed\n * arbitrarily old numbers that looked exactly like fresh ones.\n */\n onConnectionChange?: (state: SeatManagerConnection) => void;\n onError?: (err: unknown) => void;\n}\n\n/** Realtime link state, as reported to the embedding host. */\nexport interface SeatManagerConnection {\n /** `live` while the socket is open; `reconnecting` from drop until reopen. */\n status: 'live' | 'reconnecting';\n /**\n * `Date.now()` of the last snapshot or delta accepted from the server, or\n * null before the first one. This is the honest \"as of\" for whatever the host\n * is displaying — NOT the time the connection dropped, which is later and\n * would overstate freshness.\n */\n lastMessageAt: number | null;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmanager: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmanager: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nfunction assertBrowserManageToken(token: string): asserts token is EventScopedManageToken {\n if (!token.startsWith('mse_')) {\n throw new Error(\n 'seatmanager: token must be a short-lived event-scoped mse_ grant minted by your backend; '\n + 'tenant secret keys are unsupported in browsers',\n );\n }\n}\n\n/** 'blocked' → renderer 'not_for_sale'; the rest pass through. */\nfunction toRenderStatus(s: DoStatus): SeatStatus {\n return s === 'blocked' ? 'not_for_sale' : s;\n}\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst STYLE_ID = 'seatlayer-manager-style';\n/** Channels mode's stylesheet — injected with its lazy module, not before. */\nconst CHANNELS_STYLE_ID = 'seatlayer-manager-channels-style';\nconst FEED_CAP = 80;\nconst MAX_LIVE_SEAT_PULSES = 16;\nconst MAX_LIVE_SECTION_PULSES = 4;\n\nconst LEGEND: { key: 'free' | 'held' | 'booked' | 'blocked'; label: string; color: string }[] = [\n { key: 'free', label: 'Free', color: '#6e7bff' },\n { key: 'held', label: 'Held', color: '#f4b740' },\n { key: 'booked', label: 'Booked', color: '#22a06b' },\n { key: 'blocked', label: 'Blocked', color: '#8b94ac' },\n];\n\n/** Exported so the motion contract can be asserted without a real browser —\n * see `SeatManagerMotion.test.ts`. Not part of the public package surface.\n * `@sl-css` opts it into build-time minification (cdn/minifyCssLiterals.ts). */\nexport const MANAGER_CSS = /* @sl-css */ `\n/* The floor was 480px, which trapped the cockpit in any host shorter than that:\n every ancestor here is overflow:hidden, so the bottom of the rail (Create\n channel, Show archived) was rendered but clipped away by the host and could\n not be reached by scrolling anything. 320px still keeps an unsized host from\n collapsing to the top bar, and the rail scrolls to its full content below. */\n.slm{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:320px;overflow:hidden;\n background:var(--slm-bg);color:var(--slm-text);font-family:var(--slm-font);border-radius:var(--slm-radius);\n /* Motion tokens (motion-system §2), declared by the cockpit ROOT rather than\n borrowed from CHANNELS_CSS. The base cockpit animates whether or not\n Channels mode is in use, so owning its own tokens is what stops a token\n edit from silently changing only half the surface. Channels mode declares\n the identical values so an embed of it stays self-contained. */\n --slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;--slm-mo-ambient:2000ms;\n --slm-mo-out:cubic-bezier(.2,.8,.2,1);--slm-mo-in-out:cubic-bezier(.4,0,.2,1);--slm-mo-exit:cubic-bezier(.4,0,1,1);\n --slm-mo-spring:cubic-bezier(.34,1.3,.64,1)}\n.slm *{box-sizing:border-box;margin:0;padding:0}\n.slm button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}\n.slm input{font:inherit}\n\n/* top bar */\n/* FOUR columns, because the bar has four children: modes, the tools\n select, the live badge, and the actions. With three, the actions had no\n column and fell to an implicit second row — where justify-self:end\n aligned them to the right of column ONE, so they read as indented\n rather than as either edge. The 1fr moves to the last column so the\n actions sit hard right and the live badge hugs its own text instead of\n stretching across the free space.\n\n .slm.compact still spans the actions full-width on its own row below;\n that wrap is deliberate and is why this looked intermittent — the same\n broken layout had one designed cause and one accidental one. */\n.slm-bar{display:grid;grid-template-columns:auto auto auto minmax(0,1fr);align-items:center;column-gap:14px;row-gap:10px;\n padding:10px 16px;border-bottom:1px solid var(--slm-line);flex:none}\n.slm-modes{display:inline-flex;background:var(--slm-surface);border:1px solid var(--slm-line);border-radius:999px;padding:3px}\n.slm-mode{padding:6px 16px;border-radius:999px;font-weight:700;font-size:13px;color:var(--slm-muted)}\n.slm-mode.on{background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-live{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.12em;font-weight:800;color:var(--slm-muted)}\n.slm-live-dot{width:8px;height:8px;border-radius:50%;background:#8b94ac}\n.slm.live .slm-live-dot{background:#22a06b;box-shadow:0 0 0 0 rgba(34,160,107,.55);\n animation:slm-pulse var(--slm-mo-ambient) infinite}\n@keyframes slm-pulse{0%{box-shadow:0 0 0 0 rgba(34,160,107,.5)}70%{box-shadow:0 0 0 7px rgba(34,160,107,0)}100%{box-shadow:0 0 0 0 rgba(34,160,107,0)}}\n.slm-kpis{grid-column:1/-1;display:grid;grid-template-columns:repeat(8,minmax(0,1fr));width:100%;padding-top:10px;\n border-top:1px solid var(--slm-line)}\n.slm-kpi{position:relative;display:flex;min-width:0;flex-direction:column;align-items:center;padding:0 5px;line-height:1.15;text-align:center}\n.slm-kpi b{display:flex;min-width:0;align-items:baseline;justify-content:center;font-size:17px;font-weight:800;\n font-variant-numeric:tabular-nums;white-space:nowrap}\n.slm-kpi span{font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--slm-muted);font-weight:700}\n.slm-kpi .dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:baseline}\n/* The one playful moment this surface is allowed (§2 --mo-spring). It ran at\n .58s against a 200ms catalog, which read as a different design language from\n the dashboard tile it mirrors; Channels mode's own count bump is the same\n pattern and must stay in step with it. */\n.slm-kpi.changed b{animation:slm-kpi-bump var(--slm-mo-base) var(--slm-mo-spring)}\n.slm-kpidelta{position:absolute;right:4px;top:-12px;padding:2px 5px;border-radius:999px;background:rgba(34,160,107,.17);\n color:#5bd39b!important;font-size:9px!important;letter-spacing:0!important;text-transform:none!important;white-space:nowrap;\n animation:slm-kpi-delta 1.45s ease-out both;pointer-events:none}\n.slm-kpidelta.down{background:rgba(244,183,64,.14);color:#f7ca6b!important}\n@keyframes slm-kpi-bump{0%,100%{transform:none}35%{transform:translateY(-2px) scale(1.08);text-shadow:0 0 18px rgba(255,255,255,.24)}}\n@keyframes slm-kpi-delta{0%{opacity:0;transform:translateY(5px)}18%,72%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-5px)}}\n.slm-barbtn{padding:7px 13px;border-radius:9px;border:1px solid var(--slm-line);color:var(--slm-text);font-weight:700;font-size:12.5px}\n.slm-barbtn:hover{border-color:var(--slm-muted)}\n.slm-barbtn.follow.on{background:rgba(34,160,107,.13);border-color:#22a06b;color:#5bd39b}\n\n/* body */\n.slm-body{display:flex;flex:1;min-height:0}\n.slm-map{position:relative;flex:1;min-width:0}\n.slm-map-host{position:absolute;inset:0}\n.slm-hud{position:absolute;left:12px;bottom:12px;display:flex;gap:8px}\n.slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);\n border:1px solid var(--slm-line);color:var(--slm-text)}\n.slm-zoomhint{position:absolute;left:50%;top:14px;transform:translateX(-50%);padding:6px 13px;border-radius:999px;\n background:rgba(0,0,0,.55);color:#fff;font-size:12px;font-weight:700;pointer-events:none;opacity:0;\n transition:opacity var(--slm-mo-base) var(--slm-mo-out)}\n.slm-zoomhint.on{opacity:1}\n.slm-liveevent{position:absolute;left:50%;top:14px;z-index:4;display:flex;align-items:center;gap:8px;max-width:min(560px,calc(100% - 32px));\n padding:8px 12px;border:1px solid var(--slm-line);border-radius:999px;background:color-mix(in srgb,var(--slm-surface) 92%,transparent);\n box-shadow:0 10px 34px rgba(0,0,0,.32);opacity:0;transform:translate(-50%,-8px);pointer-events:none;\n transition:opacity var(--slm-mo-quick) var(--slm-mo-out),transform var(--slm-mo-base) var(--slm-mo-out);\n backdrop-filter:blur(10px)}\n.slm-liveevent.on{opacity:1;transform:translate(-50%,0)}\n.slm.block-mode .slm-liveevent{top:52px}\n.slm-liveeventdot{width:8px;height:8px;border-radius:50%;flex:none}.slm-liveeventcopy{min-width:0;overflow:hidden;text-overflow:ellipsis;\n white-space:nowrap;font-size:12px;font-weight:800}.slm-liveeventhint{color:var(--slm-muted);font-size:10px;white-space:nowrap}\n.slm-rail{width:320px;flex:none;border-left:1px solid var(--slm-line);display:flex;flex-direction:column;min-height:0}\n.slm-railscroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px}\n.slm-eyebrow{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--slm-muted);font-weight:800;margin-bottom:6px}\n.slm-hint{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}\n\n/* legend rows */\n.slm-legend{display:flex;flex-direction:column;gap:2px;margin-bottom:16px}\n.slm-legrow{display:flex;align-items:center;gap:9px;padding:7px 2px;border-bottom:1px solid var(--slm-line)}\n.slm-legdot{width:10px;height:10px;border-radius:50%;flex:none}\n.slm-leglabel{flex:1;font-size:13px;font-weight:600}\n.slm-legcount{font-size:13px;font-weight:800;font-variant-numeric:tabular-nums}\n\n/* activity feed */\n.slm-feed{display:flex;flex-direction:column;gap:0}\n.slm-feedrow{display:flex!important;width:100%;align-items:center;gap:9px;padding:8px 2px!important;border-bottom:1px solid var(--slm-line)!important;\n border-radius:6px;font-size:12.5px;text-align:left!important;\n animation:slm-in var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-feedrow:hover{background:rgba(255,255,255,.035)!important}\n@keyframes slm-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}\n.slm-feeddot{width:8px;height:8px;border-radius:50%;flex:none}\n.slm-feedtext{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.slm-feedtext b{font-weight:800}\n.slm-feedsection{display:block;overflow:hidden;text-overflow:ellipsis;color:var(--slm-muted);font-size:10px;font-weight:750}\n.slm-feedmeta{display:flex;flex:none;flex-direction:column;align-items:flex-end;gap:1px}.slm-feedtime{font-size:10px;color:var(--slm-muted);font-variant-numeric:tabular-nums}\n.slm-feedlocate{font-size:9.5px;color:var(--slm-accent);font-weight:800}\n.slm-empty{font-size:12.5px;color:var(--slm-muted);padding:12px 0}\n\n/* block toolbar */\n.slm-selbar{display:flex;align-items:baseline;gap:8px;margin-bottom:10px}\n.slm-selnum{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums}\n.slm-sellabel{font-size:12px;color:var(--slm-muted);font-weight:600}\n.slm-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}\n.slm-btn{flex:1;min-width:120px;padding:10px 14px;border-radius:10px;background:var(--slm-accent);color:var(--slm-accent-ink);\n font-weight:800;font-size:13px;text-align:center}\n.slm-btn:disabled{opacity:.45;cursor:not-allowed}\n.slm-btn.ghost{background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text)}\n.slm-btn.danger{background:#c0392b;color:#fff}\n.slm-chiprow{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:6px}\n.slm-chip{padding:6px 11px;border-radius:999px;border:1px solid var(--slm-line);background:var(--slm-surface);\n font-size:12px;font-weight:700;color:var(--slm-text);display:inline-flex;align-items:center;gap:6px}\n.slm-chip:hover{border-color:var(--slm-muted)}\n.slm-chip .dot{width:8px;height:8px;border-radius:50%}\n.slm-chip .slm-chipcount{min-width:18px;padding:1px 5px;border-radius:999px;background:rgba(255,255,255,.07);\n color:var(--slm-muted);font-size:10px;font-variant-numeric:tabular-nums;text-align:center}\n.slm-chip .slm-chipcheck{display:none;font-size:11px;line-height:1}\n.slm-chip.on{border-color:var(--slm-accent);background:color-mix(in srgb,var(--slm-accent) 20%,var(--slm-surface));\n box-shadow:0 0 0 1px color-mix(in srgb,var(--slm-accent) 45%,transparent)}\n.slm-chip.on .slm-chipcount{background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-chip.on .slm-chipcheck{display:inline}\n.slm-chip.partial{border-style:dashed;border-color:var(--slm-accent)}\n.slm-chip:disabled{opacity:.42;cursor:not-allowed}\n.slm-selecthelp{margin:-1px 0 9px;color:var(--slm-muted);font-size:11px;line-height:1.4}\n.slm-field{margin:14px 0}\n.slm-field label{display:block;font-size:11px;font-weight:700;color:var(--slm-muted);margin-bottom:5px}\n.slm-input,.slm-select{width:100%;padding:8px 10px;border-radius:9px;border:1px solid var(--slm-line);\n background:var(--slm-surface);color:var(--slm-text)}\n.slm-note{font-size:11.5px;color:var(--slm-muted);margin-top:5px}\n.slm-blocked{margin-top:17px;padding-top:15px;border-top:1px solid var(--slm-line)}\n.slm-blockedhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}\n.slm-blockedhead .slm-eyebrow{margin-bottom:0}.slm-blockedtotal{font-size:11px;color:var(--slm-muted)}\n.slm-blockedtotal b{color:var(--slm-text);font-variant-numeric:tabular-nums}\n.slm-blockedtools{display:grid;grid-template-columns:minmax(0,1fr);gap:7px}\n.slm-blockedsummary{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:9px 0 6px;\n color:var(--slm-muted);font-size:10.5px}\n.slm-linkbtn{font-size:11px!important;font-weight:800!important;color:var(--slm-accent)!important;text-align:right}\n.slm-linkbtn:disabled{opacity:.45;cursor:not-allowed}\n.slm-blockedlist{max-height:246px;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);\n border-radius:10px;background:var(--slm-surface)}\n.slm-blockeditem{display:grid!important;grid-template-columns:18px minmax(0,1fr);width:100%;gap:8px;padding:8px 9px!important;\n border-bottom:1px solid var(--slm-line)!important;text-align:left!important}\n.slm-blockeditem:last-child{border-bottom:0!important}.slm-blockeditem:hover{background:rgba(255,255,255,.035)!important}\n.slm-blockeditem.on{background:color-mix(in srgb,var(--slm-accent) 13%,var(--slm-surface))!important}\n.slm-blockedcheck{display:flex;align-items:center;justify-content:center;width:16px;height:16px;margin-top:1px;border-radius:4px;\n border:1px solid var(--slm-muted);color:transparent;font-size:10px;font-weight:900}\n.slm-blockeditem.on .slm-blockedcheck{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-blockedcopy{min-width:0}.slm-blockedlabel{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\n font-size:12px;font-weight:800}.slm-blockedmeta{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\n margin-top:2px;color:var(--slm-muted);font-size:10px}\n.slm-blockedmore{width:100%;padding:9px!important;color:var(--slm-accent)!important;font-size:11px!important;font-weight:800!important}\n.slm-blockedempty{padding:12px;color:var(--slm-muted);font-size:11.5px;line-height:1.45}\n.slm-allnote{margin-top:-4px;margin-bottom:10px}\n\n/* toast */\n.slm-toast{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);padding:10px 16px;border-radius:10px;\n font-size:13px;font-weight:700;box-shadow:0 8px 24px rgba(0,0,0,.28);opacity:0;pointer-events:none;\n transition:opacity var(--slm-mo-base) var(--slm-mo-out);\n background:var(--slm-surface);color:var(--slm-text);border:1px solid var(--slm-line);z-index:5}\n.slm-toast.on{opacity:1}\n.slm-toast.err{background:#c0392b;color:#fff;border-color:#c0392b}\n.slm-toast.ok{background:#1f7a4d;color:#fff;border-color:#1f7a4d}\n\n/* control-room actions + insights */\n.slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:7px}\n.slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:#f7ca6b}\n.slm-sectionlist{display:flex;flex-direction:column;gap:8px;margin-top:4px}\n.slm-sectionlist + .slm-eyebrow{margin-top:18px}\n.slm-sectionrow{width:100%;padding:10px!important;border:1px solid var(--slm-line)!important;border-radius:10px;\n background:var(--slm-surface)!important;text-align:left!important;\n transition:border-color var(--slm-mo-quick) var(--slm-mo-out),transform var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-sectionrow:hover{border-color:var(--slm-muted)!important;transform:translateY(-1px)}\n.slm-sectiontop,.slm-sectionmeta{display:flex;align-items:center;justify-content:space-between;gap:10px}\n.slm-sectiontop{font-size:12.5px;font-weight:800}.slm-sectionmeta{margin-top:5px;color:var(--slm-muted);font-size:11px}\n.slm-sectionmeta>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.slm-trend{font-size:10px;text-transform:uppercase;letter-spacing:.08em}.slm-trend.rising{color:#22a06b}.slm-trend.cooling{color:#f4b740}\n.slm-sectionlocate{color:var(--slm-accent);font-size:9.5px;font-weight:800}\n.slm-health{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}\n.slm-healthitem{padding:10px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface)}\n.slm-healthitem b{display:block;font-size:17px;font-variant-numeric:tabular-nums}.slm-healthitem span{display:block;margin-top:2px;color:var(--slm-muted);font-size:10px;text-transform:uppercase;letter-spacing:.08em}\n.slm-sectionhead{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-top:18px}\n.slm-windows{display:flex;gap:3px;padding:2px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-surface)}\n.slm-window{padding:4px 6px;border-radius:6px;font-size:10px;font-weight:800;color:var(--slm-muted)}.slm-window.on{background:var(--slm-accent);color:var(--slm-accent-ink)}\n.slm-momentumhelp{margin:10px 0 14px;padding:10px;border:1px solid rgba(244,183,64,.28);border-radius:10px;background:rgba(244,183,64,.07)}\n.slm-momentumhelp[hidden]{display:none}.slm-momentumscale{display:flex;align-items:center;gap:7px;color:var(--slm-muted);font-size:10px;font-weight:750;text-transform:uppercase;letter-spacing:.07em}\n.slm-momentumgradient{height:6px;min-width:64px;flex:1;border-radius:999px;background:linear-gradient(90deg,#f4b740,#ef4444)}\n.slm-momentumcopy{margin-top:7px;color:var(--slm-muted);font-size:11px;line-height:1.45}\n/* sections: availability windows */\n.slm-availlist{display:flex;flex-direction:column;gap:8px;margin:2px 0 12px}\n.slm-availrow{padding:10px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface);\n transition:border-color var(--slm-mo-quick) var(--slm-mo-out),opacity var(--slm-mo-quick) var(--slm-mo-out)}\n.slm-availrow.zone{background:color-mix(in srgb,var(--slm-surface) 82%,#000)}\n.slm-availrow.hidden{opacity:.62}.slm-availrow.closed{opacity:.82}\n.slm-availhead{display:flex;align-items:center;gap:8px}\n.slm-availlabel{display:flex;align-items:center;gap:5px;flex:1;min-width:0;font-size:12.5px;font-weight:800;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.slm-availcaret{flex:none;color:var(--slm-muted);font-size:10px}\n.slm-availcount{flex:none;font-size:11px;font-weight:700;color:var(--slm-muted);font-variant-numeric:tabular-nums}\n.slm-availbadge{flex:none;font-size:9px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;padding:2px 6px;border-radius:999px}\n.slm-availbadge.hidden{background:rgba(139,148,172,.18);color:#c2c9d8}\n.slm-availbadge.closed{background:rgba(244,183,64,.16);color:#f7ca6b}\n.slm-availselwrap{position:relative;flex:none;display:inline-flex}\n.slm-availmode{width:auto;max-width:190px;padding:6px 8px;font-size:11.5px;font-weight:700;cursor:pointer}\n.slm-availmode.on{border-color:var(--slm-accent);color:var(--slm-text)}\n.slm-availmode:disabled{opacity:.55;cursor:progress}\n.slm-availfollows{flex:none;padding:5px 10px;border:1px solid var(--slm-line);border-radius:7px;background:var(--slm-surface);color:var(--slm-muted);font-size:11px;font-weight:600;white-space:nowrap}\n.slm-availdetail{display:flex;align-items:center;gap:8px;margin-top:9px}\n.slm-availdetail .slm-input{flex:1}\n.slm-availpct{max-width:74px;flex:none!important}\n.slm-availpctlabel{font-size:11px;color:var(--slm-muted);font-weight:600;white-space:nowrap}\n.slm-availsummary{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--slm-line);border-radius:9px;color:var(--slm-muted);font-size:12.5px}\n.slm-availdot{width:9px;height:9px;border-radius:50%;flex:none;background:#22a06b}.slm-availdot.warn{background:#f4b740}\n.slm-availcallout{display:flex;align-items:flex-start;gap:8px;margin-top:10px;padding:10px 12px;border:1px solid rgba(244,183,64,.45);border-radius:9px;background:rgba(244,183,64,.1)}\n.slm-availstar{flex:none;margin-top:1px;color:#f4b740;font-size:13px;line-height:1}\n.slm-availcallout p{font-size:11.5px;line-height:1.55;color:#f4d58a}.slm-availcallout b{color:#ffe4a3;font-weight:800}\n.slm-inspect-card{padding:16px;border:1px solid var(--slm-line);border-radius:12px;background:var(--slm-surface)}\n.slm-inspect-label{font-size:24px;font-weight:850;letter-spacing:-.02em;line-height:1.1}\n.slm-inspect-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px;margin-top:18px}\n.slm-inspect-grid>div{min-width:0}.slm-inspect-grid span{display:block;color:var(--slm-muted);font-size:10px;\n text-transform:uppercase;letter-spacing:.08em}.slm-inspect-grid b{display:block;margin-top:4px;font-size:13px;line-height:1.35;overflow-wrap:anywhere}\n.slm:fullscreen{border-radius:0;min-height:100vh;background:var(--slm-bg)}\n.slm:fullscreen .slm-bar{padding:14px 22px}.slm:fullscreen .slm-kpi b{font-size:21px}.slm:fullscreen .slm-rail{width:360px}\n\n.slm.compact .slm-rail{width:100%;border-left:0;border-top:1px solid var(--slm-line);height:44%}\n.slm.compact .slm-body{flex-direction:column}\n.slm.compact .slm-bar{grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:8px}\n.slm.compact .slm-modes{min-width:0}.slm.compact .slm-mode{padding-inline:11px}\n.slm.compact .slm-live{justify-self:end}.slm.compact .slm-bar-actions{grid-column:1/-1;justify-self:stretch}\n.slm.compact .slm-barbtn{flex:1;padding:6px 9px}.slm.compact .slm-kpis{grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}\n.slm.compact .slm-kpi[data-kpi=\"viewing-map\"],.slm.compact .slm-kpi[data-kpi=\"active-holds\"],\n.slm.compact .slm-kpi[data-kpi=\"booked-pct\"],.slm.compact .slm-kpi[data-kpi=\"booked-value\"]{display:none}\n/* Reduced motion, as a BLANKET over the cockpit subtree rather than a list of\n selectors. The list this replaces named four animations and two transitions,\n and had silently fallen behind the stylesheet: the zoom hint, the toast and\n the availability rows all still animated for a user who had asked the OS for\n none. An enumerated list has to be edited every time a rule is added, and\n nothing fails when it isn't — so it drifts. This cannot.\n\n Motion is removed, never the information it carried: Channels mode's own\n block substitutes static outlines for its shake and success states, and it\n stays authoritative for those. No JS here waits on animationend or\n transitionend, so cutting them outright strands no state. */\n@media (prefers-reduced-motion:reduce){\n .slm,.slm *,.slm *::before,.slm *::after{\n animation:none!important;\n transition:none!important;\n scroll-behavior:auto!important}\n}\n`;\n\nfunction injectStyle(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = MANAGER_CSS;\n document.head.appendChild(el);\n}\n\n/**\n * Channels mode's stylesheet, injected when its module arrives.\n *\n * It used to be concatenated into `MANAGER_CSS`, which meant the whole Channels\n * stylesheet was a static dependency of the cockpit's first paint even for the\n * majority of visits that never open Channels. Splitting it here is what lets\n * `channelsMode` leave the static graph entirely.\n *\n * Its own `<style>` element, and a second id, so the base cockpit's stylesheet\n * is never rewritten after mount — restyling a live surface is how a repaint\n * turns into a flash. Every rule inside is scoped under `.slm`, so arriving\n * late changes nothing that was already on screen.\n */\nfunction injectChannelsStyle(css: string): void {\n if (typeof document === 'undefined' || document.getElementById(CHANNELS_STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = CHANNELS_STYLE_ID;\n el.textContent = css;\n document.head.appendChild(el);\n}\n\n/** Resolve chrome tokens from a chart theme (dark war-room defaults). */\nfunction themeVars(theme: ChartTheme | undefined): Record<string, string> {\n const t = theme ?? {};\n return {\n '--slm-bg': t.background ?? '#0e1017',\n '--slm-surface': '#181b24',\n '--slm-text': '#eef1f7',\n '--slm-muted': '#8b93a7',\n '--slm-line': 'rgba(255,255,255,.09)',\n '--slm-accent': t.accent ?? '#6e7bff',\n '--slm-accent-ink': t.accentInk ?? '#ffffff',\n '--slm-font': \"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif\",\n '--slm-radius': '14px',\n };\n}\n\nfunction relTime(at: number, now: number): string {\n const s = Math.max(0, Math.round((now - at) / 1000));\n if (s < 5) return 'just now';\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n return `${Math.round(m / 60)}h ago`;\n}\n\nfunction fmtMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency, maximumFractionDigits: 0 }).format(amount);\n } catch {\n return `${currency} ${Math.round(amount).toLocaleString()}`;\n }\n}\n\nfunction esc(value: unknown): string {\n return String(value ?? '')\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nexport class SeatManager {\n private readonly opts: SeatManagerOptions;\n private readonly api: ManageApi;\n private readonly key: string;\n private keepLive: boolean;\n\n private host: HTMLElement;\n private root!: HTMLDivElement;\n private mapHost!: HTMLDivElement;\n private els: Record<string, HTMLElement> = {};\n\n private renderer: SeatmapRenderer | null = null;\n private doc: ChartDoc | null = null;\n private mode: SeatManagerMode;\n\n // label ⇄ id + status truth (backend speaks labels, engine speaks ids).\n private labelToId = new Map<string, string>();\n private labelToSeat = new Map<string, ExpandedSeat>();\n private allIds: string[] = [];\n /**\n * GA inventory units — real sellable labels the server counts, with NO seat\n * geometry and therefore no renderer binding. They live here rather than in\n * `labelToId`/`allIds` so every paint path keeps addressing paintable nodes\n * only, while the tally denominator finally covers the same universe the\n * numerator does. Without them a GA sale hit `booked` but not `total`:\n * Free under-reported by GA capacity and SOLD% could exceed 100%.\n */\n private gaUnitLabelSet = new Set<string>();\n private status = new Map<string, DoStatus>();\n /** Live non-free counters, moved by each delta rather than re-walked. */\n private counts: Record<Exclude<DoStatus, 'free'>, number> = { held: 0, booked: 0, blocked: 0 };\n /** Bumped whenever the seat model is replaced wholesale (a full snapshot). */\n private modelVersion = 0;\n private currency = 'USD';\n /** Currency read from the event/control-room projection; host currency is fallback only. */\n private authoritativeCurrency: string | null = null;\n private authoritativeGrossRevenue = 0;\n private revenueStatus: SeatManagerTallies['revenueStatus'] = 'loading';\n private revenueRequest = 0;\n private controlRoomSnapshot: ControlRoomSnapshot | null = null;\n /** Bearer-fetched organizer chart media, revoked with this manager. */\n private readonly organizerAssetUrls: OrganizerAssetObjectUrls;\n /**\n * The server's own totals, pinned to the client model they were read against.\n * Display = server baseline + (client now − client then), so the authoritative\n * numbers land exactly on arrival and deltas still move them between reads.\n * A wholesale model replacement invalidates the pairing (`model`), and the\n * client tallies — themselves a fresh authenticated read — take over.\n */\n private serverBaseline: {\n model: number;\n server: { free: number; held: number; booked: number; blocked: number };\n client: { free: number; held: number; booked: number; blocked: number };\n } | null = null;\n /** Latest presence frame, held whether or not a snapshot has landed yet. */\n private livePresence: { at: number; value: { shoppingSessions: number; activeHolds: number } } | null = null;\n /** Latest cumulative booked gross pushed on a delta frame. */\n private liveGross: { at: number; value: number } | null = null;\n /** Coalesces a burst of deltas into one KPI/rail repaint. */\n private paintHandle: number | null = null;\n private trendWindowMinutes = 15;\n private heatEnabled = false;\n private followLive: boolean;\n private lastKpiValues = new Map<string, number>();\n private activeKpiDeltas = new Map<string, { text: string; down: boolean }>();\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 /** Mirrors the `live` root class, so the getter never has to read the DOM. */\n private connectionStatus: SeatManagerConnection['status'] = 'reconnecting';\n /** When the server last told us something. Stamped on accepted traffic only —\n * a socket that opens and says nothing has not refreshed anything. */\n private lastMessageAt: number | null = null;\n private ready = false;\n\n private feed: SeatManagerActivity[] = [];\n private feedTimer: ReturnType<typeof setInterval> | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private liveEventTimer: ReturnType<typeof setTimeout> | null = null;\n private kpiCleanupTimer: ReturnType<typeof setTimeout> | null = null;\n private followLiveTimer: ReturnType<typeof setTimeout> | null = null;\n private followSeatTimer: ReturnType<typeof setTimeout> | null = null;\n private releaseAt: number | null = null;\n private layoutObserver: ResizeObserver | null = null;\n private tokenExpiresAt: number | null = null;\n private tokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private tokenRefreshInFlight = false;\n private sectionByObject = new Map<string, string>();\n private sectionLabelById = new Map<string, string>();\n private sectionsBase: ReturnType<typeof computeSections> | null = null;\n // Sections mode (availability windows): organizer rules + the live effective\n // hidden/closed sets from the snapshot + WS (a timed/threshold rule fires DO-side).\n private availabilityRules: Record<string, AvailabilityRule> = {};\n private effectiveHidden = new Set<string>();\n private effectiveClosed = new Set<string>();\n private availabilitySaving = false;\n private lastSyncedAt: number | null = null;\n private blockedQuery = '';\n private blockedSection = '';\n private blockedResultLimit = 100;\n private unblockAllConfirmTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Sales channels (M6b).\n *\n * Two fields, and the split between them is the whole point. `channelCaps` is\n * AUTHORITY and is known early — it is read from the token's declared\n * capabilities before the first rail paint, so the Channels pill either\n * exists from the start or never appears. `channels` is the loaded sub-app,\n * and it now arrives late: its module is fetched on first entry into Channels\n * mode (`ensureChannels`), not at mount.\n *\n * So every gate that used to ask `!!this.channels` — the pill, the mode\n * whitelist, the `c` shortcut — asks `channelCaps.view` instead. Asking the\n * instance would make a permission the member genuinely has look like one\n * they do not for as long as a network fetch takes.\n */\n private channels: ChannelsMode | null = null;\n private channelCaps: ChannelsCapabilities = { view: false, manage: false };\n /** Supersedes an async capability probe after token/capability rotation. */\n private channelCapabilityResolution = 0;\n /** In-flight `import('./channelsMode')`, so concurrent entries load once. */\n private channelsLoading: Promise<void> | null = null;\n\n private readonly onFullscreenChange = (): void => {\n this.paintFullscreenButton();\n this.updateContainerLayout();\n this.renderer?.forceDraw();\n };\n\n private readonly onKeyDown = (event: KeyboardEvent): void => {\n if (event.metaKey || event.ctrlKey || event.altKey) return;\n const target = event.target as HTMLElement | null;\n if (target?.matches('input,select,textarea,[contenteditable=\"true\"]')) return;\n const key = event.key.toLowerCase();\n if (key === 'm') this.setMode('view');\n else if (key === 'i') this.setMode('inspect');\n else if (key === 'b') this.setMode('block');\n else if (key === 's') this.setMode('sections');\n else if (key === 'c') { if (!this.channelCaps.view) return; this.setMode('channels'); }\n else if (key === 'f') this.toggleFullscreen();\n else if (key === 'escape') { if (!this.channels?.handleBack()) return; }\n else return;\n event.preventDefault();\n };\n\n private readonly onRailClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n const sectionButton = target?.closest<HTMLElement>('[data-section-focus]');\n if (sectionButton?.dataset.sectionFocus) {\n this.locateSection(sectionButton.dataset.sectionFocus);\n return;\n }\n const feedButton = target?.closest<HTMLElement>('[data-feed-id]');\n if (feedButton?.dataset.feedId) this.locateActivity(feedButton.dataset.feedId);\n };\n\n constructor(options: SeatManagerOptions) {\n assertBrowserManageToken(options.token);\n this.opts = options;\n this.key = options.eventKey;\n this.mode = options.mode ?? 'view';\n this.keepLive = options.keepLiveWhileHidden ?? true;\n this.followLive = options.followLive ?? false;\n this.currency = options.currency ?? 'USD';\n this.tokenExpiresAt = options.tokenExpiresAt ?? null;\n this.api = new ManageApi(options.apiBase ?? DEFAULT_API_BASE, options.token);\n this.organizerAssetUrls = new OrganizerAssetObjectUrls(\n this.key,\n (key, asset) => this.withAuthRetry(() => this.api.asset(key, asset)),\n );\n this.host = resolveContainer(options.container);\n }\n\n /** Build the DOM, load the chart, subscribe to realtime, mount the board. */\n async render(): Promise<this> {\n injectStyle();\n this.buildChrome();\n try {\n const res = await this.withAuthRetry(() => this.api.chart(this.key));\n this.doc = await this.organizerAssetUrls.prepareRendererChart(res.doc);\n this.authoritativeCurrency = res.event.currency ?? null;\n this.currency = this.authoritativeCurrency ?? this.opts.currency ?? this.currency;\n this.buildUnitUniverse(this.doc);\n this.buildRenderer();\n this.buildSectionOptions();\n const [, controlRoom] = await Promise.all([\n this.resnapshot(),\n this.refreshControlRoom().catch((err) => this.opts.onError?.(err)),\n this.refreshAvailability(),\n ]);\n // Restore recent activity through the view-safe control-room projection.\n // Older workers lack this field, so privileged/secret-key hosts retain the\n // legacy best-effort audit-log fallback during rolling upgrades.\n if (controlRoom?.activity) this.seedFeed(controlRoom.activity);\n else this.api.log(this.key, { limit: 24 }).then((page) => this.seedFeed(page.entries)).catch(() => {});\n void this.connect();\n this.startFeedClock();\n this.ready = true;\n // Resolve channel authority BEFORE the first rail paint so the pill either\n // exists from the start or never appears — a pill that pops in later reads\n // as a permission change that did not happen.\n await this.resolveChannelCapabilities();\n this.setMode(this.mode); // paint the right rail\n this.scheduleTokenRefresh();\n this.opts.onReady?.();\n } catch (err) {\n this.fail(err);\n }\n return this;\n }\n\n // ---- public API -----------------------------------------------------------\n\n setMode(mode: SeatManagerMode): void {\n // Fail closed: a host asking for a mode this token cannot use gets the\n // read-only board, never a half-rendered management surface. The test is\n // the CAPABILITY, not whether the lazy module has landed — see `channels`.\n if (mode === 'channels' && !this.channelCaps.view) mode = 'view';\n // First entry pays for the module. Kicked off before the paints below so\n // the fetch overlaps the mode switch instead of following it.\n if (mode === 'channels' && !this.channels) void this.ensureChannels();\n const changed = mode !== this.mode;\n const wasChannels = this.mode === 'channels';\n this.mode = mode;\n if (!this.renderer && this.doc) this.buildRenderer();\n else this.updateRendererInteraction();\n if (changed) this.renderer?.clearSelection();\n if (wasChannels && mode !== 'channels') this.channels?.leave();\n this.paintModeTabs();\n this.paintRail();\n this.applySectionCanvasTreatment();\n if (mode === 'channels') this.channels?.enter();\n if (changed) this.opts.onModeChange?.(mode);\n }\n\n /**\n * Decide what this token may do with sales channels.\n *\n * Declared capabilities win — a host that mints an `mse_…` grant knows exactly\n * what it asked for. A delegated token with no declaration is probed for read\n * access and then treated as READ-ONLY, because \"we could not tell\" must never\n * render mutation controls.\n */\n private async resolveChannelCapabilities(): Promise<void> {\n const resolution = ++this.channelCapabilityResolution;\n const declared = this.opts.capabilities;\n let next: ChannelsCapabilities;\n if (declared) {\n const set = new Set(declared as string[]);\n next = {\n view: set.has('event:channels:view'),\n manage: set.has('event:channels:view') && set.has('event:channels:manage'),\n };\n } else {\n next = { view: false, manage: false };\n }\n if (!next.view && !declared) {\n // Undeclared delegated token: probe read access once. Read-only either way.\n try {\n await this.api.channels(this.key);\n next = { view: true, manage: false };\n } catch {\n next = { view: false, manage: false };\n }\n }\n if (resolution !== this.channelCapabilityResolution) return;\n this.channelCaps = next;\n if (!this.channelCaps.view) {\n this.channels?.destroy();\n this.channels = null;\n if (this.mode === 'channels') this.setMode('view');\n else this.paintModeTabs();\n return;\n }\n // The instance is NOT built here any more — only the authority is settled.\n // Building it would load the sub-app on every mount, which is the cost this\n // split exists to remove. An instance that already exists (a token rotation\n // re-runs this) is told about the new capabilities in place.\n this.channels?.setCapabilities(this.channelCaps);\n this.paintModeTabs();\n }\n\n /**\n * Load Channels mode, once, on first entry.\n *\n * Everything about this method is shaped by one rule: the cockpit must stay\n * usable and honest while the module is in the air.\n *\n * - The promise is memoized, so a member who taps the pill twice, or a host\n * whose deep link and initial `mode` prop both ask for Channels, loads one\n * module and builds one instance.\n * - Authority is re-checked on arrival. A token rotation can revoke\n * `event:channels:view` between the tap and the load, and building the\n * sub-app for a token that no longer carries the capability would put\n * mutation controls on screen that every server call then refuses.\n * - The mode is re-checked too. Someone who taps Channels and then Monitor\n * before the chunk lands must not be yanked into Channels when it does; the\n * instance is kept (it is paid for) but only entered if we are still there.\n * - A failed load is stated in the rail rather than swallowed. Channels is a\n * whole surface — silently showing an empty one would read as \"this event\n * has no channels\", which is a lie about inventory.\n */\n private ensureChannels(): Promise<void> {\n if (this.channelsLoading) return this.channelsLoading;\n if (this.channels) return Promise.resolve();\n const load = (async () => {\n try {\n const mod = await import('./channelsMode');\n if (this.closed) return;\n // Re-read authority after the await — see above.\n if (!this.channelCaps.view) return;\n if (!this.channels) {\n injectChannelsStyle(mod.CHANNELS_CSS);\n this.channels = new mod.ChannelsMode(this.buildChannelsHost(), this.channelCaps);\n // Entering/leaving buyer preview flips the canvas between selectable\n // and strictly read-only, so re-arm the renderer when the view changes.\n this.channels.onInteractionChange = () => this.updateRendererInteraction();\n }\n if (this.mode !== 'channels') return;\n this.updateRendererInteraction();\n this.paintRail();\n this.channels.enter();\n } catch (err) {\n if (this.closed) return;\n // Allow a retry: the member can leave and re-enter the mode.\n this.channelsLoading = null;\n if (this.mode === 'channels') this.paintRail();\n this.opts.onError?.(err);\n }\n })();\n this.channelsLoading = load;\n return load;\n }\n\n /** The adapter between the cockpit's internals and Channels mode. */\n private buildChannelsHost() {\n return {\n eventKey: this.key,\n api: this.api,\n rail: this.els.rail,\n mapLayer: this.root.querySelector('.slm-map') as HTMLElement,\n root: this.root,\n seats: () => [...this.labelToSeat.values()].map((seat) => ({\n id: seat.id, label: seat.label, x: seat.x, y: seat.y,\n })),\n statusOf: (label: string): ChannelSeatStatus | undefined => this.status.get(label)\n ?? (this.labelToSeat.has(label) ? 'free' : undefined),\n selectionLabels: () => this.selectionLabels(),\n selectByLabels: (labels: string[]) => { this.selectByLabels(labels); },\n clearSelection: () => this.clearSelection(),\n selectSection: (sectionId: string) => { this.selectSection(sectionId); },\n sections: () => this.sectionOptions,\n labelsInSection: (sectionId: string) =>\n this.renderer?.getSelectableInSection(sectionId).map((seat) => seat.label) ?? [],\n // Logical rows, not physical row objects: a segmented row is authored as\n // several objects sharing one `logicalRowId`, and the organizer thinks of\n // it as one row. Tables carry seats too, so they are rows here as well.\n rows: (): ChannelsRowView[] => {\n const objects = new Map((this.doc?.objects ?? []).map((object) => [object.id, object]));\n const rows = new Map<string, ChannelsRowView>();\n for (const seat of this.labelToSeat.values()) {\n const object = objects.get(seat.rowId);\n if (!object || (object.type !== 'row' && object.type !== 'table')) continue;\n const id = seat.logicalRowId ?? seat.rowId;\n const sectionId = this.sectionByObject.get(seat.rowId) ?? UNGROUPED_ID;\n const row = rows.get(id) ?? {\n id,\n label: object.type === 'row'\n ? object.segmentedRow?.displayLabel ?? object.displayLabel ?? object.label\n : object.displayLabel ?? object.label,\n sectionId,\n sectionLabel: this.sectionLabelById.get(sectionId) ?? 'Other seats',\n labels: [],\n };\n row.labels.push(seat.label);\n rows.set(id, row);\n }\n return [...rows.values()].sort((left, right) =>\n left.sectionLabel.localeCompare(right.sectionLabel, undefined, { numeric: true, sensitivity: 'base' })\n || left.label.localeCompare(right.label, undefined, { numeric: true, sensitivity: 'base' }));\n },\n categories: () => (this.doc?.categories ?? []).map((category) => ({\n key: category.key, label: category.label ?? category.key, color: category.color,\n })),\n labelsInCategory: (key: string) => [...this.labelToSeat.entries()]\n .filter(([, seat]) => seat.categoryKey === key).map(([label]) => label),\n sectionOfLabel: (label: string) => {\n const seat = this.labelToSeat.get(label);\n if (!seat) return null;\n const id = this.sectionByObject.get(seat.rowId) ?? UNGROUPED_ID;\n return { id, label: this.sectionLabelById.get(id) ?? 'Other seats' };\n },\n worldToScreen: (point: { x: number; y: number }) => this.renderer?.worldToScreen(point) ?? null,\n seatPixelSize: () => this.seatPixelSize(),\n isSeatDetail: () => this.renderer?.getRung?.() === 'seats',\n showSectionOverview: () => {\n this.renderer?.clearSectionFocus();\n this.renderer?.setRung?.('sections');\n },\n focusSection: (sectionId: string) => this.renderer?.focusSection(sectionId),\n isCompact: () => !!this.root?.classList.contains('compact'),\n setMapInert: (inert: boolean) => {\n this.mapHost.toggleAttribute('inert', inert);\n this.mapHost.setAttribute('aria-hidden', String(inert));\n },\n toast: (message: string, kind: 'ok' | 'err') => this.toast(message, kind),\n onError: (err: unknown) => this.opts.onError?.(err),\n };\n }\n\n /** Actual on-screen seat diameter, for the channel overlay's marks. The\n * renderer's base seat radius is 9 chart units; retaining the camera scale\n * (rather than capping it) keeps every preview paint aligned with the real\n * chart geometry at deep zoom. */\n private seatPixelSize(): number {\n const rect = this.renderer?.getVisibleWorldRect?.();\n const width = this.mapHost?.clientWidth ?? 0;\n if (!rect?.width || !width) return 6;\n return Math.max(3, (width / rect.width) * 18);\n }\n\n /** Toggle the normalized sales-velocity outline overlay without changing seat colors. */\n setHeatOverlay(enabled: boolean): void {\n this.heatEnabled = enabled;\n this.applyHeatOverlay();\n this.paintHeatButton();\n }\n\n /** Toggle opt-in camera following for new buyer hold/book events. */\n setFollowLive(enabled: boolean): void {\n const changed = this.followLive !== enabled;\n this.followLive = enabled;\n if (!enabled) {\n if (this.followLiveTimer) clearTimeout(this.followLiveTimer);\n if (this.followSeatTimer) clearTimeout(this.followSeatTimer);\n this.followLiveTimer = null;\n this.followSeatTimer = null;\n }\n this.paintFollowLiveButton();\n if (changed) this.opts.onFollowLiveChange?.(enabled);\n }\n\n /** Update background-tab repaint policy without rebuilding the board. */\n setKeepLiveWhileHidden(enabled: boolean | undefined): void {\n this.keepLive = enabled ?? true;\n this.opts.keepLiveWhileHidden = enabled;\n }\n\n /** Update the host fallback currency; an event/control-room currency still wins. */\n setCurrency(currency: string | undefined): void {\n this.opts.currency = currency;\n if (this.authoritativeCurrency) return;\n this.currency = currency ?? 'USD';\n if (this.ready) this.recomputeTallies();\n }\n\n /** Apply organizer chrome tokens in place without losing camera or selection. */\n setTheme(theme: ChartTheme | undefined): void {\n this.opts.theme = theme;\n if (!this.root) return;\n for (const [property, value] of Object.entries(themeVars(theme))) {\n this.root.style.setProperty(property, value);\n }\n }\n\n /** Replace the declared authority for the current token and fail closed. */\n setCapabilities(capabilities: SeatManagerOptions['capabilities']): void {\n this.opts.capabilities = capabilities;\n if (this.ready) void this.resolveChannelCapabilities();\n }\n\n /** Change proactive token-refresh policy without rebuilding the manager. */\n setTokenRefresh(onTokenRefresh: SeatManagerOptions['onTokenRefresh']): void {\n this.opts.onTokenRefresh = onTokenRefresh;\n this.scheduleTokenRefresh();\n }\n\n /** Change the current-vs-previous sales window and refresh the private projection. */\n setTrendWindow(windowMinutes: number): Promise<ControlRoomSnapshot> {\n const normalized = Number.isFinite(windowMinutes) ? Math.floor(windowMinutes) : 15;\n this.trendWindowMinutes = Math.max(5, Math.min(60, normalized));\n this.paintTrendWindow();\n return this.refreshControlRoom();\n }\n\n async enterFullscreen(): Promise<void> {\n if (!this.root?.requestFullscreen || this.isFullscreen()) return;\n await this.root.requestFullscreen();\n this.root.focus({ preventScroll: true });\n }\n\n async exitFullscreen(): Promise<void> {\n if (typeof document === 'undefined' || !this.isFullscreen()) return;\n await document.exitFullscreen();\n }\n\n isFullscreen(): boolean {\n return typeof document !== 'undefined' && document.fullscreenElement === this.root;\n }\n\n private toggleFullscreen(): void {\n const request = this.isFullscreen() ? this.exitFullscreen() : this.enterFullscreen();\n void request.catch((err) => this.opts.onError?.(err));\n }\n\n /** Rotate the delegated credential without rebuilding DOM, canvas or socket. */\n setToken(token: EventScopedManageToken, expiresAt?: number): void {\n assertBrowserManageToken(token);\n this.api.setToken(token);\n this.opts.token = token;\n this.opts.tokenExpiresAt = expiresAt;\n this.tokenExpiresAt = expiresAt ?? null;\n this.scheduleTokenRefresh();\n if (this.ready) void this.resolveChannelCapabilities();\n }\n\n private scheduleTokenRefresh(): void {\n if (this.tokenRefreshTimer) clearTimeout(this.tokenRefreshTimer);\n this.tokenRefreshTimer = null;\n const refresh = this.opts.onTokenRefresh;\n const expiresAt = this.tokenExpiresAt;\n if (this.closed || !refresh || !expiresAt || !Number.isFinite(expiresAt)) return;\n const remaining = expiresAt - Date.now();\n const lead = Math.min(120_000, Math.max(30_000, remaining * 0.2));\n const delay = Math.max(0, remaining - lead);\n this.tokenRefreshTimer = setTimeout(() => {\n this.tokenRefreshTimer = null;\n void this.rotateToken();\n }, delay);\n }\n\n private async rotateToken(): Promise<void> {\n if (this.closed || this.tokenRefreshInFlight || !this.opts.onTokenRefresh) return;\n this.tokenRefreshInFlight = true;\n try {\n const next = await this.opts.onTokenRefresh();\n if (!next?.token || !Number.isFinite(next.expiresAt)) throw new Error('invalid_token_refresh_result');\n this.setToken(next.token, next.expiresAt);\n } catch (err) {\n this.opts.onError?.(err);\n if (!this.closed) {\n this.tokenRefreshTimer = setTimeout(() => {\n this.tokenRefreshTimer = null;\n void this.rotateToken();\n }, 30_000);\n }\n } finally {\n this.tokenRefreshInFlight = false;\n }\n }\n\n /** Bulk block the given labels (or the current selection when omitted). */\n async block(labels?: string[], opts: { releaseAt?: number; reason?: string } = {}): Promise<void> {\n const targets = (labels ?? this.selectionLabels()).filter((l) => this.status.get(l) === 'free');\n if (!targets.length) return;\n const releaseAt = opts.releaseAt ?? this.releaseAt ?? undefined;\n // optimistic\n this.setSeatsLocal(targets, 'blocked');\n try {\n await this.api.block(this.key, targets, { ...opts, releaseAt });\n this.clearSelection();\n this.done('block', targets, releaseAt\n ? `Blocked ${targets.length} — auto-release ${new Date(releaseAt).toLocaleString()}.`\n : `Blocked ${targets.length} seat${targets.length === 1 ? '' : 's'}.`);\n } catch (err) {\n this.setSeatsLocal(targets, 'free'); // revert\n this.toastErr(err instanceof ManageApiError && err.status === 409\n ? 'Some seats were just taken. Try again.'\n : \"Couldn't block those seats.\");\n this.opts.onError?.(err);\n }\n }\n\n async unblock(labels?: string[]): Promise<void> {\n const targets = (labels ?? this.selectionLabels()).filter((l) => this.status.get(l) === 'blocked');\n if (!targets.length) return;\n this.setSeatsLocal(targets, 'free');\n try {\n await this.api.unblock(this.key, targets);\n this.clearSelection();\n this.done('unblock', targets, `Unblocked ${targets.length} seat${targets.length === 1 ? '' : 's'}.`);\n } catch (err) {\n this.setSeatsLocal(targets, 'blocked');\n this.toastErr(\"Couldn't unblock those seats.\");\n this.opts.onError?.(err);\n }\n }\n\n async unblockAll(): Promise<void> {\n const blocked = [...this.status.entries()].filter(([, s]) => s === 'blocked').map(([l]) => l);\n if (!blocked.length) return;\n this.setSeatsLocal(blocked, 'free');\n try {\n const res = await this.api.unblockAll(this.key);\n this.clearSelection();\n this.done('unblockAll', blocked, `Unblocked ${res.freed} seat${res.freed === 1 ? '' : 's'}.`);\n } catch (err) {\n await this.resnapshot();\n this.toastErr(\"Couldn't mark everything for sale.\");\n this.opts.onError?.(err);\n }\n }\n\n /** Cancel bookings (BOOKED → free), guarded by the original booking ref. */\n async cancelBooking(labels: string[], bookingRef: string): Promise<void> {\n const targets = labels.filter((l) => this.status.get(l) === 'booked');\n if (!targets.length || !bookingRef) return;\n this.setSeatsLocal(targets, 'free');\n try {\n await this.api.unbook(this.key, targets, bookingRef);\n this.clearSelection();\n this.done('cancelBooking', targets, `Released ${targets.length} booked unit${targets.length === 1 ? '' : 's'}.`);\n } catch (err) {\n this.setSeatsLocal(targets, 'booked');\n this.toastErr(\"Couldn't release that booked inventory. Check the booking reference.\");\n this.opts.onError?.(err);\n }\n }\n\n selectAll(): ExpandedSeat[] {\n const seats = this.renderer?.selectAllSelectable() ?? [];\n this.syncSelection();\n return seats;\n }\n\n selectSection(sectionId: string): ExpandedSeat[] {\n if (!this.renderer) return [];\n const seats = this.renderer.getSelectableInSection(sectionId);\n this.renderer.selectByLabels(seats.map((s) => s.label));\n this.syncSelection();\n return this.renderer.getSelection();\n }\n\n selectByLabels(labels: string[]): ExpandedSeat[] {\n const seats = this.renderer?.selectByLabels(labels) ?? [];\n this.syncSelection();\n return seats;\n }\n\n clearSelection(): void {\n this.renderer?.clearSelection();\n this.syncSelection();\n }\n\n getSelection(): ExpandedSeat[] {\n return this.renderer?.getSelection() ?? [];\n }\n\n getReport(): Promise<ReportResult> {\n return this.api.report(this.key).then((report) => {\n this.applyReportRevenue(report);\n return report;\n });\n }\n\n getControlRoomSnapshot(windowMinutes = this.trendWindowMinutes): Promise<ControlRoomSnapshot> {\n return this.setTrendWindow(windowMinutes);\n }\n\n /**\n * The realtime link's current state and the \"as of\" behind it.\n *\n * Pair with `onConnectionChange` for the edges: a host that mounts after a\n * drop, or re-reads on tab focus, needs to be able to ASK rather than wait\n * for the next transition that may never come.\n */\n getConnection(): SeatManagerConnection {\n return { status: this.connectionStatus, lastMessageAt: this.lastMessageAt };\n }\n\n getLog(opts: { limit?: number; before?: number } = {}): Promise<{ entries: LogEntry[]; nextBefore: number | null }> {\n return this.api.log(this.key, opts);\n }\n\n async setHoldTtl(ms: number | null): Promise<void> {\n try {\n await this.api.setHoldTtl(this.key, ms);\n this.done('setHoldTtl', [], ms ? `Hold window set to ${Math.round(ms / 60000)} min.` : 'Hold window reset.');\n } catch (err) {\n this.toastErr(\"Couldn't update the hold window.\");\n this.opts.onError?.(err);\n }\n }\n\n zoomToFit(): void {\n this.renderer?.clearSectionFocus();\n this.renderer?.zoomToFit();\n }\n\n destroy(): void {\n this.closed = true;\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n if (this.feedTimer) clearInterval(this.feedTimer);\n if (this.toastTimer) clearTimeout(this.toastTimer);\n if (this.liveEventTimer) clearTimeout(this.liveEventTimer);\n if (this.kpiCleanupTimer) clearTimeout(this.kpiCleanupTimer);\n if (this.followLiveTimer) clearTimeout(this.followLiveTimer);\n if (this.followSeatTimer) clearTimeout(this.followSeatTimer);\n if (this.unblockAllConfirmTimer) clearTimeout(this.unblockAllConfirmTimer);\n if (this.paintHandle !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(this.paintHandle);\n }\n this.paintHandle = null;\n this.channels?.destroy();\n this.channels = null;\n // A load still in flight is not cancellable, but `this.closed` makes its\n // continuation a no-op — so drop the memo rather than leaving a settled\n // promise that would make a later `ensureChannels()` resolve into nothing.\n this.channelsLoading = null;\n if (this.tokenRefreshTimer) clearTimeout(this.tokenRefreshTimer);\n this.layoutObserver?.disconnect();\n this.layoutObserver = null;\n this.root?.removeEventListener('keydown', this.onKeyDown);\n this.els.rail?.removeEventListener('click', this.onRailClick);\n if (typeof document !== 'undefined') document.removeEventListener('fullscreenchange', this.onFullscreenChange);\n if (this.ws) { try { this.ws.close(); } catch { /* ignore */ } this.ws = null; }\n this.renderer?.destroy();\n this.renderer = null;\n this.organizerAssetUrls.dispose();\n if (this.root && this.root.parentNode === this.host) this.host.removeChild(this.root);\n }\n\n // ---- renderer lifecycle ---------------------------------------------------\n\n private buildRenderer(): void {\n if (!this.doc) return;\n const bulk = this.isBulkSelectMode();\n this.renderer = new SeatmapRenderer(this.mapHost, {\n manageMode: true,\n marqueeSelect: bulk,\n maxSelection: 1_000_000,\n selectableStatuses: this.selectableStatuses(),\n currency: this.currency,\n onSelect: (seat) => this.handleSeatSelect(seat),\n onDeselect: () => this.syncSelection(),\n onMarquee: () => this.syncSelection(),\n onSectionTap: (sectionId) => {\n this.renderer?.focusSection(sectionId);\n this.channels?.handleSectionFocus(sectionId);\n },\n onViewChange: () => { this.updateZoomHint(); this.channels?.handleViewChange(); },\n });\n this.renderer.setChart(this.doc);\n this.repaintAll();\n this.applyHeatOverlay();\n this.updateZoomHint();\n }\n\n /** Block always uses a marquee. Channels only enables its marquee after the\n * organizer deliberately chooses Assign seats; Pan map keeps desktop drag\n * available for large charts. */\n private isBulkSelectMode(): boolean {\n return this.mode === 'block' || (this.mode === 'channels' && this.channels?.usesMarqueeSelection() === true);\n }\n\n /**\n * Block never touches held or booked inventory, so it cannot select it.\n * Channels must be able to select it — the Review sheet's honesty depends on\n * counting the held and sold units inside a marquee and saying they will not\n * move, rather than silently omitting them from the selection.\n */\n private selectableStatuses(): SeatStatus[] {\n if (this.mode === 'block') return ['free', 'not_for_sale'];\n if (this.mode === 'inspect' || this.isBulkSelectMode()\n || (this.mode === 'channels' && this.channels?.canSelect() === true)) {\n return ['free', 'held', 'booked', 'not_for_sale'];\n }\n return [];\n }\n\n private updateRendererInteraction(): void {\n const bulk = this.isBulkSelectMode();\n this.renderer?.setManageInteraction({\n manageMode: true,\n marqueeSelect: bulk,\n maxSelection: 1_000_000,\n selectableStatuses: this.selectableStatuses(),\n });\n this.updateZoomHint();\n }\n\n private handleSeatSelect(seat: ExpandedSeat): void {\n if (this.mode === 'inspect') {\n const others = this.getSelection()\n .filter((selected) => selected.id !== seat.id)\n .map((selected) => selected.id);\n if (others.length) this.renderer?.deselect(others);\n }\n this.syncSelection();\n }\n\n /**\n * Build the client's inventory universe from the chart.\n *\n * `expandChart` yields SEATS — it has no output for a GA area, whose capacity\n * is sold as N synthetic unit labels. The server's seat map keys, its deltas\n * and its `totals` all speak those labels, so a client that only knows seats\n * counts GA sales in the numerator (every key of the snapshot is written into\n * `status`) while leaving them out of the denominator. Registering the GA\n * units here — labels only, never a render binding — is what makes the two\n * agree.\n */\n private buildUnitUniverse(doc: ChartDoc): void {\n for (const seat of expandChart(doc)) {\n this.labelToId.set(seat.label, seat.id);\n this.labelToSeat.set(seat.label, seat);\n this.allIds.push(seat.id);\n }\n for (const area of gaAreasOf(doc)) {\n for (const label of gaUnitLabels(area)) {\n // A GA unit never shadows a seat label, and a joined area's provenance\n // can name the same unit twice across segments — the Set settles both.\n if (!this.labelToId.has(label)) this.gaUnitLabelSet.add(label);\n }\n }\n }\n\n /** Every sellable unit the client knows: seats + GA capacity. */\n private unitTotal(): number {\n return this.allIds.length + this.gaUnitLabelSet.size;\n }\n\n /** Every label the client models, whether or not it can be painted. */\n private knownLabels(): Iterable<string> {\n return [...this.labelToId.keys(), ...this.gaUnitLabelSet];\n }\n\n private repaintAll(): void {\n const r = this.renderer;\n if (!r) return;\n if (this.allIds.length) r.setStatus(this.allIds, 'free');\n const byStatus: Record<SeatStatus, string[]> = { free: [], held: [], booked: [], not_for_sale: [] };\n for (const [label, st] of this.status.entries()) {\n const id = this.labelToId.get(label);\n if (id) byStatus[toRenderStatus(st)].push(id);\n }\n (['held', 'booked', 'not_for_sale'] as SeatStatus[]).forEach((st) => {\n if (byStatus[st].length) r.setStatus(byStatus[st], st);\n });\n }\n\n // ---- realtime -------------------------------------------------------------\n\n /**\n * Open the cockpit's realtime socket AS THE ORGANIZER.\n *\n * The scope has to be established before the upgrade, because a browser\n * `WebSocket` cannot send an Authorization header: the manage token is traded\n * over HTTPS for a one-use ticket which rides in `Sec-WebSocket-Protocol`.\n * Without it the server treats this socket as an anonymous public buyer and\n * projects its deltas, so any change inside a private channel allocation is\n * structurally suppressed and the map silently drifts.\n *\n * If the mint fails, remain reconnecting. An unticketed socket is a buyer\n * projection, so applying it to organizer state would be worse than staying\n * visibly offline while the host refreshes authority or upgrades the API.\n */\n private async connect(): Promise<void> {\n if (this.closed) return;\n let protocols: string[];\n try {\n protocols = (await this.withAuthRetry(() => this.api.subscribeTicket(this.key))).protocols;\n if (!protocols.length) throw new Error('manage_subscribe_ticket_missing');\n } catch (err) {\n this.setLive(false);\n this.opts.onError?.(err);\n this.scheduleReconnect();\n return;\n }\n if (this.closed) return;\n let ws: WebSocket;\n try {\n ws = new WebSocket(this.api.socketUrl(this.key), protocols);\n } catch (err) {\n this.opts.onError?.(err);\n this.scheduleReconnect();\n return;\n }\n this.ws = ws;\n ws.onopen = () => {\n this.attempt = 0;\n this.setLive(true);\n // Connect (and every reconnect) is where the server's own totals, booked\n // value and section metrics are re-established. Between connects the\n // delta stream carries both counts and configured value, so nothing polls.\n void this.resnapshot()\n .then(() => this.refreshControlRoom())\n .catch((err) => this.opts.onError?.(err));\n void this.refreshAvailability();\n };\n ws.onmessage = (e) => this.onMessage(e);\n ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.setLive(false);\n this.scheduleReconnect();\n };\n ws.onerror = () => { try { ws.close(); } catch { /* ignore */ } };\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n const delay = Math.min(1000 * 2 ** Math.min(this.attempt++, 5), 15000);\n this.reconnectTimer = setTimeout(() => { this.reconnectTimer = null; void this.connect(); }, delay);\n }\n\n private onMessage(e: MessageEvent): void {\n let msg: unknown;\n try {\n msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n } catch {\n return;\n }\n if (!msg || typeof msg !== 'object') return;\n // Stamped here, after parsing: unreadable frames prove the socket is open\n // but prove nothing about the numbers, and \"as of\" must mean the data.\n this.lastMessageAt = Date.now();\n const m = msg as {\n type?: string;\n seats?: Record<string, string>;\n /** Compact (protocol 1) snapshots send the modal status once and list\n * only the seats that differ from it. Absent on legacy frames. */\n default?: string;\n changes?: { label: string; status: string }[];\n /** Canonical cumulative configured value for booked inventory. */\n bookedValue?: { gross?: number };\n /** @deprecated Older workers called booked value `revenue`. */\n revenue?: { gross?: number };\n shoppingSessions?: number;\n activeHolds?: number;\n hidden?: string[];\n closed?: string[];\n };\n // Availability state (effective hidden/closed) can ride any message and is the\n // dedicated payload of the 'hidden' broadcast — keep the Sections rail + canvas fresh.\n if (Array.isArray(m.hidden) || Array.isArray(m.closed)) {\n this.updateEffectiveAvailability(m.hidden, m.closed);\n }\n if (m.type === 'presence') {\n // Presence used to be gated on a control-room snapshot already existing,\n // which silently dropped every frame in the window right after connect —\n // the exact window the cockpit is watched in. The counts are held on their\n // own field now and merged into the snapshot whenever one lands.\n if (typeof m.shoppingSessions === 'number' && typeof m.activeHolds === 'number') {\n this.livePresence = {\n at: Date.now(),\n value: { shoppingSessions: m.shoppingSessions, activeHolds: m.activeHolds },\n };\n if (this.controlRoomSnapshot) {\n this.controlRoomSnapshot = { ...this.controlRoomSnapshot, presence: this.livePresence.value };\n this.opts.onControlRoom?.(this.controlRoomSnapshot);\n }\n this.lastSyncedAt = Date.now();\n this.recomputeTallies();\n this.paintMonitorInsights();\n }\n return;\n }\n if (m.type === 'hidden') return;\n if (m.seats && typeof m.seats === 'object') {\n this.applySnapshot(m.seats, typeof m.default === 'string' ? m.default : undefined);\n } else if (Array.isArray(m.changes)) {\n const ids: string[] = [];\n const groups = new Map<string, { labels: string[]; verb: string; status: DoStatus }>();\n for (const ch of m.changes) {\n const st = (['free', 'held', 'booked', 'blocked'].includes(ch.status) ? ch.status : 'free') as DoStatus;\n const prev = this.status.get(ch.label) ?? 'free';\n if (prev === st) continue;\n this.setStatusLabel(ch.label, st, prev);\n const id = this.labelToId.get(ch.label);\n if (id) { this.renderer?.setStatus([id], toRenderStatus(st)); ids.push(id); }\n const verb = this.verbFor(prev, st);\n const groupKey = `${verb}:${st}`;\n const group = groups.get(groupKey) ?? { labels: [], verb, status: st };\n group.labels.push(ch.label);\n groups.set(groupKey, group);\n }\n for (const group of groups.values()) {\n const activity = this.pushActivity(group.labels, group.verb, group.status);\n if (activity) this.paintSpatialActivity(activity);\n }\n if (ids.length) {\n this.lastSyncedAt = Date.now();\n this.afterPaint();\n }\n // Money rides the frame now. GA-only sales register no renderer id, so a\n // refresh gated on `ids.length` never fired for them and GROSS SALES sat\n // frozen; a frame that carries the figure needs no fetch at all.\n const liveBookedValue = typeof m.bookedValue?.gross === 'number'\n ? m.bookedValue.gross\n : m.revenue?.gross;\n if (typeof liveBookedValue === 'number' && Number.isFinite(liveBookedValue)) {\n this.applyLiveGross(liveBookedValue);\n }\n this.recomputeTallies();\n }\n }\n\n /**\n * Adopt the cumulative booked gross a delta frame carried.\n *\n * Stashed with its arrival time so an in-flight control-room read can decide\n * whether it is holding the newer number: a frame that landed after the\n * request started is newer than the response, one that landed before is not.\n */\n private applyLiveGross(gross: number): void {\n this.liveGross = { at: Date.now(), value: gross };\n this.authoritativeGrossRevenue = gross;\n this.revenueStatus = 'current';\n if (this.controlRoomSnapshot) {\n const current = this.controlRoomSnapshot.bookedValue ?? this.controlRoomSnapshot.revenue;\n const bookedValue = { ...current, gross };\n this.controlRoomSnapshot = {\n ...this.controlRoomSnapshot,\n bookedValue,\n revenue: bookedValue,\n };\n this.opts.onControlRoom?.(this.controlRoomSnapshot);\n }\n }\n\n /** The single writer for a label's status, so the counters never drift. */\n private setStatusLabel(label: string, next: DoStatus, prev = this.status.get(label) ?? 'free'): void {\n this.status.set(label, next);\n if (prev === next) return;\n if (prev !== 'free') this.counts[prev] -= 1;\n if (next !== 'free') this.counts[next] += 1;\n }\n\n private async resnapshot(): Promise<void> {\n try {\n const objs = await this.api.objects(this.key);\n this.applySnapshot(objs.seats);\n this.updateEffectiveAvailability(objs.hidden, objs.closed);\n // A full snapshot over HTTP is server truth just as much as a delta is —\n // \"as of\" would otherwise ignore the freshest read the cockpit ever does.\n this.lastMessageAt = Date.now();\n } catch {\n /* transient — the delta stream keeps us fresh */\n }\n }\n\n /**\n * Replace the whole seat model.\n *\n * `fallback` is the compact frame's modal status: those snapshots list only\n * the seats that DIFFER from it, so every other known label takes it. Without\n * this the omitted majority would silently fall back to `free` — fine when\n * the mode really is free, wrong the moment it is not.\n */\n private applySnapshot(seats: Record<string, string>, fallback?: string): void {\n const known = (st: string): DoStatus =>\n (['free', 'held', 'booked', 'blocked'].includes(st) ? st : 'free') as DoStatus;\n const next = new Map<string, DoStatus>();\n if (fallback !== undefined) {\n const base = known(fallback);\n // GA units take the modal status too — they are inventory the server sells.\n for (const label of this.knownLabels()) next.set(label, base);\n }\n for (const [label, st] of Object.entries(seats)) {\n next.set(label, known(st));\n }\n this.status = next;\n this.modelVersion += 1;\n this.recountAll();\n this.lastSyncedAt = Date.now();\n this.repaintAll();\n this.afterPaint();\n this.recomputeTallies();\n }\n\n /** The one O(n) walk left: a wholesale model replacement re-bases the counters. */\n private recountAll(): void {\n const counts: Record<Exclude<DoStatus, 'free'>, number> = { held: 0, booked: 0, blocked: 0 };\n for (const st of this.status.values()) if (st !== 'free') counts[st] += 1;\n this.counts = counts;\n }\n\n /** Optimistic local write shared by organizer actions. Paint and tally once,\n * even when an arena-sized operation changes hundreds of seats. */\n private setSeatsLocal(labels: string[], st: DoStatus): void {\n const ids: string[] = [];\n for (const label of labels) {\n this.setStatusLabel(label, st);\n const id = this.labelToId.get(label);\n if (id) ids.push(id);\n }\n if (ids.length) this.renderer?.setStatus(ids, toRenderStatus(st));\n this.afterPaint();\n this.recomputeTallies();\n }\n\n /** Keep the canvas painting on hidden/occluded tabs (war-room second monitor). */\n private afterPaint(): void {\n if (this.keepLive && typeof document !== 'undefined' && document.hidden) {\n this.renderer?.forceDraw();\n }\n }\n\n private activityColor(status: DoStatus): string {\n return status === 'held' ? '#f4b740'\n : status === 'booked' ? '#22a06b'\n : status === 'blocked' ? '#8b94ac'\n : '#6e7bff';\n }\n\n private sectionsForLabels(labels: string[]): { ids: string[]; labels: string[] } {\n const ids = new Set<string>();\n for (const label of labels) {\n const seat = this.labelToSeat.get(label);\n if (!seat) continue;\n const sectionId = this.sectionByObject.get(seat.rowId);\n if (sectionId && sectionId !== UNGROUPED_ID) ids.add(sectionId);\n }\n const sectionIds = [...ids];\n return {\n ids: sectionIds,\n labels: sectionIds.map((id) => this.sectionLabelById.get(id) ?? id),\n };\n }\n\n private pulseSeatLabels(labels: string[], status: DoStatus): void {\n const color = this.activityColor(status);\n for (const label of labels.slice(0, MAX_LIVE_SEAT_PULSES)) {\n const id = this.labelToId.get(label);\n if (id) this.renderer?.flashSeat(id, color);\n }\n }\n\n /** Render one grouped realtime operation at the right semantic zoom level. */\n private paintSpatialActivity(activity: SeatManagerActivity): void {\n const sectionIds = activity.sectionIds ?? this.sectionsForLabels(activity.labels).ids;\n const focused = this.renderer?.getFocusedSection() ?? null;\n const followable = this.followLive && sectionIds.length === 1 &&\n (activity.status === 'held' || activity.status === 'booked');\n\n if (followable && focused === sectionIds[0]) {\n this.pulseSeatLabels(activity.labels, activity.status);\n return;\n }\n if (followable) {\n if (this.followLiveTimer) clearTimeout(this.followLiveTimer);\n if (this.followSeatTimer) clearTimeout(this.followSeatTimer);\n this.followLiveTimer = setTimeout(() => {\n this.followLiveTimer = null;\n this.renderer?.focusSection(sectionIds[0]);\n this.followSeatTimer = setTimeout(() => {\n this.followSeatTimer = null;\n this.pulseSeatLabels(activity.labels, activity.status);\n }, 520);\n }, 220);\n return;\n }\n\n if (!focused && sectionIds.length) {\n const color = this.activityColor(activity.status);\n for (const sectionId of sectionIds.slice(0, MAX_LIVE_SECTION_PULSES)) {\n this.renderer?.flashSection(sectionId, color);\n }\n return;\n }\n if (!sectionIds.length || (focused && sectionIds.includes(focused))) {\n this.pulseSeatLabels(activity.labels, activity.status);\n }\n }\n\n private locateSection(sectionId: string): void {\n this.renderer?.focusSection(sectionId);\n }\n\n private locateActivity(activityId: string): void {\n const activity = this.feed.find((item) => item.id === activityId);\n if (!activity) return;\n const sectionIds = activity.sectionIds ?? this.sectionsForLabels(activity.labels).ids;\n if (this.followSeatTimer) clearTimeout(this.followSeatTimer);\n if (sectionIds.length === 1) {\n this.locateSection(sectionIds[0]);\n this.followSeatTimer = setTimeout(() => {\n this.followSeatTimer = null;\n this.pulseSeatLabels(activity.labels, activity.status);\n }, 520);\n return;\n }\n this.zoomToFit();\n this.followSeatTimer = setTimeout(() => {\n this.followSeatTimer = null;\n if (sectionIds.length) {\n const color = this.activityColor(activity.status);\n for (const sectionId of sectionIds.slice(0, MAX_LIVE_SECTION_PULSES)) {\n this.renderer?.flashSection(sectionId, color);\n }\n } else {\n this.pulseSeatLabels(activity.labels, activity.status);\n }\n }, 280);\n }\n\n private showLiveEvent(activity: SeatManagerActivity): void {\n const element = this.els.liveevent;\n if (!element) return;\n const sections = activity.sectionLabels ?? [];\n const place = sections.length === 1 ? sections[0]\n : sections.length > 1 ? `${sections.length} sections`\n : activity.label;\n const noun = activity.count === 1 ? 'seat' : 'seats';\n element.innerHTML = `<span class=\"slm-liveeventdot\" style=\"background:${this.activityColor(activity.status)}\"></span>\n <span class=\"slm-liveeventcopy\">${esc(place)} · ${activity.count.toLocaleString()} ${noun} ${esc(activity.verb)}</span>\n <span class=\"slm-liveeventhint\">Live</span>`;\n element.classList.add('on');\n if (this.liveEventTimer) clearTimeout(this.liveEventTimer);\n this.liveEventTimer = setTimeout(() => {\n this.liveEventTimer = null;\n element.classList.remove('on');\n element.innerHTML = '';\n }, 2800);\n }\n\n // ---- tallies + feed -------------------------------------------------------\n\n private applyReportRevenue(report: ReportResult): void {\n this.authoritativeGrossRevenue = report.report.byCategory.reduce(\n (sum, row) => {\n const value = Number.isFinite(row.bookedValue) ? row.bookedValue : row.bookedRevenue;\n return sum + (Number.isFinite(value) ? value : 0);\n },\n 0,\n );\n this.revenueStatus = 'current';\n this.recomputeTallies();\n }\n\n /**\n * Read the server's own control-room projection.\n *\n * Called on mount, on every socket (re)connect and after an organizer action —\n * never on a timer and never per delta frame. Presence and gross that arrived\n * on the socket AFTER this request started are newer than the response, so\n * they survive it; anything older defers to the read.\n */\n private async refreshControlRoom(): Promise<ControlRoomSnapshot> {\n const request = ++this.revenueRequest;\n const requestedAt = Date.now();\n try {\n const fetched = await this.api.controlRoom(this.key, this.trendWindowMinutes);\n // A custom ManageApi-compatible host or one-window-old worker can still\n // supply only `revenue`. Normalize again at the widget boundary so the\n // canonical runtime contract does not depend on the concrete client.\n const incoming = fetched.bookedValue ?? fetched.revenue ?? { gross: 0, bySection: [] };\n const normalizedSections = (incoming.bySection ?? []).map((row) => {\n const value = Number.isFinite(row.bookedValue) ? row.bookedValue : row.bookedRevenue;\n return { ...row, bookedValue: value ?? 0, bookedRevenue: value ?? 0 };\n });\n const canonical = { ...incoming, bySection: normalizedSections };\n let snapshot = { ...fetched, bookedValue: canonical, revenue: canonical };\n if (request === this.revenueRequest) {\n if (this.livePresence && this.livePresence.at >= requestedAt) {\n snapshot = { ...snapshot, presence: this.livePresence.value };\n } else {\n this.livePresence = null;\n }\n if (this.liveGross && this.liveGross.at >= requestedAt) {\n const bookedValue = { ...snapshot.bookedValue, gross: this.liveGross.value };\n snapshot = { ...snapshot, bookedValue, revenue: bookedValue };\n } else {\n this.liveGross = null;\n }\n this.controlRoomSnapshot = snapshot;\n this.rebaseServerTotals(snapshot);\n this.lastSyncedAt = Date.now();\n this.authoritativeGrossRevenue = snapshot.bookedValue.gross;\n this.authoritativeCurrency = snapshot.currency;\n this.currency = snapshot.currency;\n this.revenueStatus = 'current';\n this.recomputeTallies();\n this.applyHeatOverlay();\n this.paintMonitorInsights();\n this.opts.onControlRoom?.(snapshot);\n }\n // The host is handed the same object the cockpit adopted — a public\n // getter that disagreed with `onControlRoom` would be its own defect.\n return snapshot;\n } catch (err) {\n if (request === this.revenueRequest) {\n this.revenueStatus = 'stale';\n this.recomputeTallies();\n }\n throw err;\n }\n }\n\n /** Pin the server's totals to the client model they were read against. */\n private rebaseServerTotals(snapshot: ControlRoomSnapshot): void {\n const totals = snapshot.totals;\n if (!totals || ['free', 'held', 'booked', 'blocked'].some(\n (key) => !Number.isFinite((totals as unknown as Record<string, number>)[key]),\n )) {\n this.serverBaseline = null;\n return;\n }\n this.serverBaseline = {\n model: this.modelVersion,\n server: { free: totals.free, held: totals.held, booked: totals.booked, blocked: totals.blocked },\n client: this.clientTallies(),\n };\n }\n\n /** What the client's own model says — GA units included since `render()`. */\n private clientTallies(): { free: number; held: number; booked: number; blocked: number } {\n const { held, booked, blocked } = this.counts;\n // The snapshot only carries non-free, so free is what is left over.\n return { held, booked, blocked, free: Math.max(0, this.unitTotal() - held - booked - blocked) };\n }\n\n /**\n * The numbers the KPI bar and rail render.\n *\n * The server is the authority: its totals land exactly as read, and the\n * delta-driven client model carries them forward until the next read. Before\n * the first snapshot — and after a wholesale model replacement invalidates the\n * pairing — the client model stands alone.\n */\n private buildTallies(): SeatManagerTallies {\n const client = this.clientTallies();\n const baseline = this.serverBaseline?.model === this.modelVersion ? this.serverBaseline : null;\n const of = (key: 'free' | 'held' | 'booked' | 'blocked'): number => (baseline\n ? Math.max(0, baseline.server[key] + (client[key] - baseline.client[key]))\n : client[key]);\n const seatTotal = this.controlRoomSnapshot?.event?.seatTotal;\n const t: SeatManagerTallies = {\n free: of('free'), held: of('held'), booked: of('booked'), blocked: of('blocked'),\n total: Number.isFinite(seatTotal) ? (seatTotal as number) : this.unitTotal(),\n capacityPct: 0,\n sellThroughPct: 0,\n bookedValue: this.authoritativeGrossRevenue,\n grossRevenue: this.authoritativeGrossRevenue,\n bookedValueStatus: this.revenueStatus,\n revenueStatus: this.revenueStatus,\n currency: this.currency,\n };\n t.capacityPct = t.total ? Math.round((t.booked / t.total) * 100) : 0;\n const sellable = t.total - t.blocked;\n t.sellThroughPct = sellable > 0 ? Math.round((t.booked / sellable) * 100) : 0;\n return t;\n }\n\n /**\n * Queue one KPI/rail repaint for this burst of changes.\n *\n * A delta frame can carry hundreds of seats and `paintKpis` rebuilds eight\n * nodes from scratch, so painting per change is what made an arena-sized\n * frame expensive. Coalescing on a frame keeps the burst to a single rebuild;\n * without `requestAnimationFrame` (SSR, an older test env) it paints inline\n * rather than dropping the update.\n */\n private recomputeTallies(): void {\n if (this.closed) return;\n if (typeof requestAnimationFrame !== 'function') { this.flushTallies(); return; }\n if (this.paintHandle !== null) return;\n this.paintHandle = requestAnimationFrame(() => {\n this.paintHandle = null;\n this.flushTallies();\n });\n }\n\n private flushTallies(): void {\n if (this.closed) return;\n const t = this.buildTallies();\n this.paintKpis(t);\n if (this.mode === 'view') {\n this.paintLegend(t);\n this.paintMonitorInsights();\n } else if (this.mode === 'inspect') this.renderInspectRail(this.getSelection());\n else if (this.mode === 'block') this.paintSelBar(this.getSelection());\n else if (this.mode === 'channels') this.channels?.handleSelectionChange();\n this.opts.onTallies?.(t);\n }\n\n private verbFor(prev: DoStatus, next: DoStatus): string {\n if (next === 'held') return 'held';\n if (next === 'booked') return 'booked';\n if (next === 'blocked') return 'blocked';\n if (next === 'free') return prev === 'blocked' ? 'unblocked' : prev === 'booked' ? 'cancelled' : 'released';\n return next;\n }\n\n private pushActivity(labels: string[], verb: string, status: DoStatus, at = Date.now()): SeatManagerActivity | null {\n const label = labels[0];\n if (!label) return null;\n const sections = this.sectionsForLabels(labels);\n const item: SeatManagerActivity = {\n id: `${label}:${at}:${Math.random().toString(36).slice(2, 6)}`,\n at,\n label,\n labels: [...labels],\n count: labels.length,\n verb,\n status,\n sectionIds: sections.ids,\n sectionLabels: sections.labels,\n };\n this.feed.unshift(item);\n if (this.feed.length > FEED_CAP) this.feed.length = FEED_CAP;\n if (this.mode === 'view') this.paintFeed();\n this.showLiveEvent(item);\n this.opts.onActivity?.(item);\n return item;\n }\n\n private seedFeed(entries: ControlRoomActivityEntry[]): void {\n const verbByAction: Record<string, string> = {\n hold: 'held', book: 'booked', release: 'released', expire: 'expired', block: 'blocked', unblock: 'unblocked',\n unbook: 'cancelled',\n };\n const stByAction: Record<string, DoStatus> = {\n hold: 'held', book: 'booked', release: 'free', expire: 'free', block: 'blocked', unblock: 'free', unbook: 'free',\n };\n for (const e of entries) {\n const label = e.labels[0];\n if (!label) continue;\n const sections = this.sectionsForLabels(e.labels);\n const item: SeatManagerActivity = {\n id: `log:${e.id}`,\n at: e.at,\n label,\n labels: [...e.labels],\n count: e.labels.length,\n verb: verbByAction[e.action] ?? e.action,\n status: stByAction[e.action] ?? 'free',\n sectionIds: sections.ids,\n sectionLabels: sections.labels,\n };\n this.feed.push(item);\n this.opts.onActivity?.(item);\n }\n this.feed.sort((a, b) => b.at - a.at);\n if (this.feed.length > FEED_CAP) this.feed.length = FEED_CAP;\n if (this.mode === 'view') this.paintFeed();\n }\n\n private startFeedClock(): void {\n this.feedTimer = setInterval(() => {\n if (this.mode === 'view') {\n this.paintFeed();\n this.paintMonitorInsights();\n }\n }, 10000);\n }\n\n // ---- selection ------------------------------------------------------------\n\n private selectionLabels(): string[] {\n return this.getSelection().map((s) => s.label);\n }\n\n private syncSelection(): void {\n const seats = this.getSelection();\n if (this.mode === 'block') this.paintSelBar(seats);\n else if (this.mode === 'inspect') this.renderInspectRail(seats);\n else if (this.mode === 'channels') this.channels?.handleSelectionChange();\n this.opts.onSelectionChange?.(seats);\n }\n\n // ---- DOM: chrome ----------------------------------------------------------\n\n private buildChrome(): void {\n const root = document.createElement('div');\n root.className = 'slm';\n root.tabIndex = 0;\n root.setAttribute('role', 'region');\n root.setAttribute('aria-label', 'SeatLayer live control room');\n const vars = themeVars(this.opts.theme);\n for (const [k, v] of Object.entries(vars)) root.style.setProperty(k, v);\n root.innerHTML = `\n <div class=\"slm-bar\">\n <div class=\"slm-modes\" data-ref=\"modes\" role=\"tablist\" aria-label=\"Manager tools\">\n <button class=\"slm-mode\" role=\"tab\" data-mode=\"view\" title=\"Monitor (M)\" aria-keyshortcuts=\"M\">Monitor</button>\n <button class=\"slm-mode\" role=\"tab\" data-mode=\"inspect\" title=\"Inspect (I)\" aria-keyshortcuts=\"I\">Inspect</button>\n <button class=\"slm-mode\" role=\"tab\" data-mode=\"block\" title=\"Block (B)\" aria-keyshortcuts=\"B\">Block</button>\n <button class=\"slm-mode\" role=\"tab\" data-mode=\"sections\" title=\"Sections (S)\" aria-keyshortcuts=\"S\">Sections</button>\n <button class=\"slm-mode\" role=\"tab\" data-mode=\"channels\" title=\"Channels (C)\" aria-keyshortcuts=\"C\" hidden>Channels</button>\n </div>\n <select class=\"slm-tools\" data-ref=\"tools\" aria-label=\"Manager tools\"></select>\n <span class=\"slm-live\"><span class=\"slm-live-dot\"></span><span data-ref=\"livetext\">CONNECTING</span></span>\n <div class=\"slm-bar-actions\">\n <button class=\"slm-barbtn follow\" data-ref=\"follow\" aria-pressed=\"false\"\n title=\"Stay on the current map view unless enabled\">Follow live</button>\n <button class=\"slm-barbtn\" data-ref=\"heat\" aria-pressed=\"false\"\n aria-label=\"Booking momentum overlay off\"\n title=\"Highlight sections booking fastest in the selected time window\">Booking momentum</button>\n <button class=\"slm-barbtn\" data-ref=\"fullscreen\" title=\"Full screen (F)\" aria-keyshortcuts=\"F\">Full screen</button>\n </div>\n <div class=\"slm-kpis\" data-ref=\"kpis\"></div>\n </div>\n <div class=\"slm-body\">\n <div class=\"slm-map\">\n <div class=\"slm-map-host\" data-ref=\"maphost\"></div>\n <div class=\"slm-zoomhint\" data-ref=\"zoomhint\">Zoom in to marquee-select</div>\n <div class=\"slm-liveevent\" data-ref=\"liveevent\" role=\"status\" aria-live=\"polite\"></div>\n <div class=\"slm-hud\"><button class=\"slm-hud-chip\" data-ref=\"zfit\">Zoom to fit</button></div>\n </div>\n <aside class=\"slm-rail\"><div class=\"slm-railscroll\" data-ref=\"rail\"></div></aside>\n </div>\n <div class=\"slm-toast\" data-ref=\"toast\"></div>\n `;\n this.host.appendChild(root);\n this.root = root;\n this.updateContainerLayout();\n if (typeof ResizeObserver !== 'undefined') {\n this.layoutObserver = new ResizeObserver(() => this.updateContainerLayout());\n this.layoutObserver.observe(root);\n }\n const ref = (n: string) => root.querySelector(`[data-ref=\"${n}\"]`) as HTMLElement;\n this.mapHost = ref('maphost') as HTMLDivElement;\n this.els = {\n modes: ref('modes'), tools: ref('tools'), livetext: ref('livetext'), kpis: ref('kpis'),\n follow: ref('follow'), heat: ref('heat'), fullscreen: ref('fullscreen'),\n zoomhint: ref('zoomhint'), liveevent: ref('liveevent'), rail: ref('rail'), toast: ref('toast'), zfit: ref('zfit'),\n };\n this.els.modes.querySelectorAll('[data-mode]').forEach((b) =>\n b.addEventListener('click', () => this.setMode((b as HTMLElement).dataset.mode as SeatManagerMode)));\n // Below the compact breakpoint the pills collapse into ONE accessible Tools\n // picker (§13) — never a tab strip plus a second scrolling mechanism.\n this.els.tools.addEventListener('change', () =>\n this.setMode((this.els.tools as HTMLSelectElement).value as SeatManagerMode));\n this.els.zfit.addEventListener('click', () => this.zoomToFit());\n this.els.follow.addEventListener('click', () => this.setFollowLive(!this.followLive));\n this.els.heat.addEventListener('click', () => this.setHeatOverlay(!this.heatEnabled));\n this.els.fullscreen.addEventListener('click', () => this.toggleFullscreen());\n root.addEventListener('keydown', this.onKeyDown);\n this.els.rail.addEventListener('click', this.onRailClick);\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\n this.paintModeTabs();\n this.paintFollowLiveButton();\n this.paintHeatButton();\n this.paintFullscreenButton();\n }\n\n private updateContainerLayout(): void {\n const width = this.root?.getBoundingClientRect().width || this.host.clientWidth;\n this.root?.classList.toggle('compact', width > 0 && width < 800);\n this.channels?.handleLayoutChange();\n }\n\n private sectionOptions: { id: string; label: string }[] = [];\n\n private buildSectionOptions(): void {\n if (!this.doc) return;\n try {\n const secs = computeSections(this.doc);\n this.sectionsBase = secs;\n this.sectionOptions = [];\n this.sectionByObject = new Map(secs.objectToSection);\n this.sectionLabelById.clear();\n for (const s of secs.sections) {\n this.sectionOptions.push({ id: s.id, label: s.label });\n this.sectionLabelById.set(s.id, s.label);\n }\n if (secs.ungrouped) {\n this.sectionOptions.push({ id: UNGROUPED_ID, label: secs.ungrouped.label });\n this.sectionLabelById.set(UNGROUPED_ID, secs.ungrouped.label);\n }\n } catch { /* no sections */ }\n }\n\n private paintModeTabs(): void {\n const available: Array<{ mode: SeatManagerMode; label: string }> = [];\n this.els.modes?.querySelectorAll('[data-mode]').forEach((b) => {\n const el = b as HTMLElement;\n const mode = el.dataset.mode as SeatManagerMode;\n // No channel-view capability ⇒ the pill is not rendered at all. A hidden\n // control is honest about authority; a disabled one advertises it.\n // Authority, not readiness: the pill must not wait on the lazy module.\n const permitted = mode !== 'channels' || this.channelCaps.view;\n el.hidden = !permitted;\n if (!permitted) return;\n available.push({ mode, label: el.textContent ?? mode });\n const active = mode === this.mode;\n el.classList.toggle('on', active);\n el.setAttribute('aria-selected', String(active));\n el.tabIndex = active ? 0 : -1;\n });\n const tools = this.els.tools as HTMLSelectElement | undefined;\n if (tools) {\n tools.innerHTML = available.map((entry) =>\n `<option value=\"${entry.mode}\"${entry.mode === this.mode ? ' selected' : ''}>${esc(entry.label)}</option>`).join('');\n tools.value = this.mode;\n }\n this.root?.classList.toggle('block-mode', this.mode === 'block');\n }\n\n private paintFollowLiveButton(): void {\n const button = this.els.follow;\n if (!button) return;\n button.classList.toggle('on', this.followLive);\n button.setAttribute('aria-pressed', String(this.followLive));\n button.setAttribute('title', this.followLive\n ? 'Following new holds and bookings. Turn off to keep the current view.'\n : 'Stay on the current map view. Enable to follow new holds and bookings.');\n }\n\n private paintHeatButton(): void {\n const button = this.els.heat;\n if (!button) return;\n button.classList.toggle('on', this.heatEnabled);\n button.setAttribute('aria-pressed', String(this.heatEnabled));\n button.setAttribute('aria-label', `Booking momentum overlay ${this.heatEnabled ? 'on' : 'off'}`);\n button.setAttribute('title', `${this.heatEnabled ? 'Hide' : 'Highlight'} sections booking fastest in the selected time window`);\n button.textContent = 'Booking momentum';\n this.paintMomentumHelp();\n }\n\n private paintMomentumHelp(): void {\n const help = this.els.rail?.querySelector('[data-ref=\"momentumhelp\"]') as HTMLElement | null;\n if (!help) return;\n help.hidden = !this.heatEnabled;\n const copy = help.querySelector('[data-ref=\"momentumcopy\"]');\n if (!copy) return;\n const hasRecentSales = this.controlRoomSnapshot?.velocity.bySection.some((row) => row.netBooked > 0);\n copy.textContent = hasRecentSales\n ? 'Warmer sections have more completed bookings, adjusted for section size. Holds and viewers are not counted.'\n : `No completed bookings in the last ${this.trendWindowMinutes} minutes.`;\n }\n\n private paintFullscreenButton(): void {\n if (!this.els.fullscreen) return;\n this.els.fullscreen.textContent = this.isFullscreen() ? 'Exit full screen' : 'Full screen';\n }\n\n private paintTrendWindow(): void {\n this.els.rail?.querySelectorAll('[data-window]').forEach((button) => {\n const value = Number((button as HTMLElement).dataset.window);\n button.classList.toggle('on', value === this.trendWindowMinutes);\n });\n }\n\n private setLive(on: boolean): void {\n this.root?.classList.toggle('live', on);\n if (this.els.livetext) this.els.livetext.textContent = on ? 'LIVE' : 'RECONNECTING';\n this.paintMonitorInsights();\n\n // Tell the host only on a real edge. `connect()` can call this with the\n // same value it already had (an open that follows a reconnect attempt),\n // and a banner that re-announces itself on every retry is noise.\n const next: SeatManagerConnection['status'] = on ? 'live' : 'reconnecting';\n if (next === this.connectionStatus) return;\n this.connectionStatus = next;\n try {\n this.opts.onConnectionChange?.(this.getConnection());\n } catch (err) {\n // A host callback must never take the socket down with it.\n this.opts.onError?.(err);\n }\n }\n\n private updateZoomHint(): void {\n const hint = this.els.zoomhint;\n if (!hint) return;\n const show = this.mode === 'block' && this.renderer?.getRung?.() !== 'seats';\n hint.classList.toggle('on', !!show);\n }\n\n private formatKpiDelta(key: string, delta: number, currency: string): string {\n const sign = delta > 0 ? '+' : '−';\n const absolute = Math.abs(delta);\n if (key === 'booked-value') return `${sign}${fmtMoney(absolute, currency)}`;\n if (key === 'booked-pct') return `${sign}${absolute.toLocaleString()}pt`;\n return `${sign}${absolute.toLocaleString()}`;\n }\n\n private paintKpis(t: SeatManagerTallies): void {\n if (!this.els.kpis) return;\n const bookedValue = t.bookedValueStatus === 'current' ? fmtMoney(t.bookedValue, t.currency) : '—';\n const presence = this.presenceCounts();\n // Two different units share this bar and used to be interleaved: \"Held\n // seats\" (seat units) sat next to \"Active holds\" (checkout sessions), which\n // read as the same quantity counted twice. Seat tallies are grouped, the\n // session-scale pair is grouped, and the session one is named for what it\n // is — a cart.\n const items: { key: string; raw: number | null; n: string; l: string; dot?: string; title: string }[] = [\n { key: 'booked-inventory', raw: t.booked, n: t.booked.toLocaleString(), l: 'Booked inventory', dot: '#22a06b', title: 'Inventory units booked' },\n { key: 'held-seats', raw: t.held, n: t.held.toLocaleString(), l: 'Held inventory', dot: '#f4b740', title: 'Inventory currently held' },\n { key: 'free-seats', raw: t.free, n: t.free.toLocaleString(), l: 'Available', dot: '#6e7bff', title: 'Inventory available to book' },\n { key: 'blocked', raw: t.blocked, n: t.blocked.toLocaleString(), l: 'Blocked', dot: '#8b94ac', title: 'Inventory withheld from booking' },\n { key: 'viewing-map', raw: presence?.shoppingSessions ?? null, n: presence ? presence.shoppingSessions.toLocaleString() : '—', l: 'Viewing map', title: 'Active map sessions right now' },\n { key: 'active-holds', raw: presence?.activeHolds ?? null, n: presence ? presence.activeHolds.toLocaleString() : '—', l: 'Active holds', title: 'Sessions currently holding inventory' },\n { key: 'booked-pct', raw: t.capacityPct, n: `${t.capacityPct}%`, l: 'Booked', title: 'Booked inventory as a share of the whole event' },\n { key: 'booked-value', raw: t.bookedValueStatus === 'current' ? t.bookedValue : null, n: bookedValue, l: 'Booked value', title: 'Configured value attached to booked inventory' },\n ];\n let hasChanges = false;\n this.els.kpis.innerHTML = items.map((item) => {\n const previous = this.lastKpiValues.get(item.key);\n const changed = item.raw != null && previous != null && item.raw !== previous;\n const delta = changed ? item.raw! - previous! : 0;\n if (changed) {\n hasChanges = true;\n this.activeKpiDeltas.set(item.key, {\n text: this.formatKpiDelta(item.key, delta, t.currency),\n down: delta < 0,\n });\n }\n if (item.raw != null) this.lastKpiValues.set(item.key, item.raw);\n const activeDelta = this.activeKpiDeltas.get(item.key);\n return `<div class=\"slm-kpi${activeDelta ? ' changed' : ''}\" data-kpi=\"${item.key}\" title=\"${esc(item.title)}\">\n <b>${item.dot ? `<span class=\"dot\" style=\"background:${item.dot}\"></span>` : ''}${item.n}</b><span>${item.l}</span>\n ${activeDelta ? `<span class=\"slm-kpidelta${activeDelta.down ? ' down' : ''}\">${activeDelta.text}</span>` : ''}\n </div>`;\n }).join('');\n if (hasChanges) {\n // The map above has already adopted the new values, so detect the rendered\n // change markers directly and remove their accessibility footprint after\n // the visual cue completes.\n if (this.kpiCleanupTimer) clearTimeout(this.kpiCleanupTimer);\n this.kpiCleanupTimer = setTimeout(() => {\n this.kpiCleanupTimer = null;\n this.activeKpiDeltas.clear();\n this.els.kpis?.querySelectorAll('.slm-kpidelta').forEach((element) => element.remove());\n this.els.kpis?.querySelectorAll('.slm-kpi.changed').forEach((element) => element.classList.remove('changed'));\n }, 1500);\n }\n }\n\n // ---- DOM: rails -----------------------------------------------------------\n\n private paintRail(): void {\n if (this.mode === 'view') this.renderViewRail();\n else if (this.mode === 'inspect') this.renderInspectRail(this.getSelection());\n else if (this.mode === 'sections') this.renderSectionsRail();\n else if (this.mode === 'channels') {\n // The sub-app may still be in the air (see `ensureChannels`). Say which\n // of the two it is rather than leaving the rail blank: an empty Channels\n // rail reads as \"this event has no channels\", which is a claim about\n // inventory and would be false.\n if (this.channels) this.channels.paintRail();\n else if (this.channelsLoading) {\n this.els.rail.innerHTML = '<div class=\"slm-empty\" role=\"status\">Loading sales channels…</div>';\n } else {\n this.els.rail.innerHTML = '<div class=\"slm-empty\" role=\"alert\">Sales channels could not be loaded. Switch away and back to try again.</div>';\n }\n }\n else this.renderBlockRail();\n this.updateZoomHint();\n }\n\n private renderViewRail(): void {\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">Monitor</p>\n <p class=\"slm-hint\">Read-only. Inventory, map activity and booking movement update on the same live board.</p>\n <div class=\"slm-health\" data-ref=\"presence\"></div>\n <div class=\"slm-legend\" data-ref=\"legend\"></div>\n <div class=\"slm-sectionhead\">\n <div><p class=\"slm-eyebrow\">Section inventory</p><p class=\"slm-note\">Configured booked value · booking momentum</p></div>\n <div class=\"slm-windows\" aria-label=\"Booking momentum window\">\n ${[5, 15, 30, 60].map((window) => `<button class=\"slm-window\" data-window=\"${window}\">${window}m</button>`).join('')}\n </div>\n </div>\n <div class=\"slm-momentumhelp\" data-ref=\"momentumhelp\" ${this.heatEnabled ? '' : 'hidden'}>\n <div class=\"slm-momentumscale\"><span>Warm</span><span class=\"slm-momentumgradient\"></span><span>Hot</span></div>\n <p class=\"slm-momentumcopy\" data-ref=\"momentumcopy\"></p>\n </div>\n <div class=\"slm-sectionlist\" data-ref=\"sections\"></div>\n <p class=\"slm-eyebrow\">Activity</p>\n <div class=\"slm-feed\" data-ref=\"feed\"></div>\n `;\n this.els.presence = this.els.rail.querySelector('[data-ref=\"presence\"]') as HTMLElement;\n this.els.legend = this.els.rail.querySelector('[data-ref=\"legend\"]') as HTMLElement;\n this.els.sections = this.els.rail.querySelector('[data-ref=\"sections\"]') as HTMLElement;\n this.els.feed = this.els.rail.querySelector('[data-ref=\"feed\"]') as HTMLElement;\n this.els.rail.querySelectorAll('[data-window]').forEach((button) => button.addEventListener('click', () => {\n const windowMinutes = Number((button as HTMLElement).dataset.window);\n void this.setTrendWindow(windowMinutes).catch((err) => this.opts.onError?.(err));\n }));\n this.recomputeTallies();\n this.paintMonitorInsights();\n this.paintTrendWindow();\n this.paintMomentumHelp();\n this.paintFeed();\n }\n\n /** Live presence wins over the snapshot's copy — it is the fresher channel,\n * and it exists from the first frame rather than the first fetch. */\n private presenceCounts(): { shoppingSessions: number; activeHolds: number } | null {\n return this.livePresence?.value ?? this.controlRoomSnapshot?.presence ?? null;\n }\n\n private paintMonitorInsights(): void {\n if (this.mode !== 'view') return;\n const snapshot = this.controlRoomSnapshot;\n if (this.els.presence) {\n const connected = this.root?.classList.contains('live');\n const sync = this.lastSyncedAt ? relTime(this.lastSyncedAt, Date.now()) : 'waiting';\n const presence = this.presenceCounts();\n this.els.presence.innerHTML = `\n <div class=\"slm-healthitem\" title=\"Active map sessions right now\"><b>${presence ? presence.shoppingSessions.toLocaleString() : '—'}</b><span>Viewing map</span></div>\n <div class=\"slm-healthitem\" title=\"Sessions currently holding inventory\"><b>${presence ? presence.activeHolds.toLocaleString() : '—'}</b><span>Active holds</span></div>\n <div class=\"slm-healthitem\"><b>${connected ? 'Healthy' : 'Reconnecting'}</b><span>Live connection</span></div>\n <div class=\"slm-healthitem\"><b>${sync}</b><span>Last sync</span></div>`;\n }\n if (!this.els.sections) return;\n if (!snapshot) {\n this.els.sections.innerHTML = '<div class=\"slm-empty\">Loading authoritative section metrics…</div>';\n return;\n }\n const velocity = new Map(snapshot.velocity.bySection.map((row) => [row.sectionId, row]));\n const rows = [...snapshot.bookedValue.bySection].sort((a, b) => {\n const av = velocity.get(a.sectionId)?.netBooked ?? 0;\n const bv = velocity.get(b.sectionId)?.netBooked ?? 0;\n return bv - av || b.bookedValue - a.bookedValue;\n });\n this.els.sections.innerHTML = rows.length ? rows.map((row) => {\n const speed = velocity.get(row.sectionId);\n const net = speed?.netBooked ?? 0;\n const netLabel = `${net > 0 ? '+' : ''}${net}`;\n const trend = speed?.trend === 'rising' || speed?.trend === 'cooling' ? speed.trend : 'steady';\n return `<button type=\"button\" class=\"slm-sectionrow\" data-section-focus=\"${esc(row.sectionId)}\" title=\"Focus ${esc(row.sectionLabel)} on the map\">\n <span class=\"slm-sectiontop\"><span>${esc(row.sectionLabel)}</span><span>${fmtMoney(row.bookedValue, snapshot.currency)}</span></span>\n <span class=\"slm-sectionmeta\"><span>${row.booked.toLocaleString()}/${row.total.toLocaleString()} booked · ${netLabel} in ${snapshot.velocity.windowMinutes}m</span><span class=\"slm-trend ${trend}\">${trend}</span><span class=\"slm-sectionlocate\">Locate</span></span>\n </button>`;\n }).join('') : '<div class=\"slm-empty\">No section metrics are available for this chart.</div>';\n this.paintTrendWindow();\n this.paintMomentumHelp();\n }\n\n private applyHeatOverlay(): void {\n const snapshot = this.controlRoomSnapshot;\n if (!this.heatEnabled || !snapshot) {\n this.renderer?.setSectionHeat(null);\n return;\n }\n const capacity = new Map(snapshot.bookedValue.bySection.map((row) => [row.sectionId, Math.max(1, row.total)]));\n const rates = snapshot.velocity.bySection.map((row) => ({\n sectionId: row.sectionId,\n rate: Math.max(0, row.netBooked) / (capacity.get(row.sectionId) ?? 1) / snapshot.velocity.windowMinutes,\n }));\n const max = Math.max(0, ...rates.map((row) => row.rate));\n const scores: Record<string, number> = {};\n for (const row of rates) scores[row.sectionId] = max > 0 ? Math.sqrt(row.rate / max) : 0;\n this.renderer?.setSectionHeat(scores);\n }\n\n private renderInspectRail(seats: ExpandedSeat[]): void {\n const seat = seats[seats.length - 1];\n if (!seat) {\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">Inspect seats</p>\n <p class=\"slm-hint\">Select a seat to see its availability and booking context. Nothing changes in this view.</p>\n <div class=\"slm-empty\">Select a seat on the map.</div>`;\n return;\n }\n const status = this.status.get(seat.label) ?? 'free';\n const statusLabel: Record<DoStatus, string> = { free: 'Free', held: 'Held', booked: 'Booked', blocked: 'Blocked' };\n const sectionId = this.sectionByObject.get(seat.rowId) ?? UNGROUPED_ID;\n const sectionLabel = this.sectionLabelById.get(sectionId) ?? 'Other seats';\n const category = this.doc?.categories.find((item) => item.key === seat.categoryKey);\n const sectionMetric = this.controlRoomSnapshot?.bookedValue.bySection.find((row) => row.sectionId === sectionId);\n const object = this.doc?.objects.find((item) => item.id === seat.rowId);\n const location = object?.type === 'row'\n ? { label: 'Row', value: object.label }\n : object?.type === 'table'\n ? { label: 'Table', value: object.label }\n : seat.kind === 'booth'\n ? { label: 'Type', value: 'Booth' }\n : null;\n const itemKind = seat.kind === 'booth' ? 'Booth' : 'Seat';\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">${itemKind} details</p>\n <p class=\"slm-hint\">Live availability and section performance.</p>\n <div class=\"slm-inspect-card\">\n <div class=\"slm-inspect-label\">${esc(seat.label)}</div>\n <div class=\"slm-inspect-grid\">\n <div><span>Status</span><b>${statusLabel[status]}</b></div>\n <div><span>Section</span><b>${esc(sectionLabel)}</b></div>\n ${location ? `<div><span>${location.label}</span><b>${esc(location.value)}</b></div>` : ''}\n <div><span>Category</span><b>${esc(category?.label ?? seat.categoryKey)}</b></div>\n <div><span>Booked in section</span><b>${sectionMetric ? `${sectionMetric.booked} of ${sectionMetric.total}` : '—'}</b></div>\n <div><span>Section booked value</span><b>${sectionMetric && this.controlRoomSnapshot ? fmtMoney(sectionMetric.bookedValue, this.controlRoomSnapshot.currency) : '—'}</b></div>\n </div>\n </div>`;\n }\n\n // ---- sections: availability windows --------------------------------------\n\n /** Pull the organizer's availability rules (event:view). Called on load and on\n * every WS (re)connect, mirroring how the other panels re-hydrate. `closed` is\n * deterministic from the rules; `hidden` (which folds in already-due timed /\n * threshold windows) comes from the snapshot + WS effective set. */\n private async refreshAvailability(): Promise<void> {\n try {\n const res = await this.withAuthRetry(() => this.api.availability(this.key));\n this.availabilityRules = res.rules ?? {};\n this.effectiveClosed = new Set(this.closedIdsFromRules(this.availabilityRules));\n if (this.mode === 'sections') this.renderSectionsRail();\n this.applySectionCanvasTreatment();\n } catch (err) {\n this.opts.onError?.(err);\n }\n }\n\n /** Run a token-authed op; on a 401 re-mint via onTokenRefresh and retry once. */\n private async withAuthRetry<T>(op: () => Promise<T>): Promise<T> {\n try {\n return await op();\n } catch (err) {\n if (err instanceof ManageApiError && err.status === 401 && this.opts.onTokenRefresh && !this.tokenRefreshInFlight) {\n await this.rotateToken();\n return op();\n }\n throw err;\n }\n }\n\n private closedIdsFromRules(rules: Record<string, AvailabilityRule>): string[] {\n return Object.entries(rules).filter(([, r]) => r.mode === 'closed').map(([id]) => id);\n }\n\n /** Adopt a new effective hidden/closed set (from a snapshot or WS broadcast) and\n * repaint the rail + canvas when it actually moves. */\n private updateEffectiveAvailability(hidden?: string[], closed?: string[]): void {\n let changed = false;\n if (Array.isArray(hidden)) {\n this.effectiveHidden = new Set(hidden.filter((x): x is string => typeof x === 'string'));\n changed = true;\n }\n if (Array.isArray(closed)) {\n this.effectiveClosed = new Set(closed.filter((x): x is string => typeof x === 'string'));\n changed = true;\n }\n if (!changed) return;\n if (this.mode === 'sections') this.renderSectionsRail();\n this.applySectionCanvasTreatment();\n }\n\n /** Canvas read of the availability state: dim hidden sections to a whisper,\n * half-light closed sections, leave open sections normal. Only in Sections mode;\n * cleared in every other tool. */\n private applySectionCanvasTreatment(): void {\n if (!this.renderer) return;\n if (this.mode === 'sections') {\n this.renderer.setDimmedSections([...this.effectiveHidden]);\n this.renderer.setClosedSections([...this.effectiveClosed]);\n } else {\n this.renderer.setDimmedSections(null);\n this.renderer.setClosedSections(null);\n }\n }\n\n /** Zone-grouped render tree: each zone header then its sections (which follow the\n * zone window), then loose sections + the ungrouped bucket. Effective hidden /\n * closed come from the live sets, rules from the organizer map. */\n private buildSectionRows(): { rows: SectionRow[]; hiddenSections: number; closedSections: number } {\n const base = this.sectionsBase;\n if (!base) return { rows: [], hiddenSections: 0, closedSections: 0 };\n const zones = this.doc?.zones ?? [];\n const byZone = new Map<string, SectionNode[]>();\n const loose: SectionNode[] = [];\n for (const s of base.sections) {\n if (s.zone && zones.some((z) => z.id === s.zone)) {\n const list = byZone.get(s.zone) ?? [];\n list.push(s);\n byZone.set(s.zone, list);\n } else {\n loose.push(s);\n }\n }\n const rows: SectionRow[] = [];\n let hiddenSections = 0;\n let closedSections = 0;\n const push = (\n kind: 'zone' | 'section',\n node: { id: string; label: string; seatCount: number; seatLabels: string[] },\n zoneRuled: boolean,\n parentClosed = false,\n ): void => {\n const rule = this.availabilityRules[node.id] ?? null;\n const effClosed = this.effectiveClosed.has(node.id) || parentClosed;\n // A closed section stays visible-but-off-sale, never counted as hidden.\n const effHidden = this.effectiveHidden.has(node.id) || (zoneRuled && !effClosed);\n if (kind === 'section' && effHidden) hiddenSections += 1;\n if (kind === 'section' && effClosed) closedSections += 1;\n rows.push({\n kind, id: node.id, label: node.label, seatCount: node.seatCount, seatLabels: node.seatLabels,\n rule, hidden: effHidden, closed: effClosed, followsZone: kind === 'section' && zoneRuled,\n });\n };\n for (const z of zones) {\n const secs = byZone.get(z.id);\n if (!secs || !secs.length) continue;\n const zoneNode = {\n id: z.id,\n label: z.label || 'Zone',\n seatCount: secs.reduce((sum, s) => sum + s.seatCount, 0),\n seatLabels: secs.flatMap((s) => s.seatLabels),\n };\n const zoneRuled = !!this.availabilityRules[z.id];\n const zoneClosed = this.availabilityRules[z.id]?.mode === 'closed';\n push('zone', zoneNode, false);\n for (const s of secs) push('section', s, zoneRuled, zoneClosed);\n }\n for (const s of loose) push('section', s, false);\n if (base.ungrouped) {\n const u = base.ungrouped;\n push('section', { id: UNGROUPED_ID, label: u.label, seatCount: u.seatCount, seatLabels: u.seatLabels }, false);\n }\n return { rows, hiddenSections, closedSections };\n }\n\n private renderSectionsRail(): void {\n const { rows, hiddenSections, closedSections } = this.buildSectionRows();\n if (!rows.length) {\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">Availability windows</p>\n <p class=\"slm-hint\">Draw sections or zones in the designer to schedule availability per area. This chart has none yet.</p>\n <div class=\"slm-empty\">No sections on this chart.</div>`;\n return;\n }\n const parts: string[] = [];\n if (hiddenSections) parts.push(`${hiddenSections} hidden`);\n if (closedSections) parts.push(`${closedSections} closed`);\n const summary = parts.length ? parts.join(' · ') : 'All sections open and on sale';\n const warn = hiddenSections > 0 || closedSections > 0;\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">Availability windows</p>\n <p class=\"slm-hint\">Control when each zone or section goes on sale. Keep it hidden, reveal it at a set time, or <b>auto-reveal once the rest sells past a threshold</b>. Hidden seats vanish for buyers; closed seats stay on the map (flat grey) but can't be bought.</p>\n <div class=\"slm-availlist\" data-ref=\"availlist\">${rows.map((row) => this.sectionRowHtml(row)).join('')}</div>\n <div class=\"slm-availsummary\">\n <span class=\"slm-availdot${warn ? ' warn' : ''}\"></span>\n <span>${esc(summary)}</span>\n </div>\n <div class=\"slm-availcallout\">\n <span class=\"slm-availstar\" aria-hidden=\"true\">✦</span>\n <p><b>Auto-reveal at % sold</b> is our differentiator — demand-triggered release: the balcony opens itself the moment the stalls hit the threshold. Neither seats.io nor Ticketmaster ships this.</p>\n </div>`;\n this.wireSectionRail();\n this.applySectionCanvasTreatment();\n }\n\n private sectionRowHtml(row: SectionRow): string {\n const mode = availabilityModeOf(row.rule);\n const cls = `slm-availrow${row.kind === 'zone' ? ' zone' : ''}${row.hidden ? ' hidden' : ''}${row.closed ? ' closed' : ''}`;\n const disabled = this.availabilitySaving ? ' disabled' : '';\n const option = (value: AvailabilityMode, text: string): string =>\n `<option value=\"${value}\"${mode === value ? ' selected' : ''}>${text}</option>`;\n const control = row.followsZone\n ? '<span class=\"slm-availfollows\">Follows zone</span>'\n : `<span class=\"slm-availselwrap\">\n <select class=\"slm-select slm-availmode${mode !== 'open' ? ' on' : ''}\" data-avail-id=\"${esc(row.id)}\"${disabled} aria-label=\"Availability for ${esc(row.label)}\">\n ${option('open', 'Open — on sale')}\n ${option('closed', 'Closed — visible, not on sale')}\n ${option('hidden', 'Hidden — off the buyer map')}\n ${option('timed', 'Reveal at a time')}\n ${option('threshold', 'Auto-reveal at % sold')}\n </select>\n </span>`;\n let detail = '';\n if (!row.followsZone && mode === 'timed') {\n const value = row.rule?.revealAt ? esc(toLocalInput(row.rule.revealAt)) : '';\n detail = `<div class=\"slm-availdetail\">\n <input type=\"datetime-local\" class=\"slm-input\" data-avail-reveal=\"${esc(row.id)}\" value=\"${value}\"${disabled} aria-label=\"Reveal time for ${esc(row.label)}\" />\n </div>`;\n } else if (!row.followsZone && mode === 'threshold') {\n const pct = row.rule?.thresholdPct ?? 80;\n detail = `<div class=\"slm-availdetail\">\n <span class=\"slm-availpctlabel\">Reveal at</span>\n <input type=\"number\" min=\"1\" max=\"100\" class=\"slm-input slm-availpct\" data-avail-pct=\"${esc(row.id)}\" value=\"${esc(pct)}\"${disabled} aria-label=\"Percent sold to reveal ${esc(row.label)}\" />\n <span class=\"slm-availpctlabel\">% sold</span>\n </div>`;\n }\n const badge = row.closed\n ? '<span class=\"slm-availbadge closed\">Closed</span>'\n : row.hidden ? '<span class=\"slm-availbadge hidden\">Hidden</span>' : '';\n const caret = row.kind === 'zone' ? `<span class=\"slm-availcaret\" aria-hidden=\"true\">${row.hidden ? '▸' : '▾'}</span>` : '';\n return `<div class=\"${cls}\">\n <div class=\"slm-availhead\">\n <span class=\"slm-availlabel\">${caret}${esc(row.label)}</span>\n ${badge}\n <span class=\"slm-availcount\">${row.seatCount.toLocaleString()}</span>\n ${control}\n </div>\n ${detail}\n </div>`;\n }\n\n private wireSectionRail(): void {\n const rail = this.els.rail;\n if (!rail) return;\n rail.querySelectorAll<HTMLSelectElement>('[data-avail-id]').forEach((select) => {\n select.addEventListener('change', () => this.setSectionMode(select.dataset.availId!, select.value as AvailabilityMode));\n });\n rail.querySelectorAll<HTMLInputElement>('[data-avail-reveal]').forEach((input) => {\n input.addEventListener('change', () => {\n const ms = new Date(input.value).getTime();\n if (Number.isFinite(ms)) this.setSectionRulePatch(input.dataset.availReveal!, { revealAt: ms });\n });\n });\n rail.querySelectorAll<HTMLInputElement>('[data-avail-pct]').forEach((input) => {\n input.addEventListener('change', () => {\n const pct = Math.max(1, Math.min(100, Number(input.value) || 0));\n this.setSectionRulePatch(input.dataset.availPct!, { thresholdPct: pct });\n });\n });\n }\n\n /** Change one row's availability mode. A zone rule subsumes its child section\n * rules, so those are dropped from the map (the zone window is the truth). */\n private setSectionMode(id: string, mode: AvailabilityMode): void {\n const row = this.buildSectionRows().rows.find((r) => r.id === id);\n const seatLabels = row?.seatLabels ?? this.availabilityRules[id]?.labels ?? [];\n const next = { ...this.availabilityRules };\n const rule = availabilityRuleForMode(mode, seatLabels, this.availabilityRules[id]);\n if (rule) next[id] = rule;\n else delete next[id];\n if (row?.kind === 'zone' && this.sectionsBase) {\n for (const s of this.sectionsBase.sections) if (s.zone === id) delete next[s.id];\n }\n void this.persistAvailability(next);\n }\n\n /** Edit a timed reveal time / threshold percent on an existing row rule. */\n private setSectionRulePatch(id: string, patch: Partial<AvailabilityRule>): void {\n const cur = this.availabilityRules[id];\n if (!cur) return;\n const row = this.buildSectionRows().rows.find((r) => r.id === id);\n const labels = row?.seatLabels ?? cur.labels ?? [];\n void this.persistAvailability({ ...this.availabilityRules, [id]: { ...cur, ...patch, labels } });\n }\n\n /** Optimistically adopt the new rules, then reconcile with the server-cleaned\n * map + effective hidden/closed sets. Rolls back the rules on failure. */\n private async persistAvailability(next: Record<string, AvailabilityRule>): Promise<void> {\n const prev = this.availabilityRules;\n this.availabilityRules = next;\n this.availabilitySaving = true;\n if (this.mode === 'sections') this.renderSectionsRail();\n try {\n const res = await this.withAuthRetry(() => this.api.setAvailability(this.key, next));\n this.availabilityRules = res.rules;\n this.effectiveHidden = new Set(res.hidden);\n this.effectiveClosed = new Set(this.closedIdsFromRules(res.rules));\n this.availabilitySaving = false;\n if (this.mode === 'sections') this.renderSectionsRail();\n this.applySectionCanvasTreatment();\n } catch (err) {\n this.availabilityRules = prev;\n this.availabilitySaving = false;\n if (this.mode === 'sections') this.renderSectionsRail();\n this.toastErr(\"Couldn't update availability. Try again.\");\n this.opts.onError?.(err);\n }\n }\n\n private paintLegend(t: SeatManagerTallies): void {\n if (!this.els.legend) return;\n this.els.legend.innerHTML = LEGEND.map((l) =>\n `<div class=\"slm-legrow\"><span class=\"slm-legdot\" style=\"background:${l.color}\"></span>\n <span class=\"slm-leglabel\">${l.label}</span><span class=\"slm-legcount\">${t[l.key].toLocaleString()}</span></div>`).join('');\n }\n\n private paintFeed(): void {\n if (!this.els.feed) return;\n if (!this.feed.length) { this.els.feed.innerHTML = `<div class=\"slm-empty\">No activity yet — it'll stream in live.</div>`; return; }\n const now = Date.now();\n const color: Record<DoStatus, string> = { free: '#6e7bff', held: '#f4b740', booked: '#22a06b', blocked: '#8b94ac' };\n this.els.feed.innerHTML = this.feed.map((a) => {\n const extra = a.count > 1 ? ` +${a.count - 1}` : '';\n const sections = a.sectionLabels ?? [];\n const sectionCopy = sections.length === 1 ? sections[0] : sections.length > 1 ? `${sections.length} sections` : '';\n return `<button type=\"button\" class=\"slm-feedrow\" data-feed-id=\"${esc(a.id)}\" title=\"Locate this activity on the map\">\n <span class=\"slm-feeddot\" style=\"background:${color[a.status]}\"></span>\n <span class=\"slm-feedtext\">${sectionCopy ? `<span class=\"slm-feedsection\">${esc(sectionCopy)}</span>` : ''}${a.count === 1 ? 'Seat' : 'Seats'} <b>${esc(a.label)}${extra}</b> ${esc(a.verb)}</span>\n <span class=\"slm-feedmeta\"><span class=\"slm-feedtime\">${relTime(a.at, now)}</span><span class=\"slm-feedlocate\">Locate</span></span>\n </button>`;\n }).join('');\n }\n\n private renderBlockRail(): void {\n const cats = this.doc?.categories ?? [];\n const catChips = cats.map((c) =>\n `<button class=\"slm-chip\" type=\"button\" data-cat=\"${esc(c.key)}\" aria-pressed=\"false\">\n <span class=\"dot\" style=\"background:${esc(c.color ?? '#6e7bff')}\"></span>\n <span>${esc(c.label ?? c.key)}</span>\n <span class=\"slm-chipcount\" data-cat-count>0</span>\n <span class=\"slm-chipcheck\" aria-hidden=\"true\">✓</span>\n </button>`).join('');\n const sectionField = this.sectionOptions.length\n ? `<div class=\"slm-field\"><label>Select a whole section</label>\n <select class=\"slm-select\" data-ref=\"section\"><option value=\"\">Choose a section…</option>\n ${this.sectionOptions.map((s) => `<option value=\"${esc(s.id)}\">${esc(s.label)}</option>`).join('')}</select></div>`\n : '';\n const blockedSectionOptions = this.sectionOptions.map((s) =>\n `<option value=\"${esc(s.id)}\">${esc(s.label)}</option>`).join('');\n this.els.rail.innerHTML = `\n <p class=\"slm-eyebrow\">Block &amp; unblock</p>\n <p class=\"slm-hint\">Drag a box on the map to marquee-select, ⌘A for all, or pick a category/section. Booked and held inventory is never actionable here.</p>\n <div class=\"slm-selbar\" aria-live=\"polite\"><span class=\"slm-selnum\" data-ref=\"selnum\">0</span><span class=\"slm-sellabel\" data-ref=\"selmeta\">selected</span></div>\n <div class=\"slm-row\">\n <button class=\"slm-btn\" data-ref=\"doblock\" disabled>Block</button>\n <button class=\"slm-btn ghost\" data-ref=\"dounblock\" disabled>Put back on sale</button>\n </div>\n <div class=\"slm-row\">\n <button class=\"slm-btn ghost\" data-ref=\"selall\">Select all</button>\n <button class=\"slm-btn ghost\" data-ref=\"clearsel\">Clear</button>\n </div>\n <p class=\"slm-eyebrow\" style=\"margin-top:8px\">Select by category</p>\n <p class=\"slm-selecthelp\">Choose one or more. A checked category is selected; click it again to remove it.</p>\n <div class=\"slm-chiprow\">${catChips || '<span class=\"slm-empty\">No categories.</span>'}</div>\n ${sectionField}\n <div class=\"slm-field\">\n <label>Auto-release blocks at (optional)</label>\n <input type=\"datetime-local\" class=\"slm-input\" data-ref=\"release\" />\n <p class=\"slm-note\" data-ref=\"releasenote\">Leave empty to block permanently.</p>\n </div>\n <section class=\"slm-blocked\" aria-labelledby=\"slm-blocked-title\">\n <div class=\"slm-blockedhead\">\n <p class=\"slm-eyebrow\" id=\"slm-blocked-title\">Blocked inventory</p>\n <span class=\"slm-blockedtotal\"><b data-ref=\"blockedcount\">0</b> out of sale</span>\n </div>\n <p class=\"slm-selecthelp\">Find blocked seats, select only the ones you need, then use “Put back on sale”.</p>\n <div class=\"slm-blockedtools\">\n <input type=\"search\" class=\"slm-input\" data-ref=\"blockedsearch\" placeholder=\"Find seat, row or category\" aria-label=\"Search blocked seats\" />\n <select class=\"slm-select\" data-ref=\"blockedsection\" aria-label=\"Filter blocked seats by section\">\n <option value=\"\">All sections</option>${blockedSectionOptions}\n </select>\n </div>\n <div class=\"slm-blockedsummary\">\n <span data-ref=\"blockedshowing\">No blocked seats</span>\n <button type=\"button\" class=\"slm-linkbtn\" data-ref=\"selblocked\" disabled>Select results</button>\n </div>\n <div class=\"slm-blockedlist\" data-ref=\"blockedlist\"></div>\n </section>\n <div class=\"slm-field\">\n <button class=\"slm-btn ghost\" data-ref=\"markall\" style=\"width:100%\" disabled>Put all blocked seats on sale</button>\n <p class=\"slm-note slm-allnote\" data-ref=\"markallnote\">For a full reset only. You will be asked to confirm.</p>\n </div>\n `;\n const r = (n: string) => this.els.rail.querySelector(`[data-ref=\"${n}\"]`) as HTMLElement;\n this.els.selnum = r('selnum'); this.els.doblock = r('doblock'); this.els.dounblock = r('dounblock');\n this.els.selmeta = r('selmeta'); this.els.blockedcount = r('blockedcount');\n this.els.blockedshowing = r('blockedshowing'); this.els.blockedlist = r('blockedlist');\n this.els.selblocked = r('selblocked'); this.els.markall = r('markall'); this.els.markallnote = r('markallnote');\n r('doblock').addEventListener('click', () => void this.block());\n r('dounblock').addEventListener('click', () => void this.unblock());\n r('selall').addEventListener('click', () => this.selectAll());\n r('clearsel').addEventListener('click', () => this.clearSelection());\n r('markall').addEventListener('click', () => this.confirmUnblockAll());\n this.els.rail.querySelectorAll('[data-cat]').forEach((b) =>\n b.addEventListener('click', () => this.toggleCategory((b as HTMLElement).dataset.cat!)));\n const sectionSel = this.els.rail.querySelector('[data-ref=\"section\"]') as HTMLSelectElement | null;\n sectionSel?.addEventListener('change', () => { if (sectionSel.value) { this.selectSection(sectionSel.value); sectionSel.value = ''; } });\n const blockedSearch = r('blockedsearch') as HTMLInputElement;\n const blockedSection = r('blockedsection') as HTMLSelectElement;\n blockedSearch.value = this.blockedQuery;\n blockedSection.value = this.blockedSection;\n blockedSearch.addEventListener('input', () => {\n this.blockedQuery = blockedSearch.value;\n this.blockedResultLimit = 100;\n this.paintBlockedInventory();\n });\n blockedSection.addEventListener('change', () => {\n this.blockedSection = blockedSection.value;\n this.blockedResultLimit = 100;\n this.paintBlockedInventory();\n });\n r('selblocked').addEventListener('click', () => {\n this.toggleLabels(this.filteredBlockedSeats().map((seat) => seat.label));\n });\n r('blockedlist').addEventListener('click', (event) => {\n const target = event.target as HTMLElement;\n const seatButton = target.closest<HTMLElement>('[data-blocked-label]');\n if (seatButton?.dataset.blockedLabel) this.toggleLabels([seatButton.dataset.blockedLabel]);\n else if (target.closest('[data-blocked-more]')) {\n this.blockedResultLimit += 100;\n this.paintBlockedInventory();\n }\n });\n const rel = r('release') as HTMLInputElement;\n rel.addEventListener('change', () => {\n const ms = rel.value ? new Date(rel.value).getTime() : NaN;\n this.releaseAt = Number.isFinite(ms) && ms > Date.now() ? ms : null;\n const note = r('releasenote');\n note.textContent = this.releaseAt\n ? `New blocks auto-release ${new Date(this.releaseAt).toLocaleString()}.`\n : rel.value ? 'Pick a time in the future.' : 'Leave empty to block permanently.';\n });\n this.paintSelBar(this.getSelection());\n }\n\n private toggleCategory(catKey: string): void {\n const labels: string[] = [];\n for (const [label, seat] of this.labelToSeat.entries()) {\n if (seat.categoryKey === catKey && this.isBlockSelectable(label)) labels.push(label);\n }\n this.toggleLabels(labels);\n }\n\n /** A category/filter is a real toggle: add the missing seats, or remove the\n * whole group when every eligible seat in it is already selected. */\n private toggleLabels(labels: string[]): void {\n if (!this.renderer) return;\n const eligible = labels.filter((label) => this.labelToSeat.has(label) && this.isBlockSelectable(label));\n if (!eligible.length) return;\n const selected = new Set(this.selectionLabels());\n const allSelected = eligible.every((label) => selected.has(label));\n if (allSelected) {\n const ids = eligible.map((label) => this.labelToId.get(label)).filter((id): id is string => Boolean(id));\n this.renderer.deselect(ids);\n } else {\n this.renderer.selectByLabels(eligible);\n }\n this.syncSelection();\n }\n\n private isBlockSelectable(label: string): boolean {\n const status = this.status.get(label) ?? 'free';\n return status === 'free' || status === 'blocked';\n }\n\n private paintSelBar(seats: ExpandedSeat[]): void {\n if (!this.els.selnum) return;\n this.els.selnum.textContent = seats.length.toLocaleString();\n const freeCount = seats.filter((s) => (this.status.get(s.label) ?? 'free') === 'free').length;\n const blockedCount = seats.filter((s) => this.status.get(s.label) === 'blocked').length;\n this.els.selmeta.textContent = seats.length\n ? `${freeCount.toLocaleString()} available · ${blockedCount.toLocaleString()} blocked`\n : 'selected';\n const blockButton = this.els.doblock as HTMLButtonElement;\n const unblockButton = this.els.dounblock as HTMLButtonElement;\n blockButton.disabled = freeCount === 0;\n unblockButton.disabled = blockedCount === 0;\n blockButton.textContent = freeCount ? `Block ${freeCount.toLocaleString()}` : 'Block selected';\n unblockButton.textContent = blockedCount ? `Put ${blockedCount.toLocaleString()} on sale` : 'Put back on sale';\n this.paintCategoryControls(seats);\n this.paintBlockedInventory();\n }\n\n private paintCategoryControls(seats: ExpandedSeat[]): void {\n const selected = new Set(seats.map((seat) => seat.label));\n this.els.rail?.querySelectorAll<HTMLButtonElement>('[data-cat]').forEach((button) => {\n const catKey = button.dataset.cat;\n const labels: string[] = [];\n for (const [label, seat] of this.labelToSeat.entries()) {\n if (seat.categoryKey === catKey && this.isBlockSelectable(label)) labels.push(label);\n }\n const picked = labels.filter((label) => selected.has(label)).length;\n const full = labels.length > 0 && picked === labels.length;\n const partial = picked > 0 && !full;\n button.disabled = labels.length === 0;\n button.classList.toggle('on', full);\n button.classList.toggle('partial', partial);\n button.setAttribute('aria-pressed', full ? 'true' : partial ? 'mixed' : 'false');\n button.setAttribute('title', full\n ? `Remove all ${labels.length.toLocaleString()} seats in this category from the selection`\n : partial\n ? `Select the remaining ${(labels.length - picked).toLocaleString()} seats in this category`\n : `Select all ${labels.length.toLocaleString()} seats in this category`);\n const count = button.querySelector<HTMLElement>('[data-cat-count]');\n if (count) count.textContent = picked ? `${picked.toLocaleString()}/${labels.length.toLocaleString()}` : labels.length.toLocaleString();\n });\n }\n\n private filteredBlockedSeats(): ExpandedSeat[] {\n const query = this.blockedQuery.trim().toLocaleLowerCase();\n const seats: ExpandedSeat[] = [];\n for (const [label, seat] of this.labelToSeat.entries()) {\n if (this.status.get(label) !== 'blocked') continue;\n const sectionId = this.sectionByObject.get(seat.rowId) ?? UNGROUPED_ID;\n if (this.blockedSection && sectionId !== this.blockedSection) continue;\n if (query) {\n const category = this.doc?.categories.find((item) => item.key === seat.categoryKey)?.label ?? seat.categoryKey;\n const section = this.sectionLabelById.get(sectionId) ?? 'Other seats';\n const object = this.doc?.objects.find((item) => item.id === seat.rowId);\n const objectLabel = object?.type === 'row' || object?.type === 'table' ? object.label : '';\n const haystack = `${label} ${category} ${section} ${objectLabel}`.toLocaleLowerCase();\n if (!haystack.includes(query)) continue;\n }\n seats.push(seat);\n }\n return seats.sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true, sensitivity: 'base' }));\n }\n\n private paintBlockedInventory(): void {\n if (!this.els.blockedlist) return;\n const allBlocked = [...this.status.entries()].filter(([, status]) => status === 'blocked').length;\n const filtered = this.filteredBlockedSeats();\n const visible = filtered.slice(0, this.blockedResultLimit);\n const selected = new Set(this.selectionLabels());\n const selectedResults = filtered.filter((seat) => selected.has(seat.label)).length;\n const allResultsSelected = filtered.length > 0 && selectedResults === filtered.length;\n this.els.blockedcount.textContent = allBlocked.toLocaleString();\n this.els.blockedshowing.textContent = filtered.length\n ? `Showing ${visible.length.toLocaleString()} of ${filtered.length.toLocaleString()}`\n : allBlocked ? 'No matches' : 'No blocked seats';\n const selectResults = this.els.selblocked as HTMLButtonElement;\n selectResults.disabled = filtered.length === 0;\n selectResults.textContent = allResultsSelected\n ? `Remove ${filtered.length.toLocaleString()} results`\n : `Select ${filtered.length.toLocaleString()} results`;\n\n this.els.blockedlist.innerHTML = visible.length ? visible.map((seat) => {\n const sectionId = this.sectionByObject.get(seat.rowId) ?? UNGROUPED_ID;\n const section = this.sectionLabelById.get(sectionId) ?? 'Other seats';\n const category = this.doc?.categories.find((item) => item.key === seat.categoryKey)?.label ?? seat.categoryKey;\n const isSelected = selected.has(seat.label);\n return `<button type=\"button\" class=\"slm-blockeditem${isSelected ? ' on' : ''}\" data-blocked-label=\"${esc(seat.label)}\" aria-pressed=\"${isSelected}\">\n <span class=\"slm-blockedcheck\" aria-hidden=\"true\">✓</span>\n <span class=\"slm-blockedcopy\"><span class=\"slm-blockedlabel\">${esc(seat.label)}</span>\n <span class=\"slm-blockedmeta\">${esc(section)} · ${esc(category)}</span></span>\n </button>`;\n }).join('') + (filtered.length > visible.length\n ? `<button type=\"button\" class=\"slm-blockedmore\" data-blocked-more>Show 100 more</button>` : '')\n : `<div class=\"slm-blockedempty\">${allBlocked\n ? 'No blocked seats match this search or section.'\n : 'No seats are blocked. Newly blocked seats will appear here.'}</div>`;\n\n const markAll = this.els.markall as HTMLButtonElement;\n const armed = markAll.dataset.confirm === 'true';\n markAll.disabled = allBlocked === 0;\n markAll.textContent = armed\n ? `Confirm: put all ${allBlocked.toLocaleString()} on sale`\n : `Put all ${allBlocked.toLocaleString()} blocked seats on sale`;\n }\n\n private confirmUnblockAll(): void {\n const button = this.els.markall as HTMLButtonElement;\n if (!button || button.disabled) return;\n if (button.dataset.confirm === 'true') {\n this.resetUnblockAllConfirm();\n void this.unblockAll();\n return;\n }\n button.dataset.confirm = 'true';\n button.classList.add('danger');\n this.els.markallnote.textContent = 'This changes every blocked seat. Click the red button again to confirm.';\n this.paintBlockedInventory();\n if (this.unblockAllConfirmTimer) clearTimeout(this.unblockAllConfirmTimer);\n this.unblockAllConfirmTimer = setTimeout(() => this.resetUnblockAllConfirm(), 6000);\n }\n\n private resetUnblockAllConfirm(): void {\n if (this.unblockAllConfirmTimer) clearTimeout(this.unblockAllConfirmTimer);\n this.unblockAllConfirmTimer = null;\n const button = this.els.markall as HTMLButtonElement | undefined;\n if (!button) return;\n delete button.dataset.confirm;\n button.classList.remove('danger');\n if (this.els.markallnote) this.els.markallnote.textContent = 'For a full reset only. You will be asked to confirm.';\n this.paintBlockedInventory();\n }\n\n // ---- toast / done / fail --------------------------------------------------\n\n private done(action: SeatManagerActionResult['action'], labels: string[], msg: string): void {\n this.toastOk(msg);\n if (labels.length) {\n const activity = action === 'block'\n ? this.pushActivity(labels, 'blocked', 'blocked')\n : action === 'unblock' || action === 'unblockAll'\n ? this.pushActivity(labels, 'unblocked', 'free')\n : action === 'cancelBooking'\n ? this.pushActivity(labels, 'cancelled', 'free')\n : null;\n if (activity) this.paintSpatialActivity(activity);\n }\n // An explicit organizer action is one of the three moments the server's own\n // totals and money are re-read (mount, (re)connect, action) — the cockpit\n // does not poll for them.\n if (action !== 'setHoldTtl') void this.refreshControlRoom().catch((err) => this.opts.onError?.(err));\n this.opts.onActionComplete?.({ action, labels, count: labels.length });\n }\n\n private toastOk(msg: string): void { this.toast(msg, 'ok'); }\n private toastErr(msg: string): void { this.toast(msg, 'err'); }\n\n private toast(msg: string, kind: 'ok' | 'err'): void {\n const el = this.els.toast;\n if (!el) return;\n el.textContent = msg;\n el.className = `slm-toast on ${kind}`;\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toastTimer = setTimeout(() => { el.className = 'slm-toast'; }, 3200);\n }\n\n private fail(err: unknown): void {\n this.opts.onError?.(err);\n if (this.els.rail) this.els.rail.innerHTML = `<div class=\"slm-empty\">Couldn't load this event. Check the event key and token.</div>`;\n }\n}\n","import type { ChartDoc, ChartReferenceImage, DecorImageObject, Floor } from '@seatlayer/core';\n\nconst SAFE_ASSET = /^[a-zA-Z0-9._-]+$/;\n\nexport interface OrganizerEventAssetReference {\n eventKey: string;\n asset: string;\n}\n\n/** Parse only the authenticated organizer Event media route. */\nexport function organizerEventAssetReference(value: string): OrganizerEventAssetReference | null {\n let url: URL;\n try {\n url = new URL(value, 'https://seatlayer.invalid');\n } catch {\n return null;\n }\n if (url.search || url.hash) return null;\n const match = /^\\/v1\\/events\\/([^/]+)\\/assets\\/([^/]+)$/.exec(url.pathname);\n if (!match) return null;\n try {\n const eventKey = decodeURIComponent(match[1]);\n const asset = decodeURIComponent(match[2]);\n if (!eventKey || !SAFE_ASSET.test(asset)) return null;\n return { eventKey, asset };\n } catch {\n return null;\n }\n}\n\nfunction looksLikeOrganizerAsset(value: string): boolean {\n try {\n return /^\\/v1\\/events\\/[^/]+\\/assets(?:\\/|$)/.test(\n new URL(value, 'https://seatlayer.invalid').pathname,\n );\n } catch {\n return false;\n }\n}\n\nexport type OrganizerAssetLoader = (eventKey: string, asset: string) => Promise<Blob>;\n\n/**\n * One SeatManager-lifetime cache for media fetched with organizer authority.\n * Object URLs are process-local, carry no bearer, and are all revoked by\n * {@link dispose}.\n */\nexport class OrganizerAssetObjectUrls {\n private readonly pending = new Map<string, Promise<string | null>>();\n private readonly created = new Set<string>();\n private disposed = false;\n\n constructor(\n private readonly eventKey: string,\n private readonly load: OrganizerAssetLoader,\n ) {}\n\n resolve(reference: string): Promise<string | null> {\n const parsed = organizerEventAssetReference(reference);\n if (!parsed) {\n // A malformed SeatLayer organizer-media path is never treated as an\n // external image and loaded without its bearer.\n return Promise.resolve(looksLikeOrganizerAsset(reference) ? null : reference);\n }\n if (parsed.eventKey !== this.eventKey || this.disposed) return Promise.resolve(null);\n\n const cacheKey = `${parsed.eventKey}/${parsed.asset}`;\n const existing = this.pending.get(cacheKey);\n if (existing) return existing;\n\n const task = this.load(parsed.eventKey, parsed.asset).then((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n if (this.disposed) {\n URL.revokeObjectURL(objectUrl);\n return null;\n }\n this.created.add(objectUrl);\n return objectUrl;\n }).catch((error) => {\n this.pending.delete(cacheKey);\n throw error;\n });\n this.pending.set(cacheKey, task);\n return task;\n }\n\n /**\n * Resolve the image fields the synchronous map renderer loads immediately.\n * View-from-seat media stays lazy: SeatManager does not open that buyer\n * surface, and eagerly downloading every row panorama would be unbounded.\n */\n async prepareRendererChart(doc: ChartDoc): Promise<ChartDoc> {\n const prepareBackground = async (background?: ChartReferenceImage): Promise<void> => {\n if (!background?.url) return;\n const resolved = await this.resolve(background.url);\n if (!resolved) throw new Error('organizer_event_asset_scope_mismatch');\n background.url = resolved;\n };\n const prepareObjects = async (objects: ChartDoc['objects']): Promise<void> => {\n for (const object of objects) {\n if (object.type !== 'decorImage') continue;\n const image = object as DecorImageObject;\n const resolved = await this.resolve(image.href);\n if (!resolved) throw new Error('organizer_event_asset_scope_mismatch');\n image.href = resolved;\n }\n };\n const prepareOwner = async (owner: Pick<ChartDoc, 'backgroundImage' | 'objects'> | Floor): Promise<void> => {\n await prepareBackground(owner.backgroundImage);\n await prepareObjects(owner.objects);\n };\n\n await prepareOwner(doc);\n for (const floor of doc.floors ?? []) await prepareOwner(floor);\n return doc;\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const url of this.created) URL.revokeObjectURL(url);\n this.created.clear();\n this.pending.clear();\n }\n}\n"],"mappings":"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","names":["value","channel","point","esc","window"]}