@seatlayer/js 0.86.8 → 0.86.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/manager.js CHANGED
@@ -1,4 +1,13 @@
1
- import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a as v,b as C,c as Z,d as Y,e as Q,f as X,g as J,h as ee,i as te,j as se,k as ie,l as oe,m as ae,n as le,o as ne,p as re,q as ce,r as de,s as he,t as pe,u as me,v as ue,w as be,x as fe,y as ge,z as ve}from"./chunk-Z3G64HUG.js";import"./chunk-OSZ7DOEH.js";import{SeatmapRenderer as Ce,expandChart as Re,computeSections as Ee,floorsOf as Ae,gaAreasOf as $e,gaUnitLabels as He,UNGROUPED_ID as g}from"@seatlayer/core";var ke=/^[a-zA-Z0-9._-]+$/;function we(d){let e;try{e=new URL(d,"https://seatlayer.invalid")}catch{return null}if(e.search||e.hash)return null;let t=/^\/v1\/events\/([^/]+)\/assets\/([^/]+)$/.exec(e.pathname);if(!t)return null;try{let s=decodeURIComponent(t[1]),i=decodeURIComponent(t[2]);return!s||!ke.test(i)?null:{eventKey:s,asset:i}}catch{return null}}function xe(d){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(d,"https://seatlayer.invalid").pathname)}catch{return!1}}var S=class{constructor(e,t){this.eventKey=e;this.load=t;this.pending=new Map;this.created=new Set;this.disposed=!1}resolve(e){let t=we(e);if(!t)return Promise.resolve(xe(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,i=this.pending.get(s);if(i)return i;let o=this.load(t.eventKey,t.asset).then(a=>{let l=URL.createObjectURL(a);return this.disposed?(URL.revokeObjectURL(l),null):(this.created.add(l),l)}).catch(a=>{throw this.pending.delete(s),a});return this.pending.set(s,o),o}async prepareRendererChart(e){let t=async o=>{if(!o?.url)return;let a=await this.resolve(o.url);if(!a)throw new Error("organizer_event_asset_scope_mismatch");o.url=a},s=async o=>{for(let a of o){if(a.type!=="decorImage")continue;let l=a,r=await this.resolve(l.href);if(!r)throw new Error("organizer_event_asset_scope_mismatch");l.href=r}},i=async o=>{await t(o.backgroundImage),await s(o.objects)};await i(e);for(let o of e.floors??[])await i(o);return e}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.created)URL.revokeObjectURL(e);this.created.clear(),this.pending.clear()}}};var I="seatlayer-manager-style",B="seatlayer-manager-channels-style",Le=`
1
+ import{c as A,d as $,f as O}from"./chunk-RZ2VKZ44.js";import{A as Me,B as Ce,D as Ee,a as F,b as k,c as H,d as ie,e as ae,f as oe,g as le,h as ne,i as re,j as ce,k as de,l as he,m as pe,n as me,o as ue,p as be,q as ge,r as ve,s as fe,t as ye,u as xe,v as ke,w as Se,x as we,y as Le,z as Te}from"./chunk-H7F4LMNV.js";import"./chunk-OSZ7DOEH.js";var j={hold:"Held",release:"Released",expire:"Expired",book:"Booked",unbook:"Cancelled",block:"Blocked",unblock:"Unblocked"},S=class{constructor(e,t){this.host=e;this.fetchPage=t;this.closed=!1;this.busy=!1;this.generation=0;this.entries=[];this.next=null;this.summary=document.createElement("div");this.list=document.createElement("div");this.message=document.createElement("div");this.older=document.createElement("button");this.latest=document.createElement("button");e.className="slm-seat-history",this.summary.className="slm-history-counts",this.list.className="slm-history-list",this.list.setAttribute("role","region"),this.list.setAttribute("aria-label","Seat history"),this.list.tabIndex=0,this.message.className="slm-note",this.message.setAttribute("role","status"),this.older.className=this.latest.className="slm-btn ghost",this.older.textContent="Load older",this.older.hidden=!0,this.latest.textContent="New activity \xB7 Show latest",this.latest.hidden=!0,this.older.onclick=()=>{this.load(!0)},this.latest.onclick=()=>{this.list.scrollTop=0,this.latest.hidden=!0,this.load()},e.append(this.summary,this.latest,this.list,this.message,this.older),this.load()}destroy(){this.closed=!0,this.generation++}refresh(){this.busy||this.load(!1,!0)}async load(e=!1,t=!1){if(this.closed||this.busy||e&&!this.next)return;this.busy=!0,this.older.disabled=!0;let s=this.generation;t||(this.message.textContent="Loading history\u2026");try{let i=await this.fetchPage(e?this.next:void 0,this.action);if(this.closed||s!==this.generation)return;if(this.paintCounts(i),t&&this.entries.length&&i.entries[0]?.id!==this.entries[0]?.id&&this.list.scrollTop>24){this.latest.hidden=!1;return}let a=!t||i.entries[0]?.id!==this.entries[0]?.id;e?(this.entries=[...this.entries,...i.entries.filter(o=>!this.entries.some(l=>l.id===o.id))],this.next=i.nextBefore):a&&(this.entries=i.entries,this.next=i.nextBefore),a&&this.paintRows(),this.older.hidden=this.next===null,this.message.textContent=this.entries.length?"":"No recorded activity for this seat."}catch{if(!this.closed){this.message.textContent="History could not be loaded. ";let i=document.createElement("button");i.className="slm-btn ghost",i.textContent="Retry",i.onclick=()=>{this.load(e)},this.message.append(i)}}finally{this.busy=!1,this.older.disabled=!1}}paintCounts(e){let t=[{action:"",count:e.total},...e.counts];this.summary.replaceChildren(...t.map(({action:s,count:i})=>{let a=document.createElement("button");return a.type="button",a.textContent=s?`${j[s]??s} ${i}`:`${i} changes`,a.setAttribute("aria-pressed",String((this.action??"")===s)),a.onclick=()=>{this.busy||(this.action=s||void 0,this.entries=[],this.next=null,this.list.scrollTop=0,this.latest.hidden=!0,this.load())},a}))}paintRows(){let e=this.list.scrollTop;this.list.replaceChildren(...this.entries.map(t=>{let s=document.createElement("div");s.className="slm-history-row",s.dataset.action=t.action;let i=document.createElement("time");i.dateTime=new Date(t.at).toISOString(),i.textContent=new Date(t.at).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),i.title=new Date(t.at).toString();let a=document.createElement("strong");return a.textContent=j[t.action]??t.action,s.append(i,a),s})),this.list.scrollTop=e}};var Re={held:"HOLD",booked:"BOOK",expired:"EXPIRE",released:"RELEASE",cancelled:"CANCEL",blocked:"BLOCK",unblocked:"ON SALE",available:"FREE"},P={held:"Held",booked:"Booked",expired:"Hold expired",released:"Hold released",cancelled:"Booking cancelled",blocked:"Blocked",unblocked:"Back on sale",available:"Available again"},w=class{constructor(e,t,s){this.host=e;this.locate=s;this.items=[];this.shown=new Set;this.paused=!1;this.limit=100;this.signature="unrendered";this.abort=new AbortController;e.innerHTML='<button class="slm-new-activity" hidden></button><div class="slm-activity-list" role="region" aria-label="Recent activity" tabindex="0"></div><button class="slm-more-activity" hidden>Show more activity</button>',this.list=e.querySelector(".slm-activity-list"),this.newer=e.querySelector(".slm-new-activity"),this.more=e.querySelector(".slm-more-activity");let i={signal:this.abort.signal},a=()=>{this.paused=!1,this.signature="unrendered",this.list.scrollTop=0,this.render()};this.list.addEventListener("scroll",()=>{this.list.scrollTop>24&&(this.paused=!0)},i),this.list.addEventListener("focusin",()=>{this.paused=!0},i),this.list.addEventListener("toggle",o=>{o.target.open&&(this.paused=!0)},{...i,capture:!0}),this.newer.addEventListener("click",a,i),this.more.addEventListener("click",()=>{this.limit=200,this.signature="unrendered",this.render(!0)},i)}update(e){this.items=e,this.render()}render(e=!1){let t=this.items,s=t.filter(o=>!this.shown.has(o.id)).length;if(this.newer.hidden=!this.paused,this.newer.textContent=s?`${s} new activit${s===1?"y":"ies"} \xB7 Back to live`:"Reading earlier activity \xB7 Back to live",this.paused&&!e)return;let i=t.slice(0,this.limit),a=i.map(o=>`${o.id}:${o.verb}`).join("|");if(a!==this.signature){if(this.signature=a,this.shown=new Set(t.map(o=>o.id)),this.list.replaceChildren(),!i.length){let o=document.createElement("p");o.className="slm-activity-empty",o.textContent=this.items.length?"No activity matches these filters.":"Waiting for activity. Holds, bookings and releases will appear here.",this.list.append(o)}for(let o of i){let l=document.createElement("article");l.className="slm-activity-entry",l.dataset.status=o.status;let r=document.createElement("button");r.type="button",r.className="slm-activity-row";let c=`${P[o.verb]??o.verb} \xB7 ${o.count} seat${o.count===1?"":"s"} \xB7 ${o.sectionLabels?.join(", ")||"Event inventory"} \xB7 ${o.labels.join(", ")} \xB7 ${new Date(o.at).toLocaleString()}`;r.title=`${c} \u2014 click to show seats on the map`,r.setAttribute("aria-label",`Show seats on map: ${c}`),r.addEventListener("click",()=>this.locate(o.id));let n=document.createElement("time");n.dateTime=new Date(o.at).toISOString(),n.textContent=new Date(o.at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let d=document.createElement("strong");d.textContent=Re[o.verb]??o.verb,d.title=P[o.verb]??o.verb;let m=document.createElement("span");if(m.className="slm-activity-seats",m.textContent=o.labels.join(", "),r.append(n,d,m),l.append(r),o.count>1){let b=document.createElement("details");b.className="slm-activity-details";let g=document.createElement("summary");g.textContent="\u22EF",g.setAttribute("aria-label",`Show all ${o.count} seats`);let v=document.createElement("p");v.textContent=c,b.append(g,v),l.append(b)}this.list.append(l)}this.more.hidden=t.length<=this.limit}}destroy(){this.abort.abort()}};var L=class{constructor(e){this.host=e;this.moving=!1;this.space=!1;this.abort=new AbortController;let t=document.createElement("div");t.className="slm-navigation";let s=u=>`<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${u}</svg>`,i=s('<path d="M8 13V6a2 2 0 0 1 4 0v6-8a2 2 0 0 1 4 0v8-6a2 2 0 0 1 4 0v10c0 4-3 6-7 6-3 0-5-2-7-5l-3-4a2 2 0 0 1 3-2l2 2Z"/>'),a=s('<path d="m5 3 14 10-7 1-3 7-4-18Z"/>'),o=s('<circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/>'),l=s('<path d="M7 6h10M12 1v10M7 18h10"/>'),r=s('<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16"/>');t.innerHTML=`<div class="slm-navigation-tools" role="group" aria-label="Map navigation">
2
+ <button type="button" data-nav="move" aria-label="Move" aria-pressed="false" title="Drag to move the map; hold Space temporarily">${i}</button>
3
+ <button type="button" data-nav="select" aria-label="Select" aria-pressed="true" title="Drag to select seats">${a}</button>
4
+ <button type="button" data-nav="search" aria-label="Search" title="Search seats, rows or sections" aria-expanded="false">${o}</button>
5
+ <button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${l}</button>
6
+ <button type="button" hidden data-nav="out" aria-label="Zoom out">\u2212</button>
7
+ <button type="button" hidden data-nav="in" aria-label="Zoom in">+</button>
8
+ <span class="slm-navigation-count" role="status" aria-live="polite">0 selected</span>
9
+ <button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${r}</button>
10
+ </div><div class="slm-navigation-search" hidden><input type="search" aria-label="Find section, row or seat" placeholder="Find section, row or seat"><div class="slm-navigation-results" hidden></div></div>`,e.map.after(t),this.bar=t,this.move=t.querySelector('[data-nav="move"]'),this.select=t.querySelector('[data-nav="select"]'),this.search=t.querySelector("input"),this.results=t.querySelector(".slm-navigation-results"),this.location=document.createElement("div"),this.location.className="slm-location",this.location.hidden=!0,this.location.setAttribute("role","status"),e.map.after(this.location);let c={signal:this.abort.signal},n=t.querySelector('[data-nav="search"]'),d=t.querySelector(".slm-navigation-search"),m=()=>{d.hidden=!0,this.results.hidden=!0,n.setAttribute("aria-expanded","false"),n.focus()};n.addEventListener("click",()=>{let u=d.hidden;d.hidden=!u,n.setAttribute("aria-expanded",String(u)),u&&this.search.focus()},c);let b=t.querySelector('[data-nav="zoom"]');b.addEventListener("click",()=>{let u=b.getAttribute("aria-expanded")!=="true";b.setAttribute("aria-expanded",String(u));for(let f of["in","out"])t.querySelector(`[data-nav="${f}"]`).hidden=!u},c),this.search.addEventListener("keydown",u=>{u.key==="Escape"&&m()},c),this.move.addEventListener("click",()=>this.setMoving(!0),c),this.select.addEventListener("click",()=>this.setMoving(!1),c),t.querySelector('[data-nav="in"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomIn()},c),t.querySelector('[data-nav="out"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomOut()},c);let g=t.querySelector('[data-nav="rail"]');g.addEventListener("click",()=>{let u=e.root.classList.toggle("details-hidden");g.setAttribute("aria-expanded",String(!u)),g.setAttribute("aria-label",u?"Show details":"Hide details"),g.title=u?"Show details":"Hide details"},c),this.search.addEventListener("input",()=>this.find(),c),this.search.addEventListener("keydown",u=>{u.key==="Escape"&&(this.results.hidden=!0),u.key==="ArrowDown"&&(u.preventDefault(),this.results.querySelector("button")?.focus())},c),e.map.addEventListener("pointerdown",()=>{this.location.hidden=!0,e.pauseFollow(),e.root.focus({preventScroll:!0}),this.results.hidden=!0},{...c,capture:!0}),e.root.querySelector(".slm-rail")?.addEventListener("pointerdown",()=>e.pauseFollow(),{...c,capture:!0}),e.map.addEventListener("wheel",()=>{this.location.hidden=!0,e.pauseFollow()},{...c,passive:!0,capture:!0}),e.root.addEventListener("keydown",u=>{u.target?.closest('input,textarea,select,button,[contenteditable="true"]')||u.code!=="Space"||u.ctrlKey||u.metaKey||u.altKey||(u.preventDefault(),this.space||(this.space=!0,e.pauseFollow(),e.setMoving(!0)))},c);let v=()=>{this.space&&(this.space=!1,e.setMoving(this.moving))};window.addEventListener("keyup",u=>{u.code==="Space"&&v()},c),window.addEventListener("blur",v,c),window.addEventListener("resize",()=>{this.location.hidden=!0},c),e.root.querySelector('[data-ref="zfit"]')?.addEventListener("click",()=>{this.location.hidden=!0},c),e.root.addEventListener("focusout",u=>{e.root.contains(u.relatedTarget)||v()},c)}setMoving(e){this.moving=e,this.host.pauseFollow(),this.host.setMoving(e||this.space),this.move.setAttribute("aria-pressed",String(e)),this.select.setAttribute("aria-pressed",String(!e))}update(e,t=!1){this.bar.querySelector(".slm-navigation-count").hidden=t,this.move.hidden=!e,this.select.hidden=!e}selectionChanged(e){this.bar.querySelector(".slm-navigation-count").textContent=`${e.toLocaleString()} selected`}find(){let e=this.search.value.trim();if(this.results.replaceChildren(),this.results.hidden=!e,!e)return;let t=this.host.targets(e);for(let s of t){let i=document.createElement("button");i.type="button",i.textContent=`${s.label} \xB7 ${s.detail}`,i.addEventListener("click",()=>{this.host.pauseFollow(),s.locate(),this.location.textContent=`${s.label} \xB7 ${s.detail}`,this.location.hidden=!1,this.results.hidden=!0,this.host.root.focus({preventScroll:!0})}),this.results.append(i)}t.length||(this.results.textContent="No matching section, row or seat.")}destroy(){this.abort.abort(),this.bar.remove(),this.location.remove()}};import{SeatmapRenderer as Oe,expandChart as Fe,computeSections as je,floorsOf as J,gaAreasOf as Pe,gaUnitLabels as De,UNGROUPED_ID as y}from"@seatlayer/core";var Ae=/^[a-zA-Z0-9._-]+$/;function $e(h){let e;try{e=new URL(h,"https://seatlayer.invalid")}catch{return null}if(e.search||e.hash)return null;let t=/^\/v1\/events\/([^/]+)\/assets\/([^/]+)$/.exec(e.pathname);if(!t)return null;try{let s=decodeURIComponent(t[1]),i=decodeURIComponent(t[2]);return!s||!Ae.test(i)?null:{eventKey:s,asset:i}}catch{return null}}function He(h){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(h,"https://seatlayer.invalid").pathname)}catch{return!1}}var T=class{constructor(e,t){this.eventKey=e;this.load=t;this.pending=new Map;this.created=new Set;this.disposed=!1}resolve(e){let t=$e(e);if(!t)return Promise.resolve(He(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,i=this.pending.get(s);if(i)return i;let a=this.load(t.eventKey,t.asset).then(o=>{let l=URL.createObjectURL(o);return this.disposed?(URL.revokeObjectURL(l),null):(this.created.add(l),l)}).catch(o=>{throw this.pending.delete(s),o});return this.pending.set(s,a),a}async prepareRendererChart(e){let t=async a=>{if(!a?.url)return;let o=await this.resolve(a.url);if(!o)throw new Error("organizer_event_asset_scope_mismatch");a.url=o},s=async a=>{for(let o of a){if(o.type!=="decorImage")continue;let l=o,r=await this.resolve(l.href);if(!r)throw new Error("organizer_event_asset_scope_mismatch");l.href=r}},i=async a=>{await t(a.backgroundImage),await s(a.objects)};await i(e);for(let a of e.floors??[])await i(a);return e}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.created)URL.revokeObjectURL(e);this.created.clear(),this.pending.clear()}}};var D="seatlayer-manager-style",N="seatlayer-manager-channels-style",Be=`
2
11
  /* The floor was 480px, which trapped the cockpit in any host shorter than that:
3
12
  every ancestor here is overflow:hidden, so the bottom of the rail (Create
4
13
  channel, Show archived) was rendered but clipped away by the host and could
@@ -18,6 +27,73 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
18
27
  .slm button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
19
28
  .slm input{font:inherit}
20
29
 
30
+ .slm .slm-btn:not(.ghost):not(.danger){background:var(--slm-accent);color:var(--slm-accent-ink);border:1px solid var(--slm-accent)}
31
+ /* Navigation remains available without changing the inventory tool. */
32
+ .slm-navigation{position:absolute;top:10px;left:10px;display:flex;flex-direction:column;align-items:flex-start;gap:6px;max-width:calc(100% - 20px);z-index:6;pointer-events:none}
33
+ .slm-navigation>*{pointer-events:auto}
34
+ .slm .slm-navigation-tools button{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;min-width:34px;padding:0}
35
+ .slm-navigation-tools svg{pointer-events:none;flex:none}
36
+ .slm-navigation-tools{padding:3px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-bg);box-shadow:0 1px 3px #00000012}
37
+ .slm-navigation-tools{display:flex;gap:2px;align-items:center;flex-wrap:wrap}
38
+ .slm-navigation-count{font-size:12px;color:var(--slm-muted);padding:0 6px;white-space:nowrap}
39
+ .slm .slm-navigation button{min-height:36px;padding:7px 10px;border:1px solid var(--slm-line);border-radius:7px;background:var(--slm-surface);color:var(--slm-text);font-size:12px}
40
+ .slm .slm-navigation button[aria-pressed="true"]{background:var(--slm-accent);color:var(--slm-accent-ink)}
41
+ /* Toolbar controls are flat; search result buttons retain their own layout. */
42
+ .slm .slm-navigation .slm-navigation-tools button{width:32px;height:32px;min-width:32px;min-height:32px;padding:0;border:0;border-radius:5px;background:transparent;box-shadow:none;color:var(--slm-muted);cursor:pointer}
43
+ .slm .slm-navigation .slm-navigation-tools button:hover{background:var(--slm-tint);color:var(--slm-text)}
44
+ .slm .slm-navigation .slm-navigation-tools button[aria-pressed=true],.slm .slm-navigation .slm-navigation-tools button[data-nav=search][aria-expanded=true],.slm .slm-navigation .slm-navigation-tools button[data-nav=zoom][aria-expanded=true]{background:var(--slm-accent);color:var(--slm-accent-ink)}
45
+ .slm .slm-navigation .slm-navigation-tools button[data-nav=rail]{margin-left:4px;position:relative}
46
+ .slm .slm-navigation .slm-navigation-tools button[data-nav=rail]::before{content:'';position:absolute;left:-4px;top:7px;bottom:7px;width:1px;background:var(--slm-line)}
47
+ .slm .slm-navigation .slm-navigation-tools button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
48
+ .slm-navigation button[hidden]{display:none}
49
+ .slm-navigation-search{position:relative;width:300px;max-width:100%;min-width:0;box-shadow:0 2px 8px #0002}
50
+ .slm-navigation input{width:100%;min-height:36px;padding:7px 10px;border:1px solid var(--slm-line);border-radius:7px;background:var(--slm-surface);color:var(--slm-text);font-size:13px}
51
+ .slm-navigation-results{position:absolute;top:100%;left:0;right:0;max-height:240px;overflow:auto;padding:6px;background:var(--slm-surface);border:1px solid var(--slm-line);border-radius:8px;box-shadow:0 8px 24px #0003}
52
+ .slm-navigation-results button{display:block;width:100%;text-align:left;margin-bottom:3px}
53
+ .slm.details-hidden .slm-rail{display:none}
54
+ .slm button:focus-visible,.slm input:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
55
+ .slm[data-theme="light"] .slm-scope.read{color:#465169}
56
+ .slm[data-theme="light"] .slm-scope.event,.slm[data-theme="light"] .slm-tablelock,.slm[data-theme="light"] .slm-kpidelta.down{color:#805500!important}
57
+ .slm[data-theme="light"] .slm-barbtn.follow.on,.slm[data-theme="light"] .slm-kpidelta{color:#17663f!important}
58
+
59
+
60
+ .slm [hidden]{display:none!important}
61
+ .slm-location{position:absolute;left:50%;top:calc(50% + 32px);transform:translateX(-50%);z-index:8;pointer-events:none;padding:7px 12px;border-radius:8px;background:var(--slm-text);color:var(--slm-bg);font-size:12px;font-weight:700;box-shadow:0 3px 12px #0003;white-space:nowrap}
62
+ .slm-location::before{content:"";position:absolute;left:50%;bottom:calc(100% + 8px);transform:translateX(-50%);width:48px;height:48px;border:3px solid var(--slm-text);border-radius:50%;box-shadow:0 0 0 3px var(--slm-bg)}
63
+ .slm-monitor-head{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:8px}
64
+ .slm-monitor-head h2{font-size:17px;letter-spacing:-.3px}
65
+ .slm-monitor-connection{font-size:12px;color:var(--slm-muted)}
66
+ .slm.live .slm-monitor-connection{color:#168153}
67
+ .slm-monitor-tabs{display:flex;border-bottom:1px solid var(--slm-line);margin-bottom:6px;gap:16px}
68
+ .slm .slm-monitor-tabs button{padding:0 0 7px;font-size:12px;color:var(--slm-muted);border-bottom:2px solid transparent}
69
+ .slm .slm-monitor-tabs button[aria-selected="true"]{color:var(--slm-text);border-color:var(--slm-accent);font-weight:700}
70
+ .slm-activity-filters{display:flex;gap:6px;margin-bottom:6px}
71
+ .slm-activity-filters label{flex:1;min-width:0;font-size:11px;color:var(--slm-muted)}
72
+ .slm-activity-filters select{width:100%;margin-top:0;padding:5px 7px;border-radius:5px;border:1px solid var(--slm-line);background:var(--slm-surface);color:var(--slm-text);font:inherit;font-size:12px}
73
+ .slm.monitor-view .slm-railscroll{display:flex;flex-direction:column;overflow:hidden}
74
+ .slm-monitor-head,.slm-monitor-tabs,.slm-activity-filters{flex:none}
75
+ .slm-monitor-activity,.slm-monitor-activity>[data-ref="feed"]{display:flex;flex-direction:column;flex:1;min-height:0}
76
+ .slm [data-monitor-panel="sections"]{overflow:auto;min-height:0}
77
+ .slm-activity-list{overflow:auto;flex:1;min-height:0;scrollbar-gutter:stable}
78
+
79
+ .slm-activity-entry{position:relative;border-bottom:1px solid var(--slm-line);display:flex;align-items:flex-start;min-width:0}
80
+ .slm .slm-activity-row{display:grid;grid-template-columns:58px 62px minmax(0,1fr);align-items:center;gap:7px;width:100%;min-width:0;height:29px;padding:0 2px;text-align:left;font-size:12px;line-height:1.2;border-radius:3px}
81
+ .slm .slm-activity-row:hover{background:var(--slm-surface)}
82
+ .slm-activity-row time{font-size:10px;color:var(--slm-muted);font-variant-numeric:tabular-nums;white-space:nowrap}
83
+ .slm-activity-row strong{display:block;text-align:center;font-size:10px;font-weight:700;padding:3px 2px;border-radius:4px;background:var(--slm-surface);color:var(--slm-muted);white-space:nowrap}
84
+ .slm-activity-entry[data-status="held"] strong{background:#b780171a;color:#946000}
85
+ .slm-activity-entry[data-status="booked"] strong{background:#1681531a;color:#14764d}
86
+ .slm[data-theme="dark"] .slm-activity-entry[data-status="held"] strong{background:#f2b44020;color:#f2bd59}
87
+ .slm[data-theme="dark"] .slm-activity-entry[data-status="booked"] strong{background:#2dc88d20;color:#6ed9ab}
88
+ .slm-activity-seats{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--slm-text);min-width:0}
89
+ .slm-activity-details{flex:none;font-size:11px}
90
+ .slm-activity-details summary{cursor:pointer;list-style:none;padding:6px 3px;color:var(--slm-muted)}
91
+ .slm-activity-details summary::-webkit-details-marker{display:none}
92
+ .slm-activity-details[open]{padding-bottom:68px}
93
+ .slm-activity-details p{position:absolute;left:0;right:0;top:29px;max-height:64px;overflow:auto;overflow-wrap:anywhere;background:var(--slm-surface);padding:6px;line-height:1.5;z-index:1}
94
+ .slm .slm-new-activity,.slm .slm-more-activity{width:100%;padding:9px;border-radius:7px;font-size:12px;margin:5px 0;background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text)}
95
+ .slm .slm-new-activity{background:var(--slm-accent);color:var(--slm-accent-ink)}
96
+ .slm-activity-empty{padding:22px 4px;color:var(--slm-muted);font-size:13px;line-height:1.6}
21
97
  /* top bar */
22
98
  /* FOUR columns, because the bar has four children: modes, the tools
23
99
  select, the live badge, and the actions. With three, the actions had no
@@ -66,6 +142,11 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
66
142
  @keyframes slm-kpi-delta{0%{opacity:0;transform:translateY(5px)}18%,72%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-5px)}}
67
143
  .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}
68
144
  .slm-barbtn:hover{border-color:var(--slm-muted)}
145
+ .slm .slm-barbtn.follow,.slm .slm-barbtn.heat{display:inline-flex;align-items:center;gap:6px;flex:none;white-space:nowrap;border:0;border-radius:6px;padding:5px 7px;min-height:30px;font-size:12px;background:transparent;color:var(--slm-text)}
146
+ .slm .slm-barbtn.follow::before,.slm .slm-barbtn.heat::before{content:'';flex:none;width:26px;height:15px;border-radius:12px;background:radial-gradient(circle at 7.5px 7.5px,var(--slm-bg) 5px,transparent 5.5px),var(--slm-muted)}
147
+ .slm .slm-barbtn.follow.on::before,.slm .slm-barbtn.heat.on::before{background:radial-gradient(circle at 18.5px 7.5px,var(--slm-accent-ink) 5px,transparent 5.5px),var(--slm-accent)}
148
+ .slm-follow-status,.slm-heat-status{position:absolute;bottom:14px;right:12px;max-width:calc(100% - 120px);padding:6px 9px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-bg);color:var(--slm-text);font-size:11px;z-index:5;pointer-events:none}
149
+ .slm-heat-status{bottom:48px}
69
150
  .slm-barbtn.follow.on{background:rgba(34,160,107,.13);border-color:#22a06b;color:#5bd39b}
70
151
 
71
152
  /* body */
@@ -73,7 +154,7 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
73
154
  .slm-map{position:relative;flex:1;min-width:0}
74
155
  .slm-map-host{position:absolute;inset:0}
75
156
  .slm-hud{position:absolute;left:12px;bottom:12px;display:flex;gap:8px}
76
- .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
157
+ .slm .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
77
158
  border:1px solid var(--slm-line);color:var(--slm-text)}
78
159
  .slm-zoomhint{position:absolute;left:50%;top:14px;transform:translateX(-50%);padding:6px 13px;border-radius:999px;
79
160
  background:rgba(0,0,0,.55);color:#fff;font-size:12px;font-weight:700;pointer-events:none;opacity:0;
@@ -91,13 +172,13 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
91
172
  .slm-rail{width:320px;flex:none;border-left:1px solid var(--slm-line);display:flex;flex-direction:column;min-height:0}
92
173
  .slm-railscroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px}
93
174
  .slm-eyebrow{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--slm-muted);font-weight:800;margin-bottom:6px}
94
- .slm-hint{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}
175
+ .slm-hint{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:8px}
95
176
  /* rail header: title + scope badge, then one plain sentence \u2014 every tool opens the same way */
96
177
  .slm-railhead{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:6px}
97
178
  .slm-railhead .slm-eyebrow{margin-bottom:0;font-size:11px;color:var(--slm-text)}
98
179
  .slm-scope{flex:none;padding:2px 8px;border-radius:999px;font-size:9.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;white-space:nowrap}
99
- .slm-scope.read{background:rgba(139,148,172,.16);color:#c2c9d8}
100
- .slm-scope.event{background:rgba(244,183,64,.16);color:#f7ca6b}
180
+ .slm-scope.read{background:rgba(139,148,172,.16);color:var(--slm-text)}
181
+ .slm-scope.event{background:rgba(244,183,64,.16);color:var(--slm-text)}
101
182
  .slm-scope.host{background:color-mix(in srgb,var(--slm-accent) 18%,transparent);color:var(--slm-accent)}
102
183
  .slm-step{display:flex;align-items:center;gap:7px}
103
184
  .slm-stepnum{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;background:var(--slm-accent);color:var(--slm-accent-ink);font-size:9.5px;letter-spacing:0}
@@ -125,7 +206,7 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
125
206
  .slm-empty{font-size:12.5px;color:var(--slm-muted);padding:12px 0}
126
207
 
127
208
  /* block toolbar */
128
- .slm-selbar{display:flex;align-items:baseline;gap:8px;margin-bottom:10px}
209
+ .slm-selbar{display:flex;align-items:baseline;gap:6px;margin-bottom:6px}
129
210
  .slm-selnum{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums}
130
211
  .slm-sellabel{font-size:12px;color:var(--slm-muted);font-weight:600}
131
212
  .slm-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
@@ -163,7 +244,15 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
163
244
  color:var(--slm-muted);font-size:10.5px}
164
245
  .slm-linkbtn{font-size:11px!important;font-weight:800!important;color:var(--slm-accent)!important;text-align:right}
165
246
  .slm-linkbtn:disabled{opacity:.45;cursor:not-allowed}
166
- .slm-blockedlist{max-height:246px;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
247
+ .slm .slm-blockedsummary .slm-linkbtn{color:var(--slm-text)}
248
+ .slm-block-seatline{display:flex;align-items:center}
249
+ .slm .slm-block-seatline>button:last-child{color:var(--slm-text);font-size:11px;padding:7px;background:transparent;border:0;cursor:pointer}
250
+ .slm-block-group{border-bottom:1px solid var(--slm-line);padding:7px}
251
+ .slm-block-grouphead{display:flex;align-items:center;justify-content:space-between;gap:8px}
252
+ .slm .slm-block-grouphead button{color:var(--slm-text);font-size:11px;text-align:left;padding:4px;background:transparent;border:0;cursor:pointer}
253
+ .slm-block-grouphead small{display:block;color:var(--slm-muted);font-size:10px;margin-top:3px}
254
+ .slm-block-group summary{font-size:11px;color:var(--slm-muted);cursor:pointer;padding:5px}
255
+ .slm-blockedlist{max-height:none;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
167
256
  border-radius:10px;background:var(--slm-surface)}
168
257
  .slm-blockeditem{display:grid!important;grid-template-columns:18px minmax(0,1fr);width:100%;gap:8px;padding:8px 9px!important;
169
258
  border-bottom:1px solid var(--slm-line)!important;text-align:left!important}
@@ -189,8 +278,8 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
189
278
  .slm-toast.ok{background:#1f7a4d;color:#fff;border-color:#1f7a4d}
190
279
 
191
280
  /* control-room actions + insights */
192
- .slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:7px}
193
- .slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:#f7ca6b}
281
+ .slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:5px;flex-wrap:wrap}
282
+ .slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:var(--slm-text)}
194
283
  .slm-sectionlist{display:flex;flex-direction:column;gap:8px;margin-top:4px}
195
284
  .slm-sectionlist + .slm-eyebrow{margin-top:18px}
196
285
  .slm-sectionrow{width:100%;padding:10px!important;border:1px solid var(--slm-line)!important;border-radius:10px;
@@ -205,6 +294,21 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
205
294
  .slm-health{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}
206
295
  .slm-healthitem{padding:10px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface)}
207
296
  .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}
297
+ .slm-seat-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
298
+ .slm-seat-heading h2{font-size:18px;margin:0}
299
+ .slm-seat-heading [data-seat-status]{font-size:12px;text-transform:capitalize}
300
+ .slm-seat-history{display:flex;flex-direction:column;min-height:0;flex:1;gap:6px}
301
+ .slm-history-counts{display:flex;flex-wrap:wrap;gap:4px;margin:5px 0}
302
+ .slm-history-counts button{font:inherit;font-size:11px;padding:3px 6px;border:1px solid var(--slm-line);border-radius:5px;background:var(--slm-bg);color:var(--slm-muted);cursor:pointer}
303
+ .slm-history-counts button[aria-pressed=true]{color:var(--slm-text);border-color:var(--slm-accent)}
304
+ .slm-history-list{min-height:0;overflow:auto;flex:1}
305
+ .slm-history-row{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:30px;border-bottom:1px solid var(--slm-line);font-size:11px}
306
+ .slm-history-row time{color:var(--slm-muted);font-variant-numeric:tabular-nums}
307
+ .slm-history-row strong{font-size:10px;text-transform:uppercase;border-radius:4px;padding:3px 6px;background:var(--slm-surface);color:var(--slm-text)}
308
+ .slm-history-row[data-action=hold] strong{color:#a66c00;background:#e9ad2220}
309
+ .slm-history-row[data-action=book] strong{color:#168251;background:#20976520}
310
+ .slm[data-theme=dark] .slm-history-row[data-action=hold] strong{color:#f6c65c}
311
+ .slm[data-theme=dark] .slm-history-row[data-action=book] strong{color:#63d6a0}
208
312
  .slm-sectionhead{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-top:18px}
209
313
  .slm-windows{display:flex;gap:3px;padding:2px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-surface)}
210
314
  .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)}
@@ -219,14 +323,35 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
219
323
  /* Mixed toward the INK rather than toward black: on a light ground a black
220
324
  mix is the only thing on the surface that reads as dark. */
221
325
  .slm-availrow.zone{background:color-mix(in srgb,var(--slm-surface) 82%,var(--slm-text))}
222
- .slm-availrow.hidden{opacity:.62}.slm-availrow.closed{opacity:.82}
326
+ .slm-availrow.hidden,.slm-availrow.closed{opacity:1}
327
+ .slm-themed-picker{min-width:0;width:100%}
328
+ .slm-themed-picker summary{display:flex;align-items:center;justify-content:space-between;gap:12px;text-align:left;list-style:none;padding:8px 10px;border:1px solid var(--slm-line);border-radius:7px;background:var(--slm-surface);color:var(--slm-text);font-size:12px;cursor:pointer}
329
+ .slm-themed-picker summary::-webkit-details-marker{display:none}
330
+ .slm-themed-picker summary::after{content:'\u2304';flex:none;margin-left:auto;line-height:1;color:var(--slm-muted)}
331
+ .slm-themed-picker summary[aria-disabled=true]{opacity:.55;cursor:wait}
332
+ .slm-themed-picker summary:focus-visible,.slm-themed-options button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
333
+ .slm-themed-options{display:flex;flex-direction:column;max-height:220px;overflow:auto;margin-top:4px;padding:4px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-bg);box-shadow:0 4px 14px #0001}
334
+ .slm .slm-themed-options button{text-align:left;padding:8px;border:0;border-radius:5px;background:transparent;color:var(--slm-text);font-size:12px;cursor:pointer}
335
+ .slm .slm-themed-options button:hover,.slm .slm-themed-options button[aria-pressed=true]{background:var(--slm-tint-strong)}
336
+ .slm-themed-options button[aria-pressed=true]::after{content:' \u2713';float:right}
337
+ .slm-availpicker{margin-top:7px}
338
+ .slm-availpicker summary{display:flex;align-items:center;justify-content:space-between;list-style:none;cursor:pointer;border:1px solid var(--slm-line);border-radius:7px;padding:7px 9px;font-size:12px;font-weight:600;color:var(--slm-text);background:var(--slm-bg)}
339
+ .slm-availpicker summary::-webkit-details-marker{display:none}
340
+ .slm-availpicker summary:focus-visible,.slm-availchoices button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
341
+ .slm-availpicker[open] summary{border-color:var(--slm-accent)}
342
+ .slm-availpicker summary[aria-disabled=true]{opacity:.55;cursor:wait}
343
+ .slm-availchoices{margin-top:5px;padding:4px;border:1px solid var(--slm-line);border-radius:9px;background:var(--slm-bg);box-shadow:0 4px 14px #0001}
344
+ .slm-availchoices button{display:flex;align-items:center;justify-content:space-between;gap:6px;width:100%;text-align:left;padding:7px 8px;border:0;border-radius:5px;cursor:pointer;color:var(--slm-text);background:transparent}
345
+ .slm-availchoices button:hover,.slm-availchoices button[aria-pressed=true]{background:var(--slm-tint-strong)}
346
+ .slm-availchoices b{display:block;font-size:12px;font-weight:600}
347
+ .slm-availchoices small{display:block;margin-top:2px;font-size:10px;color:var(--slm-muted)}
223
348
  .slm-availhead{display:flex;align-items:center;gap:8px}
224
349
  .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}
225
350
  .slm-availcaret{flex:none;color:var(--slm-muted);font-size:10px}
226
351
  .slm-availcount{flex:none;font-size:11px;font-weight:700;color:var(--slm-muted);font-variant-numeric:tabular-nums}
227
352
  .slm-availbadge{flex:none;font-size:9px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;padding:2px 6px;border-radius:999px}
228
- .slm-availbadge.hidden{background:rgba(139,148,172,.18);color:#c2c9d8}
229
- .slm-availbadge.closed{background:rgba(244,183,64,.16);color:#f7ca6b}
353
+ .slm-availbadge.hidden{background:rgba(139,148,172,.18);color:var(--slm-text)}
354
+ .slm-availbadge.closed{background:rgba(244,183,64,.16);color:var(--slm-text)}
230
355
  .slm-availselwrap{position:relative;flex:none;display:inline-flex}
231
356
  .slm-availmode{width:auto;max-width:190px;padding:6px 8px;font-size:11.5px;font-weight:700;cursor:pointer}
232
357
  .slm-availmode.on{border-color:var(--slm-accent);color:var(--slm-text)}
@@ -240,7 +365,7 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
240
365
  .slm-availdot{width:9px;height:9px;border-radius:50%;flex:none;background:#22a06b}.slm-availdot.warn{background:#f4b740}
241
366
  .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)}
242
367
  .slm-availstar{flex:none;margin-top:1px;color:#f4b740;font-size:13px;line-height:1}
243
- .slm-availcallout p{font-size:11.5px;line-height:1.55;color:#f4d58a}.slm-availcallout b{color:#ffe4a3;font-weight:800}
368
+ .slm-availcallout p{font-size:11.5px;line-height:1.55;color:var(--slm-text)}.slm-availcallout b{color:inherit;font-weight:800}
244
369
  .slm-inspect-card{padding:16px;border:1px solid var(--slm-line);border-radius:12px;background:var(--slm-surface)}
245
370
  .slm-inspect-label{font-size:24px;font-weight:850;letter-spacing:-.02em;line-height:1.1}
246
371
  .slm-inspect-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px;margin-top:18px}
@@ -276,6 +401,8 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
276
401
 
277
402
  .slm.compact .slm-rail{width:100%;border-left:0;border-top:1px solid var(--slm-line);height:44%}
278
403
  .slm.compact .slm-body{flex-direction:column}
404
+ .slm.compact.monitor-view{min-height:760px}
405
+ .slm.compact.monitor-view .slm-rail{height:55%;min-height:260px}
279
406
  .slm.compact .slm-bar{grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:8px}
280
407
  .slm.compact .slm-modes{display:none}
281
408
  .slm.compact .slm-tools{display:block;width:100%;padding:9px 13px;min-height:44px;border:1px solid var(--slm-line);
@@ -301,47 +428,44 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
301
428
  transition:none!important;
302
429
  scroll-behavior:auto!important}
303
430
  }
304
- `;function O(){if(typeof document>"u"||document.getElementById(I))return;let d=document.createElement("style");d.id=I,d.textContent=Le,document.head.appendChild(d)}function z(d){if(typeof document>"u"||document.getElementById(B))return;let e=document.createElement("style");e.id=B,e.textContent=d,document.head.appendChild(e)}import{formatMoney as Te}from"@seatlayer/core";function F(d){return d?d.mode:"open"}function j(d,e,t){switch(d){case"open":return null;case"hidden":return{mode:"hidden",labels:e};case"closed":return{mode:"closed",labels:e};case"timed":return{mode:"timed",revealAt:t?.revealAt??Date.now()+36e5,labels:e};case"threshold":return{mode:"threshold",thresholdPct:t?.thresholdPct??80,labels:e}}}function D(d){return new Date(d-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function P(d){if(typeof d=="string"){let e=document.querySelector(d);if(!e)throw new Error(`seatmanager: container "${d}" not found`);return e}if(!(d instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return d}function R(d){if(!d.startsWith("mse_"))throw new Error("seatmanager: token must be a short-lived event-scoped mse_ grant minted by your backend; tenant secret keys are unsupported in browsers")}function k(d){return d==="blocked"?"not_for_sale":d}var V=[{key:"free",label:"Free",color:"#6e7bff"},{key:"held",label:"Held",color:"#f4b740"},{key:"booked",label:"Booked",color:"#22a06b"},{key:"blocked",label:"Blocked",color:"#8b94ac"}];function N(d,e){let t=d??{},s=e?T[e]:null,i=e==="light";return{"--slm-bg":t.background??s?.background??"#0e1017","--slm-surface":s?.surface??"#181b24","--slm-text":s?.text??"#eef1f7","--slm-muted":s?.muted??"#8b93a7","--slm-line":s?.line??"rgba(255,255,255,.09)","--slm-tint":i?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":i?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??"#6e7bff","--slm-accent-ink":t.accentInk??"#ffffff","--slm-font":"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif","--slm-radius":"14px"}}function q(d){return d?T[d].map:null}function E(d,e){let t=Math.max(0,Math.round((e-d)/1e3));if(t<5)return"just now";if(t<60)return`${t}s ago`;let s=Math.round(t/60);return s<60?`${s}m ago`:`${Math.round(s/60)}h ago`}function y(d,e){return Te(d,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function p(d){return String(d??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}import{UNGROUPED_ID as Me}from"@seatlayer/core";function A(d){return Object.entries(d).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function w(d){let e=d.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=d.doc?.zones??[],s=new Map,i=[];for(let c of e.sections)if(c.zone&&t.some(n=>n.id===c.zone)){let n=s.get(c.zone)??[];n.push(c),s.set(c.zone,n)}else i.push(c);let o=[],a=0,l=0,r=(c,n,h,m=!1)=>{let u=d.availabilityRules[n.id]??null,b=d.effectiveClosed.has(n.id)||m,f=d.effectiveHidden.has(n.id)||h&&!b;c==="section"&&f&&(a+=1),c==="section"&&b&&(l+=1),o.push({kind:c,id:n.id,label:n.label,seatCount:n.seatCount,seatLabels:n.seatLabels,rule:u,hidden:f,closed:b,followsZone:c==="section"&&h})};for(let c of t){let n=s.get(c.id);if(!n||!n.length)continue;let h={id:c.id,label:c.label||"Zone",seatCount:n.reduce((b,f)=>b+f.seatCount,0),seatLabels:n.flatMap(b=>b.seatLabels)},m=!!d.availabilityRules[c.id],u=d.availabilityRules[c.id]?.mode==="closed";r("zone",h,!1);for(let b of n)r("section",b,m,u)}for(let c of i)r("section",c,!1);if(e.ungrouped){let c=e.ungrouped;r("section",{id:Me,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels},!1)}return{rows:o,hiddenSections:a,closedSections:l}}function _(d,e){let t=F(d.rule),s=`slm-availrow${d.kind==="zone"?" zone":""}${d.hidden?" hidden":""}${d.closed?" closed":""}`,i=e?" disabled":"",o=(n,h)=>`<option value="${n}"${t===n?" selected":""}>${h}</option>`,a=d.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<span class="slm-availselwrap">
305
- <select class="slm-select slm-availmode${t!=="open"?" on":""}" data-avail-id="${p(d.id)}"${i} aria-label="Availability for ${p(d.label)}">
306
- ${o("open","Open \u2014 on sale")}
307
- ${o("closed","Closed \u2014 visible, not on sale")}
308
- ${o("hidden","Hidden \u2014 off the buyer map")}
309
- ${o("timed","Reveal at a time")}
310
- ${o("threshold","Auto-reveal at % sold")}
311
- </select>
312
- </span>`,l="";if(!d.followsZone&&t==="timed"){let n=d.rule?.revealAt?p(D(d.rule.revealAt)):"";l=`<div class="slm-availdetail">
313
- <input type="datetime-local" class="slm-input" data-avail-reveal="${p(d.id)}" value="${n}"${i} aria-label="Reveal time for ${p(d.label)}" />
314
- </div>`}else if(!d.followsZone&&t==="threshold"){let n=d.rule?.thresholdPct??80;l=`<div class="slm-availdetail">
431
+ `;function q(){if(typeof document>"u"||document.getElementById(D))return;let h=document.createElement("style");h.id=D,h.textContent=Be,document.head.appendChild(h)}function V(h){if(typeof document>"u"||document.getElementById(N))return;let e=document.createElement("style");e.id=N,e.textContent=h,document.head.appendChild(e)}import{formatMoney as Ie}from"@seatlayer/core";function _(h){return h?h.mode:"open"}function U(h,e,t){switch(h){case"open":return null;case"hidden":return{mode:"hidden",labels:e};case"closed":return{mode:"closed",labels:e};case"timed":return{mode:"timed",revealAt:t?.revealAt??Date.now()+36e5,labels:e};case"threshold":return{mode:"threshold",thresholdPct:t?.thresholdPct??80,labels:e}}}function K(h){return new Date(h-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function W(h){if(typeof h=="string"){let e=document.querySelector(h);if(!e)throw new Error(`seatmanager: container "${h}" not found`);return e}if(!(h instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return h}function B(h){if(!h.startsWith("mse_"))throw new Error("seatmanager: token must be a short-lived event-scoped mse_ grant minted by your backend; tenant secret keys are unsupported in browsers")}function M(h){return h==="blocked"?"not_for_sale":h}var G=[{key:"free",label:"Free",color:"#6e7bff"},{key:"held",label:"Held",color:"#f4b740"},{key:"booked",label:"Booked",color:"#22a06b"},{key:"blocked",label:"Blocked",color:"#8b94ac"}];function Z(h,e){let t=h??{},s=e?A[e]:null,i=e==="light";return{"--slm-bg":t.background??s?.background??"#0e1017","--slm-surface":s?.surface??"#181b24","--slm-text":s?.text??"#eef1f7","--slm-muted":s?.muted??"#8b93a7","--slm-line":s?.line??"rgba(255,255,255,.09)","--slm-tint":i?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":i?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??(i?"#4654c8":"#6e7bff"),"--slm-accent-ink":t.accentInk??"#ffffff","--slm-font":"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif","--slm-radius":"14px"}}function Y(h){return h?A[h].map:null}function X(h,e){let t=Math.max(0,Math.round((e-h)/1e3));if(t<5)return"just now";if(t<60)return`${t}s ago`;let s=Math.round(t/60);return s<60?`${s}m ago`:`${Math.round(s/60)}h ago`}function C(h,e){return Ie(h,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function p(h){return String(h??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}import{UNGROUPED_ID as ze}from"@seatlayer/core";function I(h){return Object.entries(h).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function E(h){let e=h.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=h.doc?.zones??[],s=new Map,i=[];for(let c of e.sections)if(c.zone&&t.some(n=>n.id===c.zone)){let n=s.get(c.zone)??[];n.push(c),s.set(c.zone,n)}else i.push(c);let a=[],o=0,l=0,r=(c,n,d,m=!1)=>{let b=h.availabilityRules[n.id]??null,g=h.effectiveClosed.has(n.id)||m,v=h.effectiveHidden.has(n.id)||d&&!g;c==="section"&&v&&(o+=1),c==="section"&&g&&(l+=1),a.push({kind:c,id:n.id,label:n.label,seatCount:n.seatCount,seatLabels:n.seatLabels,rule:b,hidden:v,closed:g,followsZone:c==="section"&&d})};for(let c of t){let n=s.get(c.id);if(!n||!n.length)continue;let d={id:c.id,label:c.label||"Zone",seatCount:n.reduce((g,v)=>g+v.seatCount,0),seatLabels:n.flatMap(g=>g.seatLabels)},m=!!h.availabilityRules[c.id],b=h.availabilityRules[c.id]?.mode==="closed";r("zone",d,!1);for(let g of n)r("section",g,m,b)}for(let c of i)r("section",c,!1);if(e.ungrouped){let c=e.ungrouped;r("section",{id:ze,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels},!1)}return{rows:a,hiddenSections:o,closedSections:l}}function Q(h,e){let t=_(h.rule),s=`slm-availrow${h.kind==="zone"?" zone":""}${h.hidden?" hidden":""}${h.closed?" closed":""}`,i=e?" disabled":"",a=[["open","Open","Available to buy"],["closed","Closed","Visible on the map, unavailable to buy"],["hidden","Hidden","Removed from the buyer map"],["timed","Scheduled reveal","Open at a specific date and time"],["threshold","Demand-based reveal","Open when sales reach a percentage"]],o=h.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
432
+ <summary aria-label="Availability for ${p(h.label)}" ${e?'aria-disabled="true"':""}>${a.find(n=>n[0]===t)[1]}<span aria-hidden="true">\u2304</span></summary>
433
+ <div class="slm-availchoices" aria-label="Availability options for ${p(h.label)}">
434
+ ${a.map(([n,d,m])=>`<button type="button" data-avail-id="${p(h.id)}" data-avail-value="${n}" aria-pressed="${t===n}"${i}><span><b>${d}</b><small>${m}</small></span><span aria-hidden="true">${t===n?"\u2713":""}</span></button>`).join("")}
435
+ </div>
436
+ </details>`,l="";if(!h.followsZone&&t==="timed"){let n=h.rule?.revealAt?p(K(h.rule.revealAt)):"";l=`<div class="slm-availdetail">
437
+ <input type="datetime-local" class="slm-input" data-avail-reveal="${p(h.id)}" value="${n}"${i} aria-label="Reveal time for ${p(h.label)}" />
438
+ </div>`}else if(!h.followsZone&&t==="threshold"){let n=h.rule?.thresholdPct??80;l=`<div class="slm-availdetail">
315
439
  <span class="slm-availpctlabel">Reveal at</span>
316
- <input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${p(d.id)}" value="${p(n)}"${i} aria-label="Percent sold to reveal ${p(d.label)}" />
440
+ <input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${p(h.id)}" value="${p(n)}"${i} aria-label="Percent sold to reveal ${p(h.label)}" />
317
441
  <span class="slm-availpctlabel">% sold</span>
318
- </div>`}let r=d.closed?'<span class="slm-availbadge closed">Closed</span>':d.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",c=d.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${d.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
442
+ </div>`}let r=h.closed?'<span class="slm-availbadge closed">Closed</span>':h.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",c=h.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${h.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
319
443
  <div class="slm-availhead">
320
- <span class="slm-availlabel">${c}${p(d.label)}</span>
444
+ <span class="slm-availlabel">${c}${p(h.label)}</span>
321
445
  ${r}
322
- <span class="slm-availcount">${d.seatCount.toLocaleString()}</span>
323
- ${a}
446
+ <span class="slm-availcount">${h.seatCount.toLocaleString()}</span>
324
447
  </div>
448
+ ${o}
325
449
  ${l}
326
- </div>`}var Ie="https://api.seatlayer.io",x=80,Be=16,U=4,K=[{key:"watch",label:"Watch",tools:[{mode:"view",label:"Monitor",shortcut:"M",title:"Live board \u2014 inventory, activity and booking momentum. Read-only."},{mode:"inspect",label:"Inspect",shortcut:"I",title:"Click one seat to read its live status and booking context. Read-only."}]},{key:"manage",label:"Manage",tools:[{mode:"block",label:"Block",shortcut:"B",title:"Take seats off sale for this event, or put them back."},{mode:"sections",label:"Sections",shortcut:"S",title:"Open, close or hide sections for this event, on a schedule or on demand."},{mode:"categories",label:"Categories",shortcut:"G",title:"Move seats to a different price category for this event only."},{mode:"tables",label:"Tables",shortcut:"T",title:"Sell each table per chair or as one whole-table booking."},{mode:"channels",label:"Channels",shortcut:"C",title:"Allocate inventory to sales channels and share their links."}]},{key:"host",label:"Host tools",tools:[{mode:"select",label:"Select",shortcut:"X",title:"Select seats for your own back-office operation. The selection is handed to your app; nothing changes here."},{mode:"filterSections",label:"Filter",shortcut:"L",title:"Filter the map to one section for your own reporting."}]}],Oe=Object.fromEntries(K.flatMap(d=>d.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),$=class{constructor(e){this.els={};this.renderer=null;this.doc=null;this.themeMode=null;this.colorSchemeStop=null;this.inventoryModelVersion=1;this.selectableObjectLabels=new Set;this.lastSelectionLabels=new Set;this.selectionWasValid=null;this.initialSelectionApplied=!1;this.labelToId=new Map;this.labelToSeat=new Map;this.allIds=[];this.gaUnitLabelSet=new Set;this.status=new Map;this.counts={held:0,booked:0,blocked:0};this.modelVersion=0;this.currency="USD";this.authoritativeCurrency=null;this.authoritativeGrossRevenue=0;this.revenueStatus="loading";this.revenueRequest=0;this.controlRoomSnapshot=null;this.serverBaseline=null;this.livePresence=null;this.liveGross=null;this.paintHandle=null;this.trendWindowMinutes=15;this.heatEnabled=!1;this.lastKpiValues=new Map;this.activeKpiDeltas=new Map;this.ws=null;this.reconnectTimer=null;this.attempt=0;this.closed=!1;this.connectionStatus="reconnecting";this.lastMessageAt=null;this.ready=!1;this.feed=[];this.feedTimer=null;this.toastTimer=null;this.liveEventTimer=null;this.kpiCleanupTimer=null;this.followLiveTimer=null;this.followSeatTimer=null;this.releaseAt=null;this.layoutObserver=null;this.tokenExpiresAt=null;this.tokenRefreshTimer=null;this.tokenRefreshInFlight=!1;this.sectionByObject=new Map;this.sectionLabelById=new Map;this.sectionsBase=null;this.filteredSectionLabel=null;this.availabilityRules={};this.effectiveHidden=new Set;this.effectiveClosed=new Set;this.availabilitySaving=!1;this.lastSyncedAt=null;this.blockedQuery="";this.blockedSection="";this.blockedResultLimit=100;this.unblockAllConfirmTimer=null;this.channels=null;this.channelCaps={view:!1,manage:!1};this.categoryCanManage=!1;this.tableCanManage=!1;this.tableBookingSaving=!1;this.channelCapabilityResolution=0;this.channelsLoading=null;this.onFullscreenChange=()=>{this.paintFullscreenButton(),this.updateContainerLayout(),this.renderer?.forceDraw()};this.onKeyDown=e=>{if(e.metaKey||e.ctrlKey||e.altKey||e.target?.matches('input,select,textarea,[contenteditable="true"]'))return;let s=e.key.toLowerCase(),i=Oe[s];if(i){if(!this.toolAvailable(i))return;this.setMode(i)}else if(s==="f")this.toggleFullscreen();else if(s==="escape"){if(!this.channels?.handleBack())return}else return;e.preventDefault()};this.onRailClick=e=>{let t=e.target,s=t?.closest("[data-section-focus]");if(s?.dataset.sectionFocus){this.locateSection(s.dataset.sectionFocus);return}let i=t?.closest("[data-feed-id]");i?.dataset.feedId&&this.locateActivity(i.dataset.feedId)};this.sectionOptions=[];R(e.token),this.assertSelectionOptions(e.maxSelectedObjects,e.numberOfPlacesToSelect),this.opts=e,this.key=e.eventKey,this.mode=e.mode??"view",this.selectableObjectLabels=new Set(e.selectableObjects??[]),this.categoryCanManage=new Set(e.capabilities??[]).has("event:categories:manage"),this.tableCanManage=new Set(e.capabilities??[]).has("event:tables:manage"),this.keepLive=e.keepLiveWhileHidden??!0,this.themeMode=e.themeMode??null,this.followLive=e.followLive??!1,this.currency=e.currency??"USD",this.tokenExpiresAt=e.tokenExpiresAt??null,this.api=new C(e.apiBase??Ie,e.token),this.organizerAssetUrls=new S(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=P(e.container)}assertSelectionOptions(e,t){let s=i=>i===void 0||Number.isInteger(i)&&i>0;if(!s(e))throw new TypeError("maxSelectedObjects must be a positive integer");if(!s(t))throw new TypeError("numberOfPlacesToSelect must be a positive integer");if(e!==void 0&&t!==void 0&&e<t)throw new TypeError("maxSelectedObjects cannot be lower than numberOfPlacesToSelect")}async render(){O(),this.buildChrome();try{let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1,this.doc=await this.organizerAssetUrls.prepareRendererChart(e.doc),this.authoritativeCurrency=e.event.currency??null,this.currency=this.authoritativeCurrency??this.opts.currency??this.currency,this.buildUnitUniverse(this.doc),this.buildRenderer(),this.buildSectionOptions(),this.settleMode();let[,t]=await Promise.all([this.resnapshot(),this.refreshControlRoom().catch(s=>this.opts.onError?.(s)),this.refreshAvailability()]);t?.activity?this.seedFeed(t.activity):this.api.log(this.key,{limit:24}).then(s=>this.seedFeed(s.entries)).catch(()=>{}),this.connect(),this.startFeedClock(),this.ready=!0,await this.resolveChannelCapabilities(),this.setMode(this.mode),this.applyInitialSelection(),this.scheduleTokenRefresh(),this.opts.onReady?.()}catch(e){this.fail(e)}return this}setMode(e){this.toolAvailable(e)||(e="view"),e==="channels"&&!this.channels&&this.ensureChannels();let t=e!==this.mode,s=this.mode==="channels",i=this.mode==="filterSections";this.mode=e,!this.renderer&&this.doc?this.buildRenderer():this.updateRendererInteraction(),t&&(this.renderer?.clearSelection(),this.syncSelection()),s&&e!=="channels"&&this.channels?.leave(),this.paintModeTabs(),this.paintRail(),this.applySectionCanvasTreatment(),i&&e!=="filterSections"&&this.renderer?.zoomToFit(),e==="channels"&&this.channels?.enter(),e==="select"&&this.applyInitialSelection(),t&&this.opts.onModeChange?.(e)}async resolveChannelCapabilities(){let e=++this.channelCapabilityResolution,t=this.opts.capabilities,s;if(t){let i=new Set(t);s={view:i.has("event:channels:view"),manage:i.has("event:channels:view")&&i.has("event:channels:manage")}}else s={view:!1,manage:!1};if(!s.view&&!t)try{await this.api.channels(this.key),s={view:!0,manage:!1}}catch{s={view:!1,manage:!1}}if(e===this.channelCapabilityResolution){if(this.channelCaps=s,!this.channelCaps.view){this.channels?.destroy(),this.channels=null,this.mode==="channels"?this.setMode("view"):this.paintModeTabs();return}this.channels?.setCapabilities(this.channelCaps),this.paintModeTabs()}}ensureChannels(){if(this.channelsLoading)return this.channelsLoading;if(this.channels)return Promise.resolve();let e=(async()=>{try{let t=await import("./channelsMode-M44RRKNM.js");if(this.closed||!this.channelCaps.view||(this.channels||(z(t.CHANNELS_CSS),this.channels=new t.ChannelsMode(this.buildChannelsHost(),this.channelCaps),this.channels.onInteractionChange=()=>this.updateRendererInteraction()),this.mode!=="channels"))return;this.updateRendererInteraction(),this.paintRail(),this.channels.enter()}catch(t){if(this.closed)return;this.channelsLoading=null,this.mode==="channels"&&this.paintRail(),this.opts.onError?.(t)}})();return this.channelsLoading=e,e}buildChannelsHost(){return{eventKey:this.key,api:this.api,rail:this.els.rail,mapLayer:this.root.querySelector(".slm-map"),root:this.root,seats:()=>[...this.labelToSeat.values()].map(e=>({id:e.id,label:e.label,x:e.x,y:e.y})),statusOf:e=>this.status.get(e)??(this.labelToSeat.has(e)?"free":void 0),selectionLabels:()=>this.selectionLabels(),selectByLabels:e=>{this.selectByLabels(e)},clearSelection:()=>this.clearSelection(),selectSection:e=>{this.selectSection(e)},sections:()=>this.sectionOptions,labelsInSection:e=>this.renderer?.getSelectableInSection(e).map(t=>t.label)??[],rows:()=>{let e=new Map((this.doc?.objects??[]).map(s=>[s.id,s])),t=new Map;for(let s of this.labelToSeat.values()){let i=e.get(s.rowId);if(!i||i.type!=="row"&&i.type!=="table")continue;let o=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??g,l=t.get(o)??{id:o,label:i.type==="row"?i.segmentedRow?.displayLabel??i.displayLabel??i.label:i.displayLabel??i.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};l.labels.push(s.label),t.set(o,l)}return[...t.values()].sort((s,i)=>s.sectionLabel.localeCompare(i.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))},categories:()=>(this.doc?.categories??[]).map(e=>({key:e.key,label:e.label??e.key,color:e.color,price:e.price,tiers:e.tiers?.map(t=>({id:t.id,name:t.name,price:t.price}))})),labelsInCategory:e=>[...this.labelToSeat.entries()].filter(([,t])=>t.categoryKey===e).map(([t])=>t),sectionOfLabel:e=>{let t=this.labelToSeat.get(e);if(!t)return null;let s=this.sectionByObject.get(t.rowId)??g;return{id:s,label:this.sectionLabelById.get(s)??"Other seats"}},worldToScreen:e=>this.renderer?.worldToScreen(e)??null,seatPixelSize:()=>this.seatPixelSize(),isSeatDetail:()=>this.renderer?.getRung?.()==="seats",showSectionOverview:()=>{this.renderer?.clearSectionFocus(),this.renderer?.setRung?.("sections")},focusSection:e=>this.renderer?.focusSection(e),isCompact:()=>!!this.root?.classList.contains("compact"),setMapInert:e=>{this.mapHost.toggleAttribute("inert",e),this.mapHost.setAttribute("aria-hidden",String(e))},toast:(e,t)=>this.toast(e,t),onError:e=>this.opts.onError?.(e)}}seatPixelSize(){let e=this.renderer?.getVisibleWorldRect?.(),t=this.mapHost?.clientWidth??0;return!e?.width||!t?6:Math.max(3,t/e.width*18)}setHeatOverlay(e){this.heatEnabled=e,this.applyHeatOverlay(),this.paintHeatButton()}setFollowLive(e){let t=this.followLive!==e;this.followLive=e,e||(this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=null,this.followSeatTimer=null),this.paintFollowLiveButton(),t&&this.opts.onFollowLiveChange?.(e)}setKeepLiveWhileHidden(e){this.keepLive=e??!0,this.opts.keepLiveWhileHidden=e}setCurrency(e){this.opts.currency=e,!this.authoritativeCurrency&&(this.currency=e??"USD",this.ready&&this.recomputeTallies())}setTheme(e){this.opts.theme=e,this.applyThemeVars()}applyThemeVars(){if(!this.root)return;let e=M(this.themeMode);for(let[t,s]of Object.entries(N(this.opts.theme,e)))this.root.style.setProperty(t,s);e?this.root.dataset.theme=e:delete this.root.dataset.theme}watchThemeMode(){this.colorSchemeStop?.(),this.colorSchemeStop=null,this.themeMode==="auto"&&(this.colorSchemeStop=H(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(s=>s.id);e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),this.updateZoomHint()}setThemeMode(e){let t=e??null;this.closed||t===this.themeMode||(this.themeMode=t,this.opts.themeMode=t??void 0,this.watchThemeMode(),this.repaintForThemeMode())}getThemeMode(){return this.themeMode}themedDoc(){let e=this.doc,t=q(M(this.themeMode));return t?{...e,theme:{...e.theme??{},background:t}}:e}setCapabilities(e){this.opts.capabilities=e,this.categoryCanManage=new Set(e??[]).has("event:categories:manage"),this.tableCanManage=new Set(e??[]).has("event:tables:manage"),!this.categoryCanManage&&this.mode==="categories"||!this.tableCanManage&&this.mode==="tables"?this.setMode("view"):this.paintModeTabs(),this.ready&&this.resolveChannelCapabilities()}setTokenRefresh(e){this.opts.onTokenRefresh=e,this.scheduleTokenRefresh()}setTrendWindow(e){let t=Number.isFinite(e)?Math.floor(e):15;return this.trendWindowMinutes=Math.max(5,Math.min(60,t)),this.paintTrendWindow(),this.refreshControlRoom()}async enterFullscreen(){!this.root?.requestFullscreen||this.isFullscreen()||(await this.root.requestFullscreen(),this.root.focus({preventScroll:!0}))}async exitFullscreen(){typeof document>"u"||!this.isFullscreen()||await document.exitFullscreen()}isFullscreen(){return typeof document<"u"&&document.fullscreenElement===this.root}toggleFullscreen(){(this.isFullscreen()?this.exitFullscreen():this.enterFullscreen()).catch(t=>this.opts.onError?.(t))}setToken(e,t){R(e),this.api.setToken(e),this.opts.token=e,this.opts.tokenExpiresAt=t,this.tokenExpiresAt=t??null,this.scheduleTokenRefresh(),this.ready&&this.resolveChannelCapabilities()}scheduleTokenRefresh(){this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.tokenRefreshTimer=null;let e=this.opts.onTokenRefresh,t=this.tokenExpiresAt;if(this.closed||!e||!t||!Number.isFinite(t))return;let s=t-Date.now(),i=Math.min(12e4,Math.max(3e4,s*.2)),o=Math.max(0,s-i);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},o)}async rotateToken(){if(!(this.closed||this.tokenRefreshInFlight||!this.opts.onTokenRefresh)){this.tokenRefreshInFlight=!0;try{let e=await this.opts.onTokenRefresh();if(!e?.token||!Number.isFinite(e.expiresAt))throw new Error("invalid_token_refresh_result");this.setToken(e.token,e.expiresAt)}catch(e){this.opts.onError?.(e),this.closed||(this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},3e4))}finally{this.tokenRefreshInFlight=!1}}}async block(e,t={}){let s=(e??this.selectionLabels()).filter(o=>this.status.get(o)==="free");if(!s.length)return;let i=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:i}),this.clearSelection(),this.done("block",s,i?`Blocked ${s.length} \u2014 auto-release ${new Date(i).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(o){this.setSeatsLocal(s,"free"),this.toastErr(o instanceof v&&o.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(o)}}async unblock(e){let t=(e??this.selectionLabels()).filter(s=>this.status.get(s)==="blocked");if(t.length){this.setSeatsLocal(t,"free");try{await this.api.unblock(this.key,t),this.clearSelection(),this.done("unblock",t,`Unblocked ${t.length} seat${t.length===1?"":"s"}.`)}catch(s){this.setSeatsLocal(t,"blocked"),this.toastErr("Couldn't unblock those seats."),this.opts.onError?.(s)}}}async unblockAll(){let e=[...this.status.entries()].filter(([,t])=>t==="blocked").map(([t])=>t);if(e.length){this.setSeatsLocal(e,"free");try{let t=await this.api.unblockAll(this.key);this.clearSelection(),this.done("unblockAll",e,`Unblocked ${t.freed} seat${t.freed===1?"":"s"}.`)}catch(t){await this.resnapshot(),this.toastErr("Couldn't mark everything for sale."),this.opts.onError?.(t)}}}async cancelBooking(e,t){let s=e.filter(i=>this.status.get(i)==="booked");if(!(!s.length||!t)){this.setSeatsLocal(s,"free");try{await this.api.unbook(this.key,s,t),this.clearSelection(),this.done("cancelBooking",s,`Released ${s.length} booked unit${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(i)}}}async setCategory(e,t){let s=this.doc?.categories.find(o=>o.key===e),i=[...new Set(t??this.selectionLabels())].filter(o=>this.labelToSeat.has(o));if(!(!s||!i.length))try{let o=await this.withAuthRetry(()=>this.api.setCategory(this.key,i,e)),a={};for(let l of o.labels){let r=this.labelToSeat.get(l),c=this.labelToId.get(l);r&&(r.categoryKey=e),c&&(a[c]=e)}this.renderer?.setSeatCategories?.(a),this.clearSelection(),this.done("setCategory",o.labels,`Assigned ${o.labels.length.toLocaleString()} object${o.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(o){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(o)}}async setTableBooking(e,t,s={}){let i=[...new Set(e)].filter(Boolean);if(!(!i.length||this.tableBookingSaving)){if(this.inventoryModelVersion!==2){this.toastErr("Table booking controls require inventory model 2 for this event.");return}this.tableBookingSaving=!0,this.mode==="tables"&&this.renderTablesRail();try{let o=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,i,t,s));await this.reloadEventChart(),this.done("setTableBooking",o.tableIds,`Updated ${o.tableIds.length.toLocaleString()} table${o.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(o){let a=o instanceof v&&o.code==="table_inventory_in_use";this.toastErr(a?"Release held, booked, or blocked table inventory before changing its booking mode.":"Couldn't update table booking. No table mode was changed."),this.opts.onError?.(o)}finally{this.tableBookingSaving=!1,this.mode==="tables"&&this.renderTablesRail()}}}async reloadEventChart(){let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1;let t=await this.organizerAssetUrls.prepareRendererChart(e.doc);this.renderer?.destroy(),this.renderer=null,this.doc=t,this.labelToId.clear(),this.labelToSeat.clear(),this.allIds=[],this.gaUnitLabelSet.clear(),this.status.clear(),this.counts={held:0,booked:0,blocked:0},this.serverBaseline=null,this.lastSelectionLabels.clear(),this.buildUnitUniverse(t),this.buildRenderer(),this.buildSectionOptions(),this.settleMode(),await Promise.all([this.resnapshot(),this.refreshAvailability()]),this.paintRail()}selectAll(){if(this.mode==="select")return this.selectByLabels([...this.labelToSeat.values()].filter(t=>this.canSelectObject(t)).map(t=>t.label));let e=this.renderer?.selectAllSelectable()??[];return this.syncSelection(),e}selectSection(e){if(!this.renderer)return[];let t=this.renderer.getSelectableInSection(e);return this.renderer.selectByLabels(t.map(s=>s.label)),this.syncSelection(),this.renderer.getSelection()}setFilteredSection(e){let t=e.trim(),s=this.filterableSections().filter(a=>a.label===t);if(!s.length)throw new Error(`Unknown event section: ${e}`);let i=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let o=s.map(({id:a,label:l,seatCount:r,zone:c})=>({id:a,label:l,seatCount:r,...c?{zone:c}:{}}));return i&&this.opts.onFilteredSectionChange?.(o),o}clearFilteredSection(){let e=this.filteredSectionLabel!==null;this.filteredSectionLabel=null,this.renderer?.setDimmedSections(null),this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit(),this.mode==="filterSections"&&this.renderFilterSectionsRail(),e&&this.opts.onFilteredSectionChange?.([])}getFilteredSections(){return this.filteredSectionLabel?this.filterableSections().filter(e=>e.label===this.filteredSectionLabel).map(({id:e,label:t,seatCount:s,zone:i})=>({id:e,label:t,seatCount:s,...i?{zone:i}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),i=this.selectionCap(),o=[...new Set(e)].filter(l=>!s.has(l)).map(l=>this.labelToSeat.get(l)).filter(l=>!!l&&this.canSelectObject(l)),a=Math.max(0,i-s.size);o.length>a&&this.opts.onSelectionLimit?.(i),t=o.slice(0,a).map(l=>l.label)}return this.renderer?.selectByLabels(t),this.syncSelection(),this.getSelection()}selectObjects(e){return this.selectByLabels(e)}deselectObjects(e){let t=e.map(s=>this.labelToId.get(s)).filter(s=>!!s);return this.renderer?.deselect(t),this.syncSelection(),this.getSelection()}selectCategories(e){let t=new Set(e);return this.selectByLabels([...this.labelToSeat.values()].filter(s=>t.has(s.categoryKey)).map(s=>s.label))}deselectCategories(e){let t=new Set(e);return this.deselectObjects(this.getSelection().filter(s=>t.has(s.categoryKey)).map(s=>s.label))}setSelectableObjects(e){this.opts.selectableObjects=[...e],this.selectableObjectLabels=new Set(e),this.reconcileSelectPolicy()}setUnavailableObjectsSelectable(e){this.opts.unavailableObjectsSelectable=e,this.reconcileSelectPolicy()}setObjectSelectable(e){this.opts.isObjectSelectable=e,this.reconcileSelectPolicy()}setMaxSelectedObjects(e){this.assertSelectionOptions(e,this.opts.numberOfPlacesToSelect),this.opts.maxSelectedObjects=e,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}setNumberOfPlacesToSelect(e){this.assertSelectionOptions(this.opts.maxSelectedObjects,e),this.opts.numberOfPlacesToSelect=e,this.selectionWasValid=null,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}getSelectionValidity(){let e=this.opts.numberOfPlacesToSelect;if(e===void 0)return null;let t=this.getSelection(),s=t.length;return{isValid:s===e,count:s,required:e,remaining:Math.max(0,e-s),objects:t}}clearSelection(){this.renderer?.clearSelection(),this.syncSelection()}getSelection(){return this.renderer?.getSelection()??[]}getReport(){return this.api.report(this.key).then(e=>(this.applyReportRevenue(e),e))}getControlRoomSnapshot(e=this.trendWindowMinutes){return this.setTrendWindow(e)}getConnection(){return{status:this.connectionStatus,lastMessageAt:this.lastMessageAt}}getLog(e={}){return this.api.log(this.key,e)}async setHoldTtl(e){try{await this.api.setHoldTtl(this.key,e),this.done("setHoldTtl",[],e?`Hold window set to ${Math.round(e/6e4)} min.`:"Hold window reset.")}catch(t){this.toastErr("Couldn't update the hold window."),this.opts.onError?.(t)}}zoomToFit(){if(this.mode==="filterSections"&&this.filteredSectionLabel){this.clearFilteredSection();return}this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit()}destroy(){if(this.closed=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.feedTimer&&clearInterval(this.feedTimer),this.toastTimer&&clearTimeout(this.toastTimer),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.paintHandle!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.paintHandle),this.paintHandle=null,this.channels?.destroy(),this.channels=null,this.channelsLoading=null,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.layoutObserver?.disconnect(),this.layoutObserver=null,this.colorSchemeStop?.(),this.colorSchemeStop=null,this.root?.removeEventListener("keydown",this.onKeyDown),this.els.rail?.removeEventListener("click",this.onRailClick),typeof document<"u"&&document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.ws){try{this.ws.close()}catch{}this.ws=null}this.renderer?.destroy(),this.renderer=null,this.organizerAssetUrls.dispose(),this.root&&this.root.parentNode===this.host&&this.host.removeChild(this.root)}buildRenderer(){if(!this.doc)return;let e=this.isBulkSelectMode();this.renderer=new Ce(this.mapHost,{manageMode:!0,marqueeSelect:e,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses(),currency:this.currency,onSelect:t=>this.handleSeatSelect(t),onDeselect:()=>this.syncSelection(),onSelectionLimit:t=>this.opts.onSelectionLimit?.(t),onMarquee:()=>this.syncSelection(),onSectionTap:t=>{if(this.mode==="filterSections"){let s=this.filterableSections().find(i=>i.id===t);s&&this.setFilteredSection(s.label);return}this.renderer?.focusSection(t),this.channels?.handleSectionFocus(t)},onViewChange:()=>{this.updateZoomHint(),this.channels?.handleViewChange()}}),this.renderer.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),this.updateZoomHint()}isBulkSelectMode(){return this.mode==="block"||this.mode==="categories"||this.mode==="channels"&&this.channels?.usesMarqueeSelection()===!0}selectableStatuses(){return this.mode==="block"?["free","not_for_sale"]:this.mode==="select"||this.mode==="categories"||this.mode==="inspect"||this.isBulkSelectMode()||this.mode==="channels"&&this.channels?.canSelect()===!0?["free","held","booked","not_for_sale"]:[]}updateRendererInteraction(){let e=this.isBulkSelectMode();this.renderer?.setManageInteraction({manageMode:!0,marqueeSelect:e,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses()}),this.updateZoomHint()}handleSeatSelect(e){if(this.mode==="select"&&!this.canSelectObject(e)){this.renderer?.deselect([e.id]),this.syncSelection();return}if(this.mode==="inspect"){let t=this.getSelection().filter(s=>s.id!==e.id).map(s=>s.id);t.length&&this.renderer?.deselect(t)}this.syncSelection()}buildUnitUniverse(e){for(let t of Re(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of $e(e))for(let s of He(t))this.labelToId.has(s)||this.gaUnitLabelSet.add(s)}unitTotal(){return this.allIds.length+this.gaUnitLabelSet.size}knownLabels(){return[...this.labelToId.keys(),...this.gaUnitLabelSet]}repaintAll(){let e=this.renderer;if(!e)return;this.allIds.length&&e.setStatus(this.allIds,"free");let t={free:[],held:[],booked:[],not_for_sale:[]};for(let[s,i]of this.status.entries()){let o=this.labelToId.get(s);o&&t[k(i)].push(o)}["held","booked","not_for_sale"].forEach(s=>{t[s].length&&e.setStatus(t[s],s)})}async connect(){if(this.closed)return;let e;try{if(e=(await this.withAuthRetry(()=>this.api.subscribeTicket(this.key))).protocols,!e.length)throw new Error("manage_subscribe_ticket_missing")}catch(s){this.setLive(!1),this.opts.onError?.(s),this.scheduleReconnect();return}if(this.closed)return;let t;try{t=new WebSocket(this.api.socketUrl(this.key),e)}catch(s){this.opts.onError?.(s),this.scheduleReconnect();return}this.ws=t,t.onopen=()=>{this.attempt=0,this.setLive(!0),this.resnapshot().then(()=>this.refreshControlRoom()).catch(s=>this.opts.onError?.(s)),this.refreshAvailability()},t.onmessage=s=>this.onMessage(s),t.onclose=()=>{this.ws===t&&(this.ws=null),this.setLive(!1),this.scheduleReconnect()},t.onerror=()=>{try{t.close()}catch{}}}scheduleReconnect(){if(this.closed||this.reconnectTimer)return;let e=Math.min(1e3*2**Math.min(this.attempt++,5),15e3);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},e)}onMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"")}catch{return}if(!t||typeof t!="object")return;this.lastMessageAt=Date.now();let s=t;if((Array.isArray(s.hidden)||Array.isArray(s.closed))&&this.updateEffectiveAvailability(s.hidden,s.closed),s.type==="presence"){typeof s.shoppingSessions=="number"&&typeof s.activeHolds=="number"&&(this.livePresence={at:Date.now(),value:{shoppingSessions:s.shoppingSessions,activeHolds:s.activeHolds}},this.controlRoomSnapshot&&(this.controlRoomSnapshot={...this.controlRoomSnapshot,presence:this.livePresence.value},this.opts.onControlRoom?.(this.controlRoomSnapshot)),this.lastSyncedAt=Date.now(),this.recomputeTallies(),this.paintMonitorInsights());return}if(s.type!=="hidden"){if(s.seats&&typeof s.seats=="object")this.applySnapshot(s.seats,typeof s.default=="string"?s.default:void 0);else if(Array.isArray(s.changes)){let i=[],o=new Map;for(let l of s.changes){let r=["free","held","booked","blocked"].includes(l.status)?l.status:"free",c=this.status.get(l.label)??"free";if(c===r)continue;this.setStatusLabel(l.label,r,c);let n=this.labelToId.get(l.label);n&&(this.renderer?.setStatus([n],k(r)),i.push(n));let h=this.verbFor(c,r),m=`${h}:${r}`,u=o.get(m)??{labels:[],verb:h,status:r};u.labels.push(l.label),o.set(m,u)}for(let l of o.values()){let r=this.pushActivity(l.labels,l.verb,l.status);r&&this.paintSpatialActivity(r)}i.length&&(this.lastSyncedAt=Date.now(),this.afterPaint());let a=typeof s.bookedValue?.gross=="number"?s.bookedValue.gross:s.revenue?.gross;typeof a=="number"&&Number.isFinite(a)&&this.applyLiveGross(a),this.recomputeTallies()}}}applyLiveGross(e){if(this.liveGross={at:Date.now(),value:e},this.authoritativeGrossRevenue=e,this.revenueStatus="current",this.controlRoomSnapshot){let s={...this.controlRoomSnapshot.bookedValue??this.controlRoomSnapshot.revenue,gross:e};this.controlRoomSnapshot={...this.controlRoomSnapshot,bookedValue:s,revenue:s},this.opts.onControlRoom?.(this.controlRoomSnapshot)}}setStatusLabel(e,t,s=this.status.get(e)??"free"){this.status.set(e,t),s!==t&&(s!=="free"&&(this.counts[s]-=1),t!=="free"&&(this.counts[t]+=1))}async resnapshot(){try{let e=await this.api.objects(this.key);this.applySnapshot(e.seats),this.updateEffectiveAvailability(e.hidden,e.closed),this.lastMessageAt=Date.now()}catch{}}applySnapshot(e,t){let s=o=>["free","held","booked","blocked"].includes(o)?o:"free",i=new Map;if(t!==void 0){let o=s(t);for(let a of this.knownLabels())i.set(a,o)}for(let[o,a]of Object.entries(e))i.set(o,s(a));this.status=i,this.modelVersion+=1,this.recountAll(),this.lastSyncedAt=Date.now(),this.repaintAll(),this.afterPaint(),this.recomputeTallies()}recountAll(){let e={held:0,booked:0,blocked:0};for(let t of this.status.values())t!=="free"&&(e[t]+=1);this.counts=e}setSeatsLocal(e,t){let s=[];for(let i of e){this.setStatusLabel(i,t);let o=this.labelToId.get(i);o&&s.push(o)}s.length&&this.renderer?.setStatus(s,k(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?"#f4b740":e==="booked"?"#22a06b":e==="blocked"?"#8b94ac":"#6e7bff"}sectionsForLabels(e){let t=new Set;for(let i of e){let o=this.labelToSeat.get(i);if(!o)continue;let a=this.sectionByObject.get(o.rowId);a&&a!==g&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(i=>this.sectionLabelById.get(i)??i)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let i of e.slice(0,Be)){let o=this.labelToId.get(i);o&&this.renderer?.flashSeat(o,s)}}paintSpatialActivity(e){let t=e.sectionIds??this.sectionsForLabels(e.labels).ids,s=this.renderer?.getFocusedSection()??null,i=this.followLive&&t.length===1&&(e.status==="held"||e.status==="booked");if(i&&s===t[0]){this.pulseSeatLabels(e.labels,e.status);return}if(i){this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=setTimeout(()=>{this.followLiveTimer=null,this.renderer?.focusSection(t[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(e.labels,e.status)},520)},220);return}if(!s&&t.length){let o=this.activityColor(e.status);for(let a of t.slice(0,U))this.renderer?.flashSection(a,o);return}(!t.length||s&&t.includes(s))&&this.pulseSeatLabels(e.labels,e.status)}locateSection(e){this.renderer?.focusSection(e)}locateActivity(e){let t=this.feed.find(i=>i.id===e);if(!t)return;let s=t.sectionIds??this.sectionsForLabels(t.labels).ids;if(this.followSeatTimer&&clearTimeout(this.followSeatTimer),s.length===1){this.locateSection(s[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(t.labels,t.status)},520);return}this.zoomToFit(),this.followSeatTimer=setTimeout(()=>{if(this.followSeatTimer=null,s.length){let i=this.activityColor(t.status);for(let o of s.slice(0,U))this.renderer?.flashSection(o,i)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],i=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,o=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
327
- <span class="slm-liveeventcopy">${p(i)} \xB7 ${e.count.toLocaleString()} ${o} ${p(e.verb)}</span>
328
- <span class="slm-liveeventhint">Live</span>`,t.classList.add("on"),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.liveEventTimer=setTimeout(()=>{this.liveEventTimer=null,t.classList.remove("on"),t.innerHTML=""},2800)}applyReportRevenue(e){this.authoritativeGrossRevenue=e.report.byCategory.reduce((t,s)=>{let i=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(i)?i:0)},0),this.revenueStatus="current",this.recomputeTallies()}async refreshControlRoom(){let e=++this.revenueRequest,t=Date.now();try{let s=await this.api.controlRoom(this.key,this.trendWindowMinutes),i=s.bookedValue??s.revenue??{gross:0,bySection:[]},o=(i.bySection??[]).map(r=>{let c=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:c??0,bookedRevenue:c??0}}),a={...i,bySection:o},l={...s,bookedValue:a,revenue:a};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?l={...l,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let r={...l.bookedValue,gross:this.liveGross.value};l={...l,bookedValue:r,revenue:r}}else this.liveGross=null;this.controlRoomSnapshot=l,this.rebaseServerTotals(l),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=l.bookedValue.gross,this.authoritativeCurrency=l.currency,this.currency=l.currency,this.revenueStatus="current",this.recomputeTallies(),this.applyHeatOverlay(),this.paintMonitorInsights(),this.opts.onControlRoom?.(l)}return l}catch(s){throw e===this.revenueRequest&&(this.revenueStatus="stale",this.recomputeTallies()),s}}rebaseServerTotals(e){let t=e.totals;if(!t||["free","held","booked","blocked"].some(s=>!Number.isFinite(t[s]))){this.serverBaseline=null;return}this.serverBaseline={model:this.modelVersion,server:{free:t.free,held:t.held,booked:t.booked,blocked:t.blocked},client:this.clientTallies()}}clientTallies(){let{held:e,booked:t,blocked:s}=this.counts;return{held:e,booked:t,blocked:s,free:Math.max(0,this.unitTotal()-e-t-s)}}buildTallies(){let e=this.clientTallies(),t=this.serverBaseline?.model===this.modelVersion?this.serverBaseline:null,s=l=>t?Math.max(0,t.server[l]+(e[l]-t.client[l])):e[l],i=this.controlRoomSnapshot?.event?.seatTotal,o={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(i)?i:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};o.capacityPct=o.total?Math.round(o.booked/o.total*100):0;let a=o.total-o.blocked;return o.sellThroughPct=a>0?Math.round(o.booked/a*100):0,o}recomputeTallies(){if(!this.closed){if(typeof requestAnimationFrame!="function"){this.flushTallies();return}this.paintHandle===null&&(this.paintHandle=requestAnimationFrame(()=>{this.paintHandle=null,this.flushTallies()}))}}flushTallies(){if(this.closed)return;let e=this.buildTallies();this.paintKpis(e),this.mode==="view"?(this.paintLegend(e),this.paintMonitorInsights()):this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="block"?this.paintSelBar(this.getSelection()):this.mode==="channels"&&this.channels?.handleSelectionChange(),this.opts.onTallies?.(e)}verbFor(e,t){return t==="held"?"held":t==="booked"?"booked":t==="blocked"?"blocked":t==="free"?e==="blocked"?"unblocked":e==="booked"?"cancelled":"released":t}pushActivity(e,t,s,i=Date.now()){let o=e[0];if(!o)return null;let a=this.sectionsForLabels(e),l={id:`${o}:${i}:${Math.random().toString(36).slice(2,6)}`,at:i,label:o,labels:[...e],count:e.length,verb:t,status:s,sectionIds:a.ids,sectionLabels:a.labels};return this.feed.unshift(l),this.feed.length>x&&(this.feed.length=x),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(l),this.opts.onActivity?.(l),l}seedFeed(e){let t={hold:"held",book:"booked",release:"released",expire:"expired",block:"blocked",unblock:"unblocked",unbook:"cancelled"},s={hold:"held",book:"booked",release:"free",expire:"free",block:"blocked",unblock:"free",unbook:"free"};for(let i of e){let o=i.labels[0];if(!o)continue;let a=this.sectionsForLabels(i.labels),l={id:`log:${i.id}`,at:i.at,label:o,labels:[...i.labels],count:i.labels.length,verb:t[i.action]??i.action,status:s[i.action]??"free",sectionIds:a.ids,sectionLabels:a.labels};this.feed.push(l),this.opts.onActivity?.(l)}this.feed.sort((i,o)=>o.at-i.at),this.feed.length>x&&(this.feed.length=x),this.mode==="view"&&this.paintFeed()}startFeedClock(){this.feedTimer=setInterval(()=>{this.mode==="view"&&(this.paintFeed(),this.paintMonitorInsights())},1e4)}selectionCap(){return this.mode!=="select"?1e6:this.opts.numberOfPlacesToSelect??this.opts.maxSelectedObjects??1e6}canSelectObject(e){let t=this.status.get(e.label)??"free",s=this.opts.unavailableObjectsSelectable??!0,i=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return i;try{return this.opts.isObjectSelectable(e,i)===!0}catch(o){return this.opts.onError?.(o),!1}}applyInitialSelection(){this.initialSelectionApplied||this.mode!=="select"||!this.renderer||(this.initialSelectionApplied=!0,this.selectByLabels(this.opts.selectedObjects??[]))}trimSelectionToCap(){if(this.mode!=="select")return;let e=this.getSelection(),t=this.selectionCap();e.length<=t||this.renderer?.deselect(e.slice(t).map(s=>s.id))}reconcileSelectPolicy(){if(this.mode!=="select")return;let e=this.getSelection().filter(t=>!this.canSelectObject(t));e.length&&this.renderer?.deselect(e.map(t=>t.id)),this.trimSelectionToCap(),this.syncSelection()}selectionLabels(){return this.getSelection().map(e=>e.label)}syncSelection(){let e=this.getSelection();this.mode==="block"?this.paintSelBar(e):this.mode==="inspect"?this.renderInspectRail(e):this.mode==="select"?this.paintSelectSelection(e):this.mode==="categories"?this.paintCategorySelection(e):this.mode==="channels"&&this.channels?.handleSelectionChange();let t=new Map(e.map(s=>[s.label,s]));if(this.mode==="select"){for(let[i,o]of t)this.lastSelectionLabels.has(i)||this.opts.onObjectSelected?.(o);for(let i of this.lastSelectionLabels)if(!t.has(i)){let o=this.labelToSeat.get(i);o&&this.opts.onObjectDeselected?.(o)}let s=this.getSelectionValidity();s&&(this.opts.onSelectionValidityChange?.(s),this.selectionWasValid!==s.isValid&&(s.isValid?this.opts.onSelectionValid?.(s):this.opts.onSelectionInvalid?.(s)),this.selectionWasValid=s.isValid)}this.lastSelectionLabels=new Set(t.keys()),this.opts.onSelectionChange?.(e)}buildChrome(){let e=document.createElement("div");e.className="slm",e.tabIndex=0,e.setAttribute("role","region"),e.setAttribute("aria-label","SeatLayer live control room"),e.innerHTML=`
450
+ </div>`}var Ne="https://api.seatlayer.io",R=200,ee=16,te=4,se=[{key:"watch",label:"Watch",tools:[{mode:"view",label:"Monitor",shortcut:"M",title:"Live board \u2014 inventory, activity and booking momentum. Read-only."},{mode:"inspect",label:"Inspect",shortcut:"I",title:"Click one seat to read its live status and booking context. Read-only."}]},{key:"manage",label:"Manage",tools:[{mode:"block",label:"Block",shortcut:"B",title:"Take seats off sale for this event, or put them back."},{mode:"sections",label:"Sections",shortcut:"S",title:"Open, close or hide sections for this event, on a schedule or on demand."},{mode:"categories",label:"Categories",shortcut:"G",title:"Move seats to a different price category for this event only."},{mode:"tables",label:"Tables",shortcut:"T",title:"Sell each table per chair or as one whole-table booking."},{mode:"channels",label:"Channels",shortcut:"C",title:"Allocate inventory to sales channels and share their links."}]},{key:"host",label:"Host tools",tools:[{mode:"select",label:"Select",shortcut:"X",title:"Select seats for your own back-office operation. The selection is handed to your app; nothing changes here."},{mode:"filterSections",label:"Filter",shortcut:"L",title:"Filter the map to one section for your own reporting."}]}],qe=Object.fromEntries(se.flatMap(h=>h.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),z=class{constructor(e){this.els={};this.renderer=null;this.doc=null;this.selectObserver=null;this.seatHistoryPanel=null;this.activityPanel=null;this.navigation=null;this.movingMap=!1;this.socketSnapshotSeen=!1;this.monitorRefreshTimer=null;this.themeMode=null;this.colorSchemeStop=null;this.inventoryModelVersion=1;this.selectableObjectLabels=new Set;this.lastSelectionLabels=new Set;this.selectionWasValid=null;this.initialSelectionApplied=!1;this.labelToId=new Map;this.labelToSeat=new Map;this.allIds=[];this.gaUnitLabelSet=new Set;this.status=new Map;this.counts={held:0,booked:0,blocked:0};this.modelVersion=0;this.currency="USD";this.authoritativeCurrency=null;this.authoritativeGrossRevenue=0;this.revenueStatus="loading";this.revenueRequest=0;this.controlRoomSnapshot=null;this.serverBaseline=null;this.livePresence=null;this.liveGross=null;this.paintHandle=null;this.trendWindowMinutes=15;this.heatEnabled=!1;this.lastKpiValues=new Map;this.activeKpiDeltas=new Map;this.ws=null;this.reconnectTimer=null;this.attempt=0;this.closed=!1;this.connectionStatus="reconnecting";this.lastMessageAt=null;this.ready=!1;this.feed=[];this.feedTimer=null;this.toastTimer=null;this.liveEventTimer=null;this.kpiCleanupTimer=null;this.followLiveTimer=null;this.followSeatTimer=null;this.releaseAt=null;this.layoutObserver=null;this.tokenExpiresAt=null;this.tokenRefreshTimer=null;this.tokenRefreshInFlight=!1;this.sectionByObject=new Map;this.sectionLabelById=new Map;this.sectionsBase=null;this.filteredSectionLabel=null;this.availabilityRules={};this.effectiveHidden=new Set;this.effectiveClosed=new Set;this.availabilitySaving=!1;this.lastSyncedAt=null;this.blockBrowse=!1;this.blockedQuery="";this.blockedSection="";this.blockedResultLimit=100;this.unblockAllConfirmTimer=null;this.channels=null;this.channelCaps={view:!1,manage:!1};this.categoryCanManage=!1;this.tableCanManage=!1;this.tableBookingSaving=!1;this.channelCapabilityResolution=0;this.channelsLoading=null;this.onFullscreenChange=()=>{this.paintFullscreenButton(),this.updateContainerLayout(),this.renderer?.forceDraw()};this.onKeyDown=e=>{if(e.metaKey||e.ctrlKey||e.altKey||e.target?.matches('input,select,textarea,[contenteditable="true"]'))return;let s=e.key.toLowerCase(),i=qe[s];if(i){if(!this.toolAvailable(i))return;this.setMode(i)}else if(s==="f")this.toggleFullscreen();else if(s==="escape"){if(!this.channels?.handleBack())return}else return;e.preventDefault()};this.onRailClick=e=>{let t=e.target,s=t?.closest("[data-section-focus]");if(s?.dataset.sectionFocus){this.locateSection(s.dataset.sectionFocus);return}let i=t?.closest("[data-feed-id]");i?.dataset.feedId&&this.locateActivity(i.dataset.feedId)};this.sectionOptions=[];B(e.token),this.assertSelectionOptions(e.maxSelectedObjects,e.numberOfPlacesToSelect),this.opts=e,this.key=e.eventKey,this.mode=e.mode??"view",this.selectableObjectLabels=new Set(e.selectableObjects??[]),this.categoryCanManage=new Set(e.capabilities??[]).has("event:categories:manage"),this.tableCanManage=new Set(e.capabilities??[]).has("event:tables:manage"),this.keepLive=e.keepLiveWhileHidden??!0,this.themeMode=e.themeMode??null,this.followLive=e.followLive??!1,this.currency=e.currency??"USD",this.tokenExpiresAt=e.tokenExpiresAt??null,this.api=new H(e.apiBase??Ne,e.token),this.organizerAssetUrls=new T(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=W(e.container)}assertSelectionOptions(e,t){let s=i=>i===void 0||Number.isInteger(i)&&i>0;if(!s(e))throw new TypeError("maxSelectedObjects must be a positive integer");if(!s(t))throw new TypeError("numberOfPlacesToSelect must be a positive integer");if(e!==void 0&&t!==void 0&&e<t)throw new TypeError("maxSelectedObjects cannot be lower than numberOfPlacesToSelect")}async render(){q(),this.buildChrome();try{let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1,this.doc=await this.organizerAssetUrls.prepareRendererChart(e.doc),this.authoritativeCurrency=e.event.currency??null,this.currency=this.authoritativeCurrency??this.opts.currency??this.currency,this.buildUnitUniverse(this.doc),this.buildRenderer(),this.buildSectionOptions(),this.settleMode();let[,t]=await Promise.all([this.resnapshot(),this.refreshControlRoom().catch(s=>this.opts.onError?.(s)),this.refreshAvailability()]);t?.activity?this.seedFeed(t.activity):this.api.log(this.key,{limit:24}).then(s=>this.seedFeed(s.entries)).catch(()=>{}),this.connect(),this.startFeedClock(),this.ready=!0,await this.resolveChannelCapabilities(),this.setMode(this.mode),this.applyInitialSelection(),this.scheduleTokenRefresh(),this.opts.onReady?.()}catch(e){this.fail(e)}return this}setMode(e){this.toolAvailable(e)||(e="view"),e==="channels"&&!this.channels&&this.ensureChannels();let t=e!==this.mode,s=this.mode==="channels",i=this.mode==="filterSections";this.mode=e,t&&e!=="view"&&this.setFollowLive(!1),!this.renderer&&this.doc?this.buildRenderer():this.updateRendererInteraction(),t&&(this.renderer?.clearSelection(),this.syncSelection()),s&&e!=="channels"&&this.channels?.leave(),this.paintModeTabs(),this.paintRail(),this.applySectionCanvasTreatment(),i&&e!=="filterSections"&&this.renderer?.zoomToFit(),e==="channels"&&this.channels?.enter(),e==="select"&&this.applyInitialSelection(),t&&this.opts.onModeChange?.(e)}async resolveChannelCapabilities(){let e=++this.channelCapabilityResolution,t=this.opts.capabilities,s;if(t){let i=new Set(t);s={view:i.has("event:channels:view"),manage:i.has("event:channels:view")&&i.has("event:channels:manage")}}else s={view:!1,manage:!1};if(!s.view&&!t)try{await this.api.channels(this.key),s={view:!0,manage:!1}}catch{s={view:!1,manage:!1}}if(e===this.channelCapabilityResolution){if(this.channelCaps=s,!this.channelCaps.view){this.channels?.destroy(),this.channels=null,this.mode==="channels"?this.setMode("view"):this.paintModeTabs();return}this.channels?.setCapabilities(this.channelCaps),this.paintModeTabs()}}ensureChannels(){if(this.channelsLoading)return this.channelsLoading;if(this.channels)return Promise.resolve();let e=(async()=>{try{let t=await import("./channelsMode-JQPW2SVE.js");if(this.closed||!this.channelCaps.view||(this.channels||(V(t.CHANNELS_CSS),this.channels=new t.ChannelsMode(this.buildChannelsHost(),this.channelCaps),this.channels.onInteractionChange=()=>this.updateRendererInteraction()),this.mode!=="channels"))return;this.updateRendererInteraction(),this.paintRail(),this.channels.enter()}catch(t){if(this.closed)return;this.channelsLoading=null,this.mode==="channels"&&this.paintRail(),this.opts.onError?.(t)}})();return this.channelsLoading=e,e}buildChannelsHost(){return{eventKey:this.key,api:this.api,rail:this.els.rail,mapLayer:this.root.querySelector(".slm-map"),root:this.root,seats:()=>[...this.labelToSeat.values()].map(e=>({id:e.id,label:e.label,x:e.x,y:e.y})),statusOf:e=>this.status.get(e)??(this.labelToSeat.has(e)?"free":void 0),selectionLabels:()=>this.selectionLabels(),selectByLabels:e=>{this.selectByLabels(e)},clearSelection:()=>this.clearSelection(),selectSection:e=>{this.selectSection(e)},sections:()=>this.sectionOptions,labelsInSection:e=>this.renderer?.getSelectableInSection(e).map(t=>t.label)??[],rows:()=>{let e=new Map((this.doc?.objects??[]).map(s=>[s.id,s])),t=new Map;for(let s of this.labelToSeat.values()){let i=e.get(s.rowId);if(!i||i.type!=="row"&&i.type!=="table")continue;let a=s.logicalRowId??s.rowId,o=this.sectionByObject.get(s.rowId)??y,l=t.get(a)??{id:a,label:i.type==="row"?i.segmentedRow?.displayLabel??i.displayLabel??i.label:i.displayLabel??i.label,sectionId:o,sectionLabel:this.sectionLabelById.get(o)??"Other seats",labels:[]};l.labels.push(s.label),t.set(a,l)}return[...t.values()].sort((s,i)=>s.sectionLabel.localeCompare(i.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))},categories:()=>(this.doc?.categories??[]).map(e=>({key:e.key,label:e.label??e.key,color:e.color,price:e.price,tiers:e.tiers?.map(t=>({id:t.id,name:t.name,price:t.price}))})),labelsInCategory:e=>[...this.labelToSeat.entries()].filter(([,t])=>t.categoryKey===e).map(([t])=>t),sectionOfLabel:e=>{let t=this.labelToSeat.get(e);if(!t)return null;let s=this.sectionByObject.get(t.rowId)??y;return{id:s,label:this.sectionLabelById.get(s)??"Other seats"}},worldToScreen:e=>this.renderer?.worldToScreen(e)??null,seatPixelSize:()=>this.seatPixelSize(),isSeatDetail:()=>this.renderer?.getRung?.()==="seats",showSectionOverview:()=>{this.renderer?.clearSectionFocus(),this.renderer?.setRung?.("sections")},focusSection:e=>this.renderer?.focusSection(e),isCompact:()=>!!this.root?.classList.contains("compact"),setMapInert:e=>{this.mapHost.toggleAttribute("inert",e),this.mapHost.setAttribute("aria-hidden",String(e))},toast:(e,t)=>this.toast(e,t),onError:e=>this.opts.onError?.(e)}}seatPixelSize(){let e=this.renderer?.getVisibleWorldRect?.(),t=this.mapHost?.clientWidth??0;return!e?.width||!t?6:Math.max(3,t/e.width*18)}setHeatOverlay(e){this.heatEnabled=e,this.applyHeatOverlay(),this.paintHeatButton()}setFollowLive(e){let t=this.followLive!==e;this.followLive=e,e||(this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=null,this.followSeatTimer=null),this.paintFollowLiveButton(),t&&this.opts.onFollowLiveChange?.(e)}setKeepLiveWhileHidden(e){this.keepLive=e??!0,this.opts.keepLiveWhileHidden=e}setCurrency(e){this.opts.currency=e,!this.authoritativeCurrency&&(this.currency=e??"USD",this.ready&&this.recomputeTallies())}setTheme(e){this.opts.theme=e,this.applyThemeVars()}applyThemeVars(){if(!this.root)return;let e=$(this.themeMode);for(let[t,s]of Object.entries(Z(this.opts.theme,e)))this.root.style.setProperty(t,s);e?this.root.dataset.theme=e:delete this.root.dataset.theme}watchThemeMode(){this.colorSchemeStop?.(),this.colorSchemeStop=null,this.themeMode==="auto"&&(this.colorSchemeStop=O(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(a=>a.id),s=e.getCameraPose(),i=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),i&&e.focusSection(i),e.setCameraPose(s),this.updateZoomHint()}setThemeMode(e){let t=e??null;this.closed||t===this.themeMode||(this.themeMode=t,this.opts.themeMode=t??void 0,this.watchThemeMode(),this.repaintForThemeMode())}getThemeMode(){return this.themeMode}themedDoc(){let e=this.doc,t=Y($(this.themeMode));return t?{...e,theme:{...e.theme??{},background:t}}:e}setCapabilities(e){this.opts.capabilities=e,this.categoryCanManage=new Set(e??[]).has("event:categories:manage"),this.tableCanManage=new Set(e??[]).has("event:tables:manage"),!this.categoryCanManage&&this.mode==="categories"||!this.tableCanManage&&this.mode==="tables"?this.setMode("view"):this.paintModeTabs(),this.ready&&this.resolveChannelCapabilities()}setTokenRefresh(e){this.opts.onTokenRefresh=e,this.scheduleTokenRefresh()}setTrendWindow(e){let t=Number.isFinite(e)?Math.floor(e):15;return this.trendWindowMinutes=Math.max(5,Math.min(60,t)),this.paintTrendWindow(),this.refreshControlRoom()}async enterFullscreen(){!this.root?.requestFullscreen||this.isFullscreen()||(await this.root.requestFullscreen(),this.root.focus({preventScroll:!0}))}async exitFullscreen(){typeof document>"u"||!this.isFullscreen()||await document.exitFullscreen()}isFullscreen(){return typeof document<"u"&&document.fullscreenElement===this.root}toggleFullscreen(){(this.isFullscreen()?this.exitFullscreen():this.enterFullscreen()).catch(t=>this.opts.onError?.(t))}setToken(e,t){B(e),this.api.setToken(e),this.opts.token=e,this.opts.tokenExpiresAt=t,this.tokenExpiresAt=t??null,this.scheduleTokenRefresh(),this.ready&&this.resolveChannelCapabilities()}scheduleTokenRefresh(){this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.tokenRefreshTimer=null;let e=this.opts.onTokenRefresh,t=this.tokenExpiresAt;if(this.closed||!e||!t||!Number.isFinite(t))return;let s=t-Date.now(),i=Math.min(12e4,Math.max(3e4,s*.2)),a=Math.max(0,s-i);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},a)}async rotateToken(){if(!(this.closed||this.tokenRefreshInFlight||!this.opts.onTokenRefresh)){this.tokenRefreshInFlight=!0;try{let e=await this.opts.onTokenRefresh();if(!e?.token||!Number.isFinite(e.expiresAt))throw new Error("invalid_token_refresh_result");this.setToken(e.token,e.expiresAt)}catch(e){this.opts.onError?.(e),this.closed||(this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},3e4))}finally{this.tokenRefreshInFlight=!1}}}async block(e,t={}){let s=(e??this.selectionLabels()).filter(a=>this.status.get(a)==="free");if(!s.length)return;let i=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:i}),this.clearSelection(),this.done("block",s,i?`Blocked ${s.length} \u2014 auto-release ${new Date(i).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(a){this.setSeatsLocal(s,"free"),this.toastErr(a instanceof k&&a.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(a)}}async unblock(e){let t=(e??this.selectionLabels()).filter(s=>this.status.get(s)==="blocked");if(t.length){this.setSeatsLocal(t,"free");try{await this.api.unblock(this.key,t),this.clearSelection(),this.done("unblock",t,`Unblocked ${t.length} seat${t.length===1?"":"s"}.`)}catch(s){this.setSeatsLocal(t,"blocked"),this.toastErr("Couldn't unblock those seats."),this.opts.onError?.(s)}}}async unblockAll(){let e=[...this.status.entries()].filter(([,t])=>t==="blocked").map(([t])=>t);if(e.length){this.setSeatsLocal(e,"free");try{let t=await this.api.unblockAll(this.key);this.clearSelection(),this.done("unblockAll",e,`Unblocked ${t.freed} seat${t.freed===1?"":"s"}.`)}catch(t){await this.resnapshot(),this.toastErr("Couldn't mark everything for sale."),this.opts.onError?.(t)}}}async cancelBooking(e,t){let s=e.filter(i=>this.status.get(i)==="booked");if(!(!s.length||!t)){this.setSeatsLocal(s,"free");try{await this.api.unbook(this.key,s,t),this.clearSelection(),this.done("cancelBooking",s,`Released ${s.length} booked unit${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(i)}}}async setCategory(e,t){let s=this.doc?.categories.find(a=>a.key===e),i=[...new Set(t??this.selectionLabels())].filter(a=>this.labelToSeat.has(a));if(!(!s||!i.length))try{let a=await this.withAuthRetry(()=>this.api.setCategory(this.key,i,e)),o={};for(let l of a.labels){let r=this.labelToSeat.get(l),c=this.labelToId.get(l);r&&(r.categoryKey=e),c&&(o[c]=e)}this.renderer?.setSeatCategories?.(o),this.clearSelection(),this.done("setCategory",a.labels,`Assigned ${a.labels.length.toLocaleString()} object${a.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(a){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(a)}}async setTableBooking(e,t,s={}){let i=[...new Set(e)].filter(Boolean);if(!(!i.length||this.tableBookingSaving)){if(this.inventoryModelVersion!==2){this.toastErr("Table booking controls require inventory model 2 for this event.");return}this.tableBookingSaving=!0,this.mode==="tables"&&this.renderTablesRail();try{let a=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,i,t,s));await this.reloadEventChart(),this.done("setTableBooking",a.tableIds,`Updated ${a.tableIds.length.toLocaleString()} table${a.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(a){let o=a instanceof k&&a.code==="table_inventory_in_use";this.toastErr(o?"Release held, booked, or blocked table inventory before changing its booking mode.":"Couldn't update table booking. No table mode was changed."),this.opts.onError?.(a)}finally{this.tableBookingSaving=!1,this.mode==="tables"&&this.renderTablesRail()}}}async reloadEventChart(){let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1;let t=await this.organizerAssetUrls.prepareRendererChart(e.doc);this.renderer?.destroy(),this.renderer=null,this.doc=t,this.labelToId.clear(),this.labelToSeat.clear(),this.allIds=[],this.gaUnitLabelSet.clear(),this.status.clear(),this.counts={held:0,booked:0,blocked:0},this.serverBaseline=null,this.lastSelectionLabels.clear(),this.buildUnitUniverse(t),this.buildRenderer(),this.buildSectionOptions(),this.settleMode(),await Promise.all([this.resnapshot(),this.refreshAvailability()]),this.paintRail()}selectAll(){if(this.mode==="select")return this.selectByLabels([...this.labelToSeat.values()].filter(t=>this.canSelectObject(t)).map(t=>t.label));let e=this.renderer?.selectAllSelectable()??[];return this.syncSelection(),e}selectSection(e){if(!this.renderer)return[];let t=this.renderer.getSelectableInSection(e);return this.renderer.selectByLabels(t.map(s=>s.label)),this.syncSelection(),this.renderer.getSelection()}setFilteredSection(e){let t=e.trim(),s=this.filterableSections().filter(o=>o.label===t);if(!s.length)throw new Error(`Unknown event section: ${e}`);let i=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let a=s.map(({id:o,label:l,seatCount:r,zone:c})=>({id:o,label:l,seatCount:r,...c?{zone:c}:{}}));return i&&this.opts.onFilteredSectionChange?.(a),a}clearFilteredSection(){let e=this.filteredSectionLabel!==null;this.filteredSectionLabel=null,this.renderer?.setDimmedSections(null),this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit(),this.mode==="filterSections"&&this.renderFilterSectionsRail(),e&&this.opts.onFilteredSectionChange?.([])}getFilteredSections(){return this.filteredSectionLabel?this.filterableSections().filter(e=>e.label===this.filteredSectionLabel).map(({id:e,label:t,seatCount:s,zone:i})=>({id:e,label:t,seatCount:s,...i?{zone:i}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),i=this.selectionCap(),a=[...new Set(e)].filter(l=>!s.has(l)).map(l=>this.labelToSeat.get(l)).filter(l=>!!l&&this.canSelectObject(l)),o=Math.max(0,i-s.size);a.length>o&&this.opts.onSelectionLimit?.(i),t=a.slice(0,o).map(l=>l.label)}return this.renderer?.selectByLabels(t),this.syncSelection(),this.getSelection()}selectObjects(e){return this.selectByLabels(e)}deselectObjects(e){let t=e.map(s=>this.labelToId.get(s)).filter(s=>!!s);return this.renderer?.deselect(t),this.syncSelection(),this.getSelection()}selectCategories(e){let t=new Set(e);return this.selectByLabels([...this.labelToSeat.values()].filter(s=>t.has(s.categoryKey)).map(s=>s.label))}deselectCategories(e){let t=new Set(e);return this.deselectObjects(this.getSelection().filter(s=>t.has(s.categoryKey)).map(s=>s.label))}setSelectableObjects(e){this.opts.selectableObjects=[...e],this.selectableObjectLabels=new Set(e),this.reconcileSelectPolicy()}setUnavailableObjectsSelectable(e){this.opts.unavailableObjectsSelectable=e,this.reconcileSelectPolicy()}setObjectSelectable(e){this.opts.isObjectSelectable=e,this.reconcileSelectPolicy()}setMaxSelectedObjects(e){this.assertSelectionOptions(e,this.opts.numberOfPlacesToSelect),this.opts.maxSelectedObjects=e,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}setNumberOfPlacesToSelect(e){this.assertSelectionOptions(this.opts.maxSelectedObjects,e),this.opts.numberOfPlacesToSelect=e,this.selectionWasValid=null,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}getSelectionValidity(){let e=this.opts.numberOfPlacesToSelect;if(e===void 0)return null;let t=this.getSelection(),s=t.length;return{isValid:s===e,count:s,required:e,remaining:Math.max(0,e-s),objects:t}}clearSelection(){this.renderer?.clearSelection(),this.syncSelection()}getSelection(){return this.renderer?.getSelection()??[]}getReport(){return this.api.report(this.key).then(e=>(this.applyReportRevenue(e),e))}getControlRoomSnapshot(e=this.trendWindowMinutes){return this.setTrendWindow(e)}getConnection(){return{status:this.connectionStatus,lastMessageAt:this.lastMessageAt}}getLog(e={}){return this.api.log(this.key,e)}async setHoldTtl(e){try{await this.api.setHoldTtl(this.key,e),this.done("setHoldTtl",[],e?`Hold window set to ${Math.round(e/6e4)} min.`:"Hold window reset.")}catch(t){this.toastErr("Couldn't update the hold window."),this.opts.onError?.(t)}}zoomToFit(){if(this.mode==="filterSections"&&this.filteredSectionLabel){this.clearFilteredSection();return}this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit()}destroy(){if(this.selectObserver?.disconnect(),this.closed=!0,this.monitorRefreshTimer&&clearTimeout(this.monitorRefreshTimer),this.monitorRefreshTimer=null,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.feedTimer&&clearInterval(this.feedTimer),this.toastTimer&&clearTimeout(this.toastTimer),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.paintHandle!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.paintHandle),this.paintHandle=null,this.channels?.destroy(),this.channels=null,this.channelsLoading=null,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.layoutObserver?.disconnect(),this.layoutObserver=null,this.colorSchemeStop?.(),this.colorSchemeStop=null,this.root?.removeEventListener("keydown",this.onKeyDown),this.els.rail?.removeEventListener("click",this.onRailClick),typeof document<"u"&&document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.ws){try{this.ws.close()}catch{}this.ws=null}this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.navigation?.destroy(),this.navigation=null,this.renderer?.destroy(),this.renderer=null,this.organizerAssetUrls.dispose(),this.root&&this.root.parentNode===this.host&&this.host.removeChild(this.root)}buildRenderer(){if(!this.doc)return;let e=this.isBulkSelectMode();this.renderer=new Oe(this.mapHost,{manageMode:!0,marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses(),currency:this.currency,onSelect:t=>this.handleSeatSelect(t),onDeselect:()=>this.syncSelection(),onSelectionLimit:t=>this.opts.onSelectionLimit?.(t),onMarquee:()=>this.syncSelection(),onSectionTap:t=>{if(this.mode==="filterSections"){let s=this.filterableSections().find(i=>i.id===t);s&&this.setFilteredSection(s.label);return}this.renderer?.focusSection(t),this.channels?.handleSectionFocus(t)},onViewChange:()=>{this.updateZoomHint(),this.channels?.handleViewChange()}}),this.renderer.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),this.updateZoomHint()}isBulkSelectMode(){return this.mode==="block"||this.mode==="categories"||this.mode==="channels"&&this.channels?.usesMarqueeSelection()===!0}selectableStatuses(){return this.mode==="block"?["free","not_for_sale"]:this.mode==="select"||this.mode==="categories"||this.mode==="inspect"||this.isBulkSelectMode()||this.mode==="channels"&&this.channels?.canSelect()===!0?["free","held","booked","not_for_sale"]:[]}updateRendererInteraction(){let e=this.isBulkSelectMode();this.renderer?.setManageInteraction({manageMode:!0,organizerStatus:this.mode!=="channels",marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses()}),this.navigation?.update(e,this.mode==="view"),this.updateZoomHint()}handleSeatSelect(e){if(this.mode==="select"&&!this.canSelectObject(e)){this.renderer?.deselect([e.id]),this.syncSelection();return}if(this.mode==="inspect"){let t=this.getSelection().filter(s=>s.id!==e.id).map(s=>s.id);t.length&&this.renderer?.deselect(t)}this.syncSelection()}buildUnitUniverse(e){for(let t of Fe(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of Pe(e))for(let s of De(t))this.labelToId.has(s)||this.gaUnitLabelSet.add(s)}unitTotal(){return this.allIds.length+this.gaUnitLabelSet.size}knownLabels(){return[...this.labelToId.keys(),...this.gaUnitLabelSet]}repaintAll(){let e=this.renderer;if(!e)return;this.allIds.length&&e.setStatus(this.allIds,"free");let t={free:[],held:[],booked:[],not_for_sale:[]};for(let[s,i]of this.status.entries()){let a=this.labelToId.get(s);a&&t[M(i)].push(a)}["held","booked","not_for_sale"].forEach(s=>{t[s].length&&e.setStatus(t[s],s)})}async connect(){if(this.closed)return;let e;try{if(e=(await this.withAuthRetry(()=>this.api.subscribeTicket(this.key))).protocols,!e.length)throw new Error("manage_subscribe_ticket_missing")}catch(s){this.setLive(!1),this.opts.onError?.(s),this.scheduleReconnect();return}if(this.closed)return;let t;try{t=new WebSocket(this.api.socketUrl(this.key),e)}catch(s){this.opts.onError?.(s),this.scheduleReconnect();return}this.ws=t,this.socketSnapshotSeen=!1,t.onopen=()=>{this.attempt=0,this.setLive(!0),this.resnapshot().then(()=>this.refreshControlRoom()).catch(s=>this.opts.onError?.(s)),this.refreshAvailability()},t.onmessage=s=>this.onMessage(s),t.onclose=()=>{this.ws===t&&(this.ws=null),this.setLive(!1),this.scheduleReconnect()},t.onerror=()=>{try{t.close()}catch{}}}scheduleReconnect(){if(this.closed||this.reconnectTimer)return;let e=Math.min(1e3*2**Math.min(this.attempt++,5),15e3);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},e)}onMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"")}catch{return}if(!t||typeof t!="object")return;this.lastMessageAt=Date.now();let s=t;if((Array.isArray(s.hidden)||Array.isArray(s.closed))&&this.updateEffectiveAvailability(s.hidden,s.closed),s.type==="presence"){typeof s.shoppingSessions=="number"&&typeof s.activeHolds=="number"&&(this.livePresence={at:Date.now(),value:{shoppingSessions:s.shoppingSessions,activeHolds:s.activeHolds}},this.controlRoomSnapshot&&(this.controlRoomSnapshot={...this.controlRoomSnapshot,presence:this.livePresence.value},this.opts.onControlRoom?.(this.controlRoomSnapshot)),this.lastSyncedAt=Date.now(),this.recomputeTallies(),this.paintMonitorInsights());return}if(s.type!=="hidden"){if(s.seats&&typeof s.seats=="object")this.applySocketSnapshot(s.seats,typeof s.default=="string"?s.default:void 0);else if(Array.isArray(s.changes)){let i=[],a=new Map;for(let l of s.changes){let r=["free","held","booked","blocked"].includes(l.status)?l.status:"free",c=this.status.get(l.label)??"free";if(c===r)continue;this.setStatusLabel(l.label,r,c);let n=this.labelToId.get(l.label);n&&(this.renderer?.setStatus([n],M(r)),i.push(n));let d=this.verbFor(c,r),m=`${d}:${r}`,b=a.get(m)??{labels:[],verb:d,status:r};b.labels.push(l.label),a.set(m,b)}for(let l of a.values()){let r=this.pushActivity(l.labels,l.verb,l.status);r&&this.paintSpatialActivity(r)}a.size&&this.scheduleMonitorRefresh(),i.length&&(this.lastSyncedAt=Date.now(),this.afterPaint());let o=typeof s.bookedValue?.gross=="number"?s.bookedValue.gross:s.revenue?.gross;typeof o=="number"&&Number.isFinite(o)&&this.applyLiveGross(o),this.recomputeTallies()}}}applyLiveGross(e){if(this.liveGross={at:Date.now(),value:e},this.authoritativeGrossRevenue=e,this.revenueStatus="current",this.controlRoomSnapshot){let s={...this.controlRoomSnapshot.bookedValue??this.controlRoomSnapshot.revenue,gross:e};this.controlRoomSnapshot={...this.controlRoomSnapshot,bookedValue:s,revenue:s},this.opts.onControlRoom?.(this.controlRoomSnapshot)}}setStatusLabel(e,t,s=this.status.get(e)??"free"){this.status.set(e,t),s!==t&&(s!=="free"&&(this.counts[s]-=1),t!=="free"&&(this.counts[t]+=1))}applySocketSnapshot(e,t){let s=this.socketSnapshotSeen?this.status:null;if(this.applySnapshot(e,t),this.socketSnapshotSeen=!0,!s)return;let i=new Map;for(let a of new Set([...s.keys(),...this.status.keys()])){let o=s.get(a)??"free",l=this.status.get(a)??"free";if(o===l)continue;let r=this.verbFor(o,l),c=`${r}:${l}`,n=i.get(c)??{labels:[],verb:r,status:l};n.labels.push(a),i.set(c,n)}for(let a of i.values()){let o=this.pushActivity(a.labels,a.verb,a.status);o&&this.paintSpatialActivity(o)}i.size&&this.scheduleMonitorRefresh()}scheduleMonitorRefresh(){this.monitorRefreshTimer||(this.monitorRefreshTimer=setTimeout(()=>{this.monitorRefreshTimer=null,this.closed||this.refreshControlRoom().catch(e=>this.opts.onError?.(e))},150))}async resnapshot(){try{let e=await this.api.objects(this.key);this.applySnapshot(e.seats),this.updateEffectiveAvailability(e.hidden,e.closed),this.lastMessageAt=Date.now()}catch{}}applySnapshot(e,t){let s=a=>["free","held","booked","blocked"].includes(a)?a:"free",i=new Map;if(t!==void 0){let a=s(t);for(let o of this.knownLabels())i.set(o,a)}for(let[a,o]of Object.entries(e))i.set(a,s(o));this.status=i,this.modelVersion+=1,this.recountAll(),this.lastSyncedAt=Date.now(),this.repaintAll(),this.afterPaint(),this.recomputeTallies()}recountAll(){let e={held:0,booked:0,blocked:0};for(let t of this.status.values())t!=="free"&&(e[t]+=1);this.counts=e}setSeatsLocal(e,t){let s=[];for(let i of e){this.setStatusLabel(i,t);let a=this.labelToId.get(i);a&&s.push(a)}s.length&&this.renderer?.setStatus(s,M(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?"#f4b740":e==="booked"?"#22a06b":e==="blocked"?"#8b94ac":"#6e7bff"}sectionsForLabels(e){let t=new Set;for(let i of e){let a=this.labelToSeat.get(i);if(!a)continue;let o=this.sectionByObject.get(a.rowId);o&&o!==y&&t.add(o)}let s=[...t];return{ids:s,labels:s.map(i=>this.sectionLabelById.get(i)??i)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let i of e.slice(0,ee)){let a=this.labelToId.get(i);a&&this.renderer?.flashSeat(a,s)}}paintSpatialActivity(e){let t=e.sectionIds??this.sectionsForLabels(e.labels).ids,s=this.renderer?.getFocusedSection()??null;if(this.followLive&&t.length===1&&(e.status==="held"||e.status==="booked")){let a=this.root?.querySelector('[data-ref="followstatus"]');a&&(a.textContent=`Following ${e.labels.length===1?e.labels[0]:`${e.labels.length} seats`} \xB7 ${e.status}`),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=setTimeout(()=>{this.followLiveTimer=null,this.focusActivitySeats(e.labels,t[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(e.labels,e.status)},520)},220);return}if(!s&&t.length){let a=this.activityColor(e.status);for(let o of t.slice(0,te))this.renderer?.flashSection(o,a);return}(!t.length||s&&t.includes(s))&&this.pulseSeatLabels(e.labels,e.status)}locateSection(e){this.renderer?.focusSection(e)}focusActivitySeats(e,t){this.renderer?.focusSection(t);let s=e.slice(0,ee).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let i=s.map(r=>r.x),a=s.map(r=>r.y),o=Math.min(...i),l=Math.min(...a);this.renderer?.focusRegion({x:o-150,y:l-100,width:Math.max(...i)-o+300,height:Math.max(...a)-l+200})}locateActivity(e){let t=this.feed.find(i=>i.id===e);if(!t)return;let s=t.sectionIds??this.sectionsForLabels(t.labels).ids;if(this.followSeatTimer&&clearTimeout(this.followSeatTimer),s.length===1){this.focusActivitySeats(t.labels,s[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(t.labels,t.status)},520);return}this.zoomToFit(),this.followSeatTimer=setTimeout(()=>{if(this.followSeatTimer=null,s.length){let i=this.activityColor(t.status);for(let a of s.slice(0,te))this.renderer?.flashSection(a,i)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],i=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,a=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
451
+ <span class="slm-liveeventcopy">${p(i)} \xB7 ${e.count.toLocaleString()} ${a} ${p(e.verb)}</span>
452
+ <span class="slm-liveeventhint">Live</span>`,t.classList.add("on"),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.liveEventTimer=setTimeout(()=>{this.liveEventTimer=null,t.classList.remove("on"),t.innerHTML=""},2800)}applyReportRevenue(e){this.authoritativeGrossRevenue=e.report.byCategory.reduce((t,s)=>{let i=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(i)?i:0)},0),this.revenueStatus="current",this.recomputeTallies()}async refreshControlRoom(){let e=++this.revenueRequest,t=Date.now();try{let s=await this.api.controlRoom(this.key,this.trendWindowMinutes),i=s.bookedValue??s.revenue??{gross:0,bySection:[]},a=(i.bySection??[]).map(r=>{let c=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:c??0,bookedRevenue:c??0}}),o={...i,bySection:a},l={...s,bookedValue:o,revenue:o};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?l={...l,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let n={...l.bookedValue,gross:this.liveGross.value};l={...l,bookedValue:n,revenue:n}}else this.liveGross=null;this.controlRoomSnapshot=l,l.activity&&this.seedFeed(l.activity),this.rebaseServerTotals(l),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=l.bookedValue.gross,this.authoritativeCurrency=l.currency,this.currency=l.currency,this.revenueStatus="current",this.recomputeTallies(),this.applyHeatOverlay(),this.paintMonitorInsights(),this.seatHistoryPanel?.refresh();let r=this.getSelection().slice(-1)[0],c=this.els.rail?.querySelector("[data-seat-status]");r&&c&&(c.textContent=this.status.get(r.label)??"free"),this.opts.onControlRoom?.(l)}return l}catch(s){throw e===this.revenueRequest&&(this.revenueStatus="stale",this.recomputeTallies()),s}}rebaseServerTotals(e){let t=e.totals;if(!t||["free","held","booked","blocked"].some(s=>!Number.isFinite(t[s]))){this.serverBaseline=null;return}this.serverBaseline={model:this.modelVersion,server:{free:t.free,held:t.held,booked:t.booked,blocked:t.blocked},client:this.clientTallies()}}clientTallies(){let{held:e,booked:t,blocked:s}=this.counts;return{held:e,booked:t,blocked:s,free:Math.max(0,this.unitTotal()-e-t-s)}}buildTallies(){let e=this.clientTallies(),t=this.serverBaseline?.model===this.modelVersion?this.serverBaseline:null,s=l=>t?Math.max(0,t.server[l]+(e[l]-t.client[l])):e[l],i=this.controlRoomSnapshot?.event?.seatTotal,a={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(i)?i:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};a.capacityPct=a.total?Math.round(a.booked/a.total*100):0;let o=a.total-a.blocked;return a.sellThroughPct=o>0?Math.round(a.booked/o*100):0,a}recomputeTallies(){if(!this.closed){if(typeof requestAnimationFrame!="function"){this.flushTallies();return}this.paintHandle===null&&(this.paintHandle=requestAnimationFrame(()=>{this.paintHandle=null,this.flushTallies()}))}}flushTallies(){if(this.closed)return;let e=this.buildTallies();this.paintKpis(e),this.mode==="view"?(this.paintLegend(e),this.paintMonitorInsights()):this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="block"?this.paintSelBar(this.getSelection()):this.mode==="channels"&&this.channels?.handleSelectionChange(),this.opts.onTallies?.(e)}verbFor(e,t){return t==="held"?"held":t==="booked"?"booked":t==="blocked"?"blocked":t==="free"?e==="blocked"?"unblocked":e==="booked"?"cancelled":"available":t}pushActivity(e,t,s,i=Date.now()){let a=e[0];if(!a)return null;let o=this.sectionsForLabels(e),l={id:`${a}:${i}:${Math.random().toString(36).slice(2,6)}`,at:i,label:a,labels:[...e],count:e.length,verb:t,status:s,sectionIds:o.ids,sectionLabels:o.labels};return this.controlRoomSnapshot?.activity||this.feed.unshift(l),this.feed.length>R&&(this.feed.length=R),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(l),this.opts.onActivity?.(l),l}seedFeed(e){this.controlRoomSnapshot?.activity&&(this.feed=this.feed.filter(i=>i.id.startsWith("log:")));let t={hold:"held",book:"booked",release:"released",expire:"expired",block:"blocked",unblock:"unblocked",unbook:"cancelled"},s={hold:"held",book:"booked",release:"free",expire:"free",block:"blocked",unblock:"free",unbook:"free"};for(let i of e){if(this.feed.some(r=>r.id===`log:${i.id}`))continue;let a=i.labels[0];if(!a)continue;let o=this.sectionsForLabels(i.labels),l={id:`log:${i.id}`,at:i.at,label:a,labels:[...i.labels],count:i.labels.length,verb:t[i.action]??i.action,status:s[i.action]??"free",sectionIds:o.ids,sectionLabels:o.labels};this.feed.push(l),this.opts.onActivity?.(l)}this.feed.sort((i,a)=>a.at-i.at),this.feed.length>R&&(this.feed.length=R),this.mode==="view"&&this.paintFeed()}startFeedClock(){this.feedTimer=setInterval(()=>{this.mode==="view"&&(this.paintFeed(),this.paintMonitorInsights())},1e4)}selectionCap(){return this.mode!=="select"?1e6:this.opts.numberOfPlacesToSelect??this.opts.maxSelectedObjects??1e6}canSelectObject(e){let t=this.status.get(e.label)??"free",s=this.opts.unavailableObjectsSelectable??!0,i=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return i;try{return this.opts.isObjectSelectable(e,i)===!0}catch(a){return this.opts.onError?.(a),!1}}applyInitialSelection(){this.initialSelectionApplied||this.mode!=="select"||!this.renderer||(this.initialSelectionApplied=!0,this.selectByLabels(this.opts.selectedObjects??[]))}trimSelectionToCap(){if(this.mode!=="select")return;let e=this.getSelection(),t=this.selectionCap();e.length<=t||this.renderer?.deselect(e.slice(t).map(s=>s.id))}reconcileSelectPolicy(){if(this.mode!=="select")return;let e=this.getSelection().filter(t=>!this.canSelectObject(t));e.length&&this.renderer?.deselect(e.map(t=>t.id)),this.trimSelectionToCap(),this.syncSelection()}selectionLabels(){return this.getSelection().map(e=>e.label)}syncSelection(){let e=this.getSelection();this.mode==="block"?this.paintSelBar(e):this.mode==="inspect"?this.renderInspectRail(e):this.mode==="select"?this.paintSelectSelection(e):this.mode==="categories"?this.paintCategorySelection(e):this.mode==="channels"&&this.channels?.handleSelectionChange();let t=new Map(e.map(s=>[s.label,s]));if(this.mode==="select"){for(let[i,a]of t)this.lastSelectionLabels.has(i)||this.opts.onObjectSelected?.(a);for(let i of this.lastSelectionLabels)if(!t.has(i)){let a=this.labelToSeat.get(i);a&&this.opts.onObjectDeselected?.(a)}let s=this.getSelectionValidity();s&&(this.opts.onSelectionValidityChange?.(s),this.selectionWasValid!==s.isValid&&(s.isValid?this.opts.onSelectionValid?.(s):this.opts.onSelectionInvalid?.(s)),this.selectionWasValid=s.isValid)}this.lastSelectionLabels=new Set(t.keys()),this.navigation?.selectionChanged(e.length),this.opts.onSelectionChange?.(e)}buildChrome(){let e=document.createElement("div");e.className="slm",e.tabIndex=0,e.setAttribute("role","region"),e.setAttribute("aria-label","SeatLayer live control room"),e.innerHTML=`
329
453
  <div class="slm-bar">
330
454
  <div class="slm-modes" data-ref="modes" role="tablist" aria-label="Control room tools">
331
- ${K.map(s=>`<div class="slm-modegroup" data-group="${s.key}" role="presentation" hidden>
332
- <span class="slm-modegroup-label" aria-hidden="true">${p(s.label)}</span>
333
- ${s.tools.map(i=>`<button class="slm-mode" role="tab" data-mode="${i.mode}"
334
- title="${p(i.title)} (${i.shortcut})" aria-keyshortcuts="${i.shortcut}" hidden>${p(i.label)}</button>`).join("")}
455
+ ${se.map(i=>`<div class="slm-modegroup" data-group="${i.key}" role="presentation" hidden>
456
+ <span class="slm-modegroup-label" aria-hidden="true">${p(i.label)}</span>
457
+ ${i.tools.map(a=>`<button class="slm-mode" role="tab" data-mode="${a.mode}"
458
+ title="${p(a.title)} (${a.shortcut})" aria-keyshortcuts="${a.shortcut}" hidden>${p(a.label)}</button>`).join("")}
335
459
  </div>`).join("")}
336
460
  </div>
337
461
  <select class="slm-tools" data-ref="tools" aria-label="Control room tools"></select>
338
462
  <span class="slm-live"><span class="slm-live-dot"></span><span data-ref="livetext">CONNECTING</span></span>
339
463
  <div class="slm-bar-actions">
340
- <button class="slm-barbtn follow" data-ref="follow" aria-pressed="false"
341
- title="Stay on the current map view unless enabled">Follow live</button>
342
- <button class="slm-barbtn" data-ref="heat" aria-pressed="false"
464
+ <button class="slm-barbtn follow" data-ref="follow" aria-label="Follow live" aria-pressed="false"
465
+ title="Stay on the current map view unless enabled">Auto-follow</button>
466
+ <button class="slm-barbtn heat" data-ref="heat" aria-pressed="false"
343
467
  aria-label="Booking momentum overlay off"
344
- title="Highlight sections booking fastest in the selected time window">Booking momentum</button>
468
+ title="Highlight sections booking fastest in the selected time window">Heatmap</button>
345
469
  <button class="slm-barbtn" data-ref="fullscreen" title="Full screen (F)" aria-keyshortcuts="F">Full screen</button>
346
470
  </div>
347
471
  <div class="slm-kpis" data-ref="kpis"></div>
@@ -351,21 +475,26 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
351
475
  <div class="slm-map-host" data-ref="maphost"></div>
352
476
  <div class="slm-zoomhint" data-ref="zoomhint">Zoom in to marquee-select</div>
353
477
  <div class="slm-liveevent" data-ref="liveevent" role="status" aria-live="polite"></div>
478
+ <div class="slm-heat-status" data-ref="heatstatus" role="status" hidden></div>
479
+ <div class="slm-follow-status" data-ref="followstatus" role="status" hidden></div>
354
480
  <div class="slm-hud"><button class="slm-hud-chip" data-ref="zfit">Zoom to fit</button></div>
355
481
  </div>
356
482
  <aside class="slm-rail"><div class="slm-railscroll" data-ref="rail"></div></aside>
357
483
  </div>
358
484
  <div class="slm-toast" data-ref="toast"></div>
359
- `,this.host.appendChild(e),this.root=e,this.applyThemeVars(),this.watchThemeMode(),this.updateContainerLayout(),typeof ResizeObserver<"u"&&(this.layoutObserver=new ResizeObserver(()=>this.updateContainerLayout()),this.layoutObserver.observe(e));let t=s=>e.querySelector(`[data-ref="${s}"]`);this.mapHost=t("maphost"),this.els={modes:t("modes"),tools:t("tools"),livetext:t("livetext"),kpis:t("kpis"),follow:t("follow"),heat:t("heat"),fullscreen:t("fullscreen"),zoomhint:t("zoomhint"),liveevent:t("liveevent"),rail:t("rail"),toast:t("toast"),zfit:t("zfit")},this.els.modes.querySelectorAll("[data-mode]").forEach(s=>s.addEventListener("click",()=>this.setMode(s.dataset.mode))),this.els.tools.addEventListener("change",()=>this.setMode(this.els.tools.value)),this.els.zfit.addEventListener("click",()=>this.zoomToFit()),this.els.follow.addEventListener("click",()=>this.setFollowLive(!this.followLive)),this.els.heat.addEventListener("click",()=>this.setHeatOverlay(!this.heatEnabled)),this.els.fullscreen.addEventListener("click",()=>this.toggleFullscreen()),e.addEventListener("keydown",this.onKeyDown),this.els.rail.addEventListener("click",this.onRailClick),document.addEventListener("fullscreenchange",this.onFullscreenChange),this.paintModeTabs(),this.paintFollowLiveButton(),this.paintHeatButton(),this.paintFullscreenButton()}updateContainerLayout(){let e=this.root?.getBoundingClientRect().width||this.host.clientWidth;this.root?.classList.toggle("compact",e>0&&e<800),this.channels?.handleLayoutChange()}filterableSections(){return this.sectionsBase?[...this.sectionsBase.sections,...this.sectionsBase.ungrouped?[this.sectionsBase.ungrouped]:[]]:[]}applyFilteredSectionCanvas(e=this.filterableSections().filter(t=>t.label===this.filteredSectionLabel)){if(!this.renderer||this.mode!=="filterSections"||!e.length)return;let t=new Set(e.map(n=>n.id)),s=this.filterableSections().filter(n=>!t.has(n.id)).map(n=>n.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let i=e.flatMap(n=>n.seatLabels).map(n=>this.labelToSeat.get(n)).filter(n=>!!n&&Number.isFinite(n.x)&&Number.isFinite(n.y));if(!i.length){this.renderer.focusRegion(e[0].id);return}let o=Math.min(...i.map(n=>n.x)),a=Math.min(...i.map(n=>n.y)),l=Math.max(...i.map(n=>n.x)),r=Math.max(...i.map(n=>n.y)),c=Math.max(40,Math.max(l-o,r-a)*.08);this.renderer.focusRegion({x:o-c,y:a-c,width:Math.max(1,l-o)+c*2,height:Math.max(1,r-a)+c*2})}buildSectionOptions(){if(this.doc)try{let e=Ee(this.doc);this.sectionsBase=e,this.sectionOptions=[],this.sectionByObject=new Map(e.objectToSection),this.sectionLabelById.clear();for(let t of e.sections)this.sectionOptions.push({id:t.id,label:t.label}),this.sectionLabelById.set(t.id,t.label);e.ungrouped&&(this.sectionOptions.push({id:g,label:e.ungrouped.label}),this.sectionLabelById.set(g,e.ungrouped.label))}catch{}}toolAvailable(e){return e==="view"?!0:e==="channels"&&!this.channelCaps.view||e==="categories"&&!this.categoryCanManage||e==="tables"&&(!this.tableCanManage||!this.tables().length)?!1:!this.opts.tools||this.opts.tools.includes(e)}settleMode(){this.toolAvailable(this.mode)?this.paintModeTabs():this.setMode("view")}tables(){return(this.doc?Ae(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let i=[];s.querySelectorAll("[data-mode]").forEach(o=>{let a=o.dataset.mode,l=this.toolAvailable(a);if(o.hidden=!l,!l)return;i.push({mode:a,label:o.textContent??a});let r=a===this.mode;o.classList.toggle("on",r),o.setAttribute("aria-selected",String(r)),o.tabIndex=r?0:-1}),s.hidden=i.length===0,i.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:i})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${p(s.label)}">${s.tools.map(i=>`<option value="${i.mode}"${i.mode===this.mode?" selected":""}>${p(i.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let i=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${p(e)}</p><span class="slm-scope ${t}">${i}</span></div>
360
- <p class="slm-hint">${s}</p>`}paintFollowLiveButton(){let e=this.els.follow;e&&(e.classList.toggle("on",this.followLive),e.setAttribute("aria-pressed",String(this.followLive)),e.setAttribute("title",this.followLive?"Following new holds and bookings. Turn off to keep the current view.":"Stay on the current map view. Enable to follow new holds and bookings."))}paintHeatButton(){let e=this.els.heat;e&&(e.classList.toggle("on",this.heatEnabled),e.setAttribute("aria-pressed",String(this.heatEnabled)),e.setAttribute("aria-label",`Booking momentum overlay ${this.heatEnabled?"on":"off"}`),e.setAttribute("title",`${this.heatEnabled?"Hide":"Highlight"} sections booking fastest in the selected time window`),e.textContent="Booking momentum",this.paintMomentumHelp())}paintMomentumHelp(){let e=this.els.rail?.querySelector('[data-ref="momentumhelp"]');if(!e)return;e.hidden=!this.heatEnabled;let t=e.querySelector('[data-ref="momentumcopy"]');if(!t)return;let s=this.controlRoomSnapshot?.velocity.bySection.some(i=>i.netBooked>0);t.textContent=s?"Warmer sections have more completed bookings, adjusted for section size. Holds and viewers are not counted.":`No completed bookings in the last ${this.trendWindowMinutes} minutes.`}paintFullscreenButton(){this.els.fullscreen&&(this.els.fullscreen.textContent=this.isFullscreen()?"Exit full screen":"Full screen")}paintTrendWindow(){this.els.rail?.querySelectorAll("[data-window]").forEach(e=>{let t=Number(e.dataset.window);e.classList.toggle("on",t===this.trendWindowMinutes)})}setLive(e){this.root?.classList.toggle("live",e),this.els.livetext&&(this.els.livetext.textContent=e?"LIVE":"RECONNECTING"),this.paintMonitorInsights();let t=e?"live":"reconnecting";if(t!==this.connectionStatus){this.connectionStatus=t;try{this.opts.onConnectionChange?.(this.getConnection())}catch(s){this.opts.onError?.(s)}}}updateZoomHint(){let e=this.els.zoomhint;if(!e)return;let t=this.mode==="block"&&this.renderer?.getRung?.()!=="seats";e.classList.toggle("on",!!t)}formatKpiDelta(e,t,s){let i=t>0?"+":"\u2212",o=Math.abs(t);return e==="booked-value"?`${i}${y(o,s)}`:e==="booked-pct"?`${i}${o.toLocaleString()}pt`:`${i}${o.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?y(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),i=[{key:"booked-inventory",raw:e.booked,n:e.booked.toLocaleString(),l:"Booked inventory",dot:"#22a06b",title:"Inventory units booked"},{key:"held-seats",raw:e.held,n:e.held.toLocaleString(),l:"Held inventory",dot:"#f4b740",title:"Inventory currently held"},{key:"free-seats",raw:e.free,n:e.free.toLocaleString(),l:"Available",dot:"#6e7bff",title:"Inventory available to book"},{key:"blocked",raw:e.blocked,n:e.blocked.toLocaleString(),l:"Blocked",dot:"#8b94ac",title:"Inventory withheld from booking"},{key:"viewing-map",raw:s?.shoppingSessions??null,n:s?s.shoppingSessions.toLocaleString():"\u2014",l:"Viewing map",title:"Active map sessions right now"},{key:"active-holds",raw:s?.activeHolds??null,n:s?s.activeHolds.toLocaleString():"\u2014",l:"Active holds",title:"Sessions currently holding inventory"},{key:"booked-pct",raw:e.capacityPct,n:`${e.capacityPct}%`,l:"Booked",title:"Booked inventory as a share of the whole event"},{key:"booked-value",raw:e.bookedValueStatus==="current"?e.bookedValue:null,n:t,l:"Booked value",title:"Configured value attached to booked inventory"}],o=!1;this.els.kpis.innerHTML=i.map(a=>{let l=this.lastKpiValues.get(a.key),r=a.raw!=null&&l!=null&&a.raw!==l,c=r?a.raw-l:0;r&&(o=!0,this.activeKpiDeltas.set(a.key,{text:this.formatKpiDelta(a.key,c,e.currency),down:c<0})),a.raw!=null&&this.lastKpiValues.set(a.key,a.raw);let n=this.activeKpiDeltas.get(a.key);return`<div class="slm-kpi${n?" changed":""}" data-kpi="${a.key}" title="${p(a.title)}">
361
- <b>${a.dot?`<span class="dot" style="background:${a.dot}"></span>`:""}${a.n}</b><span>${a.l}</span>
485
+ `,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let i=e.querySelector(".slm-rail");i&&F(i)});let t=e.querySelector(".slm-rail");t&&this.selectObserver.observe(t,{childList:!0,subtree:!0}),this.applyThemeVars(),this.watchThemeMode(),this.updateContainerLayout(),typeof ResizeObserver<"u"&&(this.layoutObserver=new ResizeObserver(()=>this.updateContainerLayout()),this.layoutObserver.observe(e));let s=i=>e.querySelector(`[data-ref="${i}"]`);this.mapHost=s("maphost"),this.els={modes:s("modes"),tools:s("tools"),livetext:s("livetext"),kpis:s("kpis"),follow:s("follow"),heat:s("heat"),fullscreen:s("fullscreen"),zoomhint:s("zoomhint"),liveevent:s("liveevent"),rail:s("rail"),toast:s("toast"),zfit:s("zfit")},this.els.modes.querySelectorAll("[data-mode]").forEach(i=>i.addEventListener("click",()=>this.setMode(i.dataset.mode))),this.els.tools.addEventListener("change",()=>this.setMode(this.els.tools.value)),this.els.zfit.addEventListener("click",()=>{this.setFollowLive(!1),this.zoomToFit()}),this.els.follow.addEventListener("click",()=>this.setFollowLive(!this.followLive)),this.els.heat.addEventListener("click",()=>this.setHeatOverlay(!this.heatEnabled)),this.els.fullscreen.addEventListener("click",()=>this.toggleFullscreen()),e.addEventListener("keydown",this.onKeyDown),this.els.rail.addEventListener("click",this.onRailClick),document.addEventListener("fullscreenchange",this.onFullscreenChange),this.paintModeTabs(),this.paintFollowLiveButton(),this.paintHeatButton(),this.paintFullscreenButton(),this.navigation=new L({root:e,map:this.mapHost,setMoving:i=>{this.movingMap=i,this.updateRendererInteraction()},pauseFollow:()=>{this.followLive&&this.setFollowLive(!1)},zoomIn:()=>this.renderer?.zoomIn(),zoomOut:()=>this.renderer?.zoomOut(),targets:i=>this.navigationTargets(i)}),this.navigation.update(this.isBulkSelectMode(),this.mode==="view")}navigationTargets(e){let t=e.toLocaleLowerCase(),s=[];for(let a of this.sectionOptions)if(a.label.toLocaleLowerCase().includes(t)&&s.push({label:a.label,detail:"Section",locate:()=>this.locateSection(a.id)}),s.length>=20)return s;let i=new Map;for(let a of this.labelToSeat.values()){let o=i.get(a.rowId)??{minX:a.x,minY:a.y,maxX:a.x,maxY:a.y};o.minX=Math.min(o.minX,a.x),o.minY=Math.min(o.minY,a.y),o.maxX=Math.max(o.maxX,a.x),o.maxY=Math.max(o.maxY,a.y),i.set(a.rowId,o)}for(let a of this.doc?J(this.doc).flatMap(o=>o.objects):[]){if(a.type!=="row"||!(a.displayLabel??a.label).toLocaleLowerCase().includes(t))continue;let o=i.get(a.id);if(!o)continue;let{minX:l,minY:r,maxX:c,maxY:n}=o;if(s.push({label:a.displayLabel??a.label,detail:"Row",locate:()=>{let d=this.sectionByObject.get(a.id);d&&this.renderer?.focusSection(d),this.renderer?.focusRegion({x:l-30,y:r-30,width:c-l+60,height:n-r+60},{minScale:1.2,animate:!1})}}),s.length>=20)return s}for(let a of this.labelToSeat.values())if(a.label.toLocaleLowerCase().includes(t)&&(s.push({label:a.label,detail:"Seat",locate:()=>{let o=this.sectionByObject.get(a.rowId);o&&this.renderer?.focusSection(o),this.renderer?.focusRegion({x:a.x-180,y:a.y-120,width:360,height:240},{animate:!1,minScale:1.5}),this.renderer?.flashSeat(a.id,this.activityColor(this.status.get(a.label)??"free"))}}),s.length>=20))break;return s}updateContainerLayout(){let e=this.root?.getBoundingClientRect().width||this.host.clientWidth;this.root?.classList.toggle("compact",e>0&&e<800),this.channels?.handleLayoutChange()}filterableSections(){return this.sectionsBase?[...this.sectionsBase.sections,...this.sectionsBase.ungrouped?[this.sectionsBase.ungrouped]:[]]:[]}applyFilteredSectionCanvas(e=this.filterableSections().filter(t=>t.label===this.filteredSectionLabel)){if(!this.renderer||this.mode!=="filterSections"||!e.length)return;let t=new Set(e.map(n=>n.id)),s=this.filterableSections().filter(n=>!t.has(n.id)).map(n=>n.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let i=e.flatMap(n=>n.seatLabels).map(n=>this.labelToSeat.get(n)).filter(n=>!!n&&Number.isFinite(n.x)&&Number.isFinite(n.y));if(!i.length){this.renderer.focusRegion(e[0].id);return}let a=Math.min(...i.map(n=>n.x)),o=Math.min(...i.map(n=>n.y)),l=Math.max(...i.map(n=>n.x)),r=Math.max(...i.map(n=>n.y)),c=Math.max(40,Math.max(l-a,r-o)*.08);this.renderer.focusRegion({x:a-c,y:o-c,width:Math.max(1,l-a)+c*2,height:Math.max(1,r-o)+c*2})}buildSectionOptions(){if(this.doc)try{let e=je(this.doc);this.sectionsBase=e,this.sectionOptions=[],this.sectionByObject=new Map(e.objectToSection),this.sectionLabelById.clear();for(let t of e.sections)this.sectionOptions.push({id:t.id,label:t.label}),this.sectionLabelById.set(t.id,t.label);e.ungrouped&&(this.sectionOptions.push({id:y,label:e.ungrouped.label}),this.sectionLabelById.set(y,e.ungrouped.label))}catch{}}toolAvailable(e){return e==="view"?!0:e==="channels"&&!this.channelCaps.view||e==="categories"&&!this.categoryCanManage||e==="tables"&&(!this.tableCanManage||!this.tables().length)?!1:!this.opts.tools||this.opts.tools.includes(e)}settleMode(){this.toolAvailable(this.mode)?this.paintModeTabs():this.setMode("view")}tables(){return(this.doc?J(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let i=[];s.querySelectorAll("[data-mode]").forEach(a=>{let o=a.dataset.mode,l=this.toolAvailable(o);if(a.hidden=!l,!l)return;i.push({mode:o,label:a.textContent??o});let r=o===this.mode;a.classList.toggle("on",r),a.setAttribute("aria-selected",String(r)),a.tabIndex=r?0:-1}),s.hidden=i.length===0,i.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:i})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${p(s.label)}">${s.tools.map(i=>`<option value="${i.mode}"${i.mode===this.mode?" selected":""}>${p(i.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let i=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${p(e)}</p><span class="slm-scope ${t}">${i}</span></div>
486
+ <p class="slm-hint">${s}</p>`}paintFollowLiveButton(){let e=this.els.follow;if(!e)return;e.classList.toggle("on",this.followLive),e.setAttribute("aria-pressed",String(this.followLive)),e.textContent="Auto-follow";let t=this.root?.querySelector('[data-ref="followstatus"]');t&&(t.hidden=!this.followLive,t.textContent="Waiting for new holds or bookings"),e.setAttribute("title",this.followLive?"Following new holds and bookings. Turn off to keep the current view.":"Stay on the current map view. Enable to follow new holds and bookings.")}paintHeatButton(){let e=this.els.heat;e&&(e.classList.toggle("on",this.heatEnabled),e.setAttribute("aria-pressed",String(this.heatEnabled)),e.setAttribute("aria-label",`Booking momentum overlay ${this.heatEnabled?"on":"off"}`),e.setAttribute("title",`${this.heatEnabled?"Hide":"Highlight"} sections booking fastest in the selected time window`),e.textContent="Heatmap",this.paintMomentumHelp())}paintMomentumHelp(){let e=this.root?.querySelector('[data-ref="heatstatus"]');if(e){e.hidden=!this.heatEnabled;let a=this.controlRoomSnapshot?.velocity.bySection.some(o=>o.netBooked>0);e.textContent=this.controlRoomSnapshot?a?`Booking heatmap \xB7 last ${this.trendWindowMinutes}m \xB7 warmer = higher net booking rate`:`No positive net bookings in the last ${this.trendWindowMinutes}m`:"Loading booking heatmap\u2026"}let t=this.els.rail?.querySelector('[data-ref="momentumhelp"]');if(!t)return;t.hidden=!this.heatEnabled;let s=t.querySelector('[data-ref="momentumcopy"]');if(!s)return;let i=this.controlRoomSnapshot?.velocity.bySection.some(a=>a.netBooked>0);s.textContent=i?"Warmer sections have more completed bookings, adjusted for section size. Holds and viewers are not counted.":`No completed bookings in the last ${this.trendWindowMinutes} minutes.`}paintFullscreenButton(){this.els.fullscreen&&(this.els.fullscreen.textContent=this.isFullscreen()?"Exit full screen":"Full screen")}paintTrendWindow(){this.els.rail?.querySelectorAll("[data-window]").forEach(e=>{let t=Number(e.dataset.window);e.classList.toggle("on",t===this.trendWindowMinutes)})}setLive(e){this.root?.classList.toggle("live",e),this.els.livetext&&(this.els.livetext.textContent=e?"LIVE":"RECONNECTING"),this.paintMonitorInsights();let t=e?"live":"reconnecting";if(t!==this.connectionStatus){this.connectionStatus=t;try{this.opts.onConnectionChange?.(this.getConnection())}catch(s){this.opts.onError?.(s)}}}updateZoomHint(){let e=this.els.zoomhint;if(!e)return;let t=this.isBulkSelectMode()&&!this.movingMap&&this.renderer?.getRung?.()!=="seats";e.classList.toggle("on",!!t)}formatKpiDelta(e,t,s){let i=t>0?"+":"\u2212",a=Math.abs(t);return e==="booked-value"?`${i}${C(a,s)}`:e==="booked-pct"?`${i}${a.toLocaleString()}pt`:`${i}${a.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?C(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),i=[{key:"booked-inventory",raw:e.booked,n:e.booked.toLocaleString(),l:"Booked inventory",dot:"#22a06b",title:"Inventory units booked"},{key:"held-seats",raw:e.held,n:e.held.toLocaleString(),l:"Held inventory",dot:"#f4b740",title:"Inventory currently held"},{key:"free-seats",raw:e.free,n:e.free.toLocaleString(),l:"Available",dot:"#6e7bff",title:"Inventory available to book"},{key:"blocked",raw:e.blocked,n:e.blocked.toLocaleString(),l:"Blocked",dot:"#8b94ac",title:"Inventory withheld from booking"},{key:"viewing-map",raw:s?.shoppingSessions??null,n:s?s.shoppingSessions.toLocaleString():"\u2014",l:"Viewing map",title:"Active map sessions right now"},{key:"active-holds",raw:s?.activeHolds??null,n:s?s.activeHolds.toLocaleString():"\u2014",l:"Active holds",title:"Sessions currently holding inventory"},{key:"booked-pct",raw:e.capacityPct,n:`${e.capacityPct}%`,l:"Booked",title:"Booked inventory as a share of the whole event"},{key:"booked-value",raw:e.bookedValueStatus==="current"?e.bookedValue:null,n:t,l:"Booked value",title:"Configured value attached to booked inventory"}],a=!1;this.els.kpis.innerHTML=i.map(o=>{let l=this.lastKpiValues.get(o.key),r=o.raw!=null&&l!=null&&o.raw!==l,c=r?o.raw-l:0;r&&(a=!0,this.activeKpiDeltas.set(o.key,{text:this.formatKpiDelta(o.key,c,e.currency),down:c<0})),o.raw!=null&&this.lastKpiValues.set(o.key,o.raw);let n=this.activeKpiDeltas.get(o.key);return`<div class="slm-kpi${n?" changed":""}" data-kpi="${o.key}" title="${p(o.title)}">
487
+ <b>${o.dot?`<span class="dot" style="background:${o.dot}"></span>`:""}${o.n}</b><span>${o.l}</span>
362
488
  ${n?`<span class="slm-kpidelta${n.down?" down":""}">${n.text}</span>`:""}
363
- </div>`}).join(""),o&&(this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.kpiCleanupTimer=setTimeout(()=>{this.kpiCleanupTimer=null,this.activeKpiDeltas.clear(),this.els.kpis?.querySelectorAll(".slm-kpidelta").forEach(a=>a.remove()),this.els.kpis?.querySelectorAll(".slm-kpi.changed").forEach(a=>a.classList.remove("changed"))},1500))}paintRail(){this.mode==="view"?this.renderViewRail():this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="select"?this.renderSelectRail():this.mode==="filterSections"?this.renderFilterSectionsRail():this.mode==="sections"?this.renderSectionsRail():this.mode==="categories"?this.renderCategoriesRail():this.mode==="tables"?this.renderTablesRail():this.mode==="channels"?this.channels?this.channels.paintRail():this.channelsLoading?this.els.rail.innerHTML='<div class="slm-empty" role="status">Loading sales channels\u2026</div>':this.els.rail.innerHTML='<div class="slm-empty" role="alert">Sales channels could not be loaded. Switch away and back to try again.</div>':this.renderBlockRail(),this.updateZoomHint()}renderViewRail(){this.els.rail.innerHTML=`
364
- ${this.railHeader("Monitor","read","Watch the event live. Inventory, buyers on the map and booking movement update on this board as they happen \u2014 nothing here changes the event.")}
365
- <div class="slm-health" data-ref="presence"></div>
366
- <div class="slm-legend" data-ref="legend"></div>
489
+ </div>`}).join(""),a&&(this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.kpiCleanupTimer=setTimeout(()=>{this.kpiCleanupTimer=null,this.activeKpiDeltas.clear(),this.els.kpis?.querySelectorAll(".slm-kpidelta").forEach(o=>o.remove()),this.els.kpis?.querySelectorAll(".slm-kpi.changed").forEach(o=>o.classList.remove("changed"))},1500))}paintRail(){this.root?.classList.toggle("monitor-view",this.mode==="view"||this.mode==="inspect"),this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.mode==="view"?this.renderViewRail():this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="select"?this.renderSelectRail():this.mode==="filterSections"?this.renderFilterSectionsRail():this.mode==="sections"?this.renderSectionsRail():this.mode==="categories"?this.renderCategoriesRail():this.mode==="tables"?this.renderTablesRail():this.mode==="channels"?this.channels?this.channels.paintRail():this.channelsLoading?this.els.rail.innerHTML='<div class="slm-empty" role="status">Loading sales channels\u2026</div>':this.els.rail.innerHTML='<div class="slm-empty" role="alert">Sales channels could not be loaded. Switch away and back to try again.</div>':this.renderBlockRail(),this.updateZoomHint()}renderViewRail(){this.els.rail.innerHTML=`
490
+ <div class="slm-monitor-head"><h2>Live activity</h2><span data-ref="presence" class="slm-monitor-connection"></span></div>
491
+ <div class="slm-monitor-tabs" role="tablist" aria-label="Monitor details">
492
+ <button role="tab" aria-selected="true" data-monitor-tab="activity">Activity</button>
493
+ <button role="tab" aria-selected="false" data-monitor-tab="sections">Section inventory</button>
494
+ </div>
495
+ <div data-monitor-panel="activity" class="slm-monitor-activity"><div data-ref="feed"></div></div>
496
+ <div data-monitor-panel="sections" hidden>
367
497
  <div class="slm-sectionhead">
368
- <div><p class="slm-eyebrow">Section inventory</p><p class="slm-note">Configured booked value \xB7 booking momentum</p></div>
369
498
  <div class="slm-windows" aria-label="Booking momentum window">
370
499
  ${[5,15,30,60].map(e=>`<button class="slm-window" data-window="${e}">${e}m</button>`).join("")}
371
500
  </div>
@@ -375,16 +504,11 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
375
504
  <p class="slm-momentumcopy" data-ref="momentumcopy"></p>
376
505
  </div>
377
506
  <div class="slm-sectionlist" data-ref="sections"></div>
378
- <p class="slm-eyebrow">Activity</p>
379
- <div class="slm-feed" data-ref="feed"></div>
380
- `,this.els.presence=this.els.rail.querySelector('[data-ref="presence"]'),this.els.legend=this.els.rail.querySelector('[data-ref="legend"]'),this.els.sections=this.els.rail.querySelector('[data-ref="sections"]'),this.els.feed=this.els.rail.querySelector('[data-ref="feed"]'),this.els.rail.querySelectorAll("[data-window]").forEach(e=>e.addEventListener("click",()=>{let t=Number(e.dataset.window);this.setTrendWindow(t).catch(s=>this.opts.onError?.(s))})),this.recomputeTallies(),this.paintMonitorInsights(),this.paintTrendWindow(),this.paintMomentumHelp(),this.paintFeed()}presenceCounts(){return this.livePresence?.value??this.controlRoomSnapshot?.presence??null}paintMonitorInsights(){if(this.mode!=="view")return;let e=this.controlRoomSnapshot;if(this.els.presence){let i=this.root?.classList.contains("live"),o=this.lastSyncedAt?E(this.lastSyncedAt,Date.now()):"waiting",a=this.presenceCounts();this.els.presence.innerHTML=`
381
- <div class="slm-healthitem" title="Active map sessions right now"><b>${a?a.shoppingSessions.toLocaleString():"\u2014"}</b><span>Viewing map</span></div>
382
- <div class="slm-healthitem" title="Sessions currently holding inventory"><b>${a?a.activeHolds.toLocaleString():"\u2014"}</b><span>Active holds</span></div>
383
- <div class="slm-healthitem"><b>${i?"Healthy":"Reconnecting"}</b><span>Live connection</span></div>
384
- <div class="slm-healthitem"><b>${o}</b><span>Last sync</span></div>`}if(!this.els.sections)return;if(!e){this.els.sections.innerHTML='<div class="slm-empty">Loading authoritative section metrics\u2026</div>';return}let t=new Map(e.velocity.bySection.map(i=>[i.sectionId,i])),s=[...e.bookedValue.bySection].sort((i,o)=>{let a=t.get(i.sectionId)?.netBooked??0;return(t.get(o.sectionId)?.netBooked??0)-a||o.bookedValue-i.bookedValue});this.els.sections.innerHTML=s.length?s.map(i=>{let o=t.get(i.sectionId),a=o?.netBooked??0,l=`${a>0?"+":""}${a}`,r=o?.trend==="rising"||o?.trend==="cooling"?o.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${p(i.sectionId)}" title="Focus ${p(i.sectionLabel)} on the map">
385
- <span class="slm-sectiontop"><span>${p(i.sectionLabel)}</span><span>${y(i.bookedValue,e.currency)}</span></span>
386
- <span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${l} in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${r}">${r}</span><span class="slm-sectionlocate">Locate</span></span>
387
- </button>`}).join(""):'<div class="slm-empty">No section metrics are available for this chart.</div>',this.paintTrendWindow(),this.paintMomentumHelp()}applyHeatOverlay(){let e=this.controlRoomSnapshot;if(!this.heatEnabled||!e){this.renderer?.setSectionHeat(null);return}let t=new Map(e.bookedValue.bySection.map(a=>[a.sectionId,Math.max(1,a.total)])),s=e.velocity.bySection.map(a=>({sectionId:a.sectionId,rate:Math.max(0,a.netBooked)/(t.get(a.sectionId)??1)/e.velocity.windowMinutes})),i=Math.max(0,...s.map(a=>a.rate)),o={};for(let a of s)o[a.sectionId]=i>0?Math.sqrt(a.rate/i):0;this.renderer?.setSectionHeat(o)}renderSelectRail(){let e=this.doc?.categories??[],t=this.opts.numberOfPlacesToSelect,s=this.selectionCap();this.els.rail.innerHTML=`
507
+ </div>
508
+ `,this.els.presence=this.els.rail.querySelector('[data-ref="presence"]'),this.els.legend=this.els.rail.querySelector('[data-ref="legend"]'),this.els.sections=this.els.rail.querySelector('[data-ref="sections"]'),this.els.feed=this.els.rail.querySelector('[data-ref="feed"]'),this.activityPanel=new w(this.els.feed,this.sectionOptions,e=>{this.setFollowLive(!1),this.locateActivity(e)}),this.els.rail.querySelectorAll("[data-monitor-tab]").forEach(e=>e.addEventListener("click",()=>{let t=e.dataset.monitorTab;this.els.rail.querySelectorAll("[data-monitor-tab]").forEach(s=>s.setAttribute("aria-selected",String(s.dataset.monitorTab===t))),this.els.rail.querySelectorAll("[data-monitor-panel]").forEach(s=>{s.hidden=s.dataset.monitorPanel!==t})})),this.els.rail.querySelectorAll("[data-window]").forEach(e=>e.addEventListener("click",()=>{let t=Number(e.dataset.window);this.setTrendWindow(t).catch(s=>this.opts.onError?.(s))})),this.recomputeTallies(),this.paintMonitorInsights(),this.paintTrendWindow(),this.paintMomentumHelp(),this.paintFeed()}presenceCounts(){return this.livePresence?.value??this.controlRoomSnapshot?.presence??null}paintMonitorInsights(){if(this.mode!=="view")return;let e=this.controlRoomSnapshot;if(this.els.presence){let i=this.root?.classList.contains("live"),a=this.lastSyncedAt?X(this.lastSyncedAt,Date.now()):"waiting";this.els.presence.textContent=i?"\u25CF Live":"Reconnecting",this.els.presence.title=`Last data received: ${a}`}if(!this.els.sections)return;if(!e){this.els.sections.innerHTML='<div class="slm-empty">Loading authoritative section metrics\u2026</div>';return}let t=new Map(e.velocity.bySection.map(i=>[i.sectionId,i])),s=[...e.bookedValue.bySection].sort((i,a)=>{let o=t.get(i.sectionId)?.netBooked??0;return(t.get(a.sectionId)?.netBooked??0)-o||a.bookedValue-i.bookedValue});this.els.sections.innerHTML=s.length?s.map(i=>{let a=t.get(i.sectionId),o=a?.netBooked??0,l=`${o>0?"+":""}${o}`,r=a?.trend==="rising"||a?.trend==="cooling"?a.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${p(i.sectionId)}" title="Focus ${p(i.sectionLabel)} on the map">
509
+ <span class="slm-sectiontop"><span>${p(i.sectionLabel)}</span><span title="Configured value of currently booked inventory">${C(i.bookedValue,e.currency)}</span></span>
510
+ <span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${l} net in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${r}">${r}</span><span class="slm-sectionlocate">Locate</span></span>
511
+ </button>`}).join(""):'<div class="slm-empty">No section metrics are available for this chart.</div>',this.paintTrendWindow(),this.paintMomentumHelp()}applyHeatOverlay(){let e=this.controlRoomSnapshot;if(!this.heatEnabled||!e){this.renderer?.setSectionHeat(null);return}let t=new Map(e.bookedValue.bySection.map(o=>[o.sectionId,Math.max(1,o.total)])),s=e.velocity.bySection.map(o=>({sectionId:o.sectionId,rate:Math.max(0,o.netBooked)/(t.get(o.sectionId)??1)/e.velocity.windowMinutes})),i=Math.max(0,...s.map(o=>o.rate)),a={};for(let o of s)a[o.sectionId]=i>0?Math.sqrt(o.rate/i):0;this.renderer?.setSectionHeat(a)}renderSelectRail(){let e=this.doc?.categories??[],t=this.opts.numberOfPlacesToSelect,s=this.selectionCap();this.els.rail.innerHTML=`
388
512
  ${this.railHeader("Select","host","Pick seats for your own back-office operation \u2014 the selection is handed to your app. This tool is read-only inside the control room: it never books, releases or blocks seats by itself.")}
389
513
  <div class="slm-selbar" aria-live="polite"><span class="slm-selnum" data-ref="selectnum">0</span><span class="slm-sellabel" data-ref="selectmeta">selected</span></div>
390
514
  <p class="slm-note" data-ref="selectvalidity">${t?`Select exactly ${t.toLocaleString()} object${t===1?"":"s"}.`:`Up to ${s.toLocaleString()} objects may be selected.`}</p>
@@ -399,10 +523,10 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
399
523
  <span>${p(i.label??i.key)}</span>
400
524
  <span class="slm-chipcount" data-cat-count>0</span>
401
525
  <span class="slm-chipcheck" aria-hidden="true">\u2713</span>
402
- </button>`).join("")}</div>`:""}`,this.els.selectnum=this.els.rail.querySelector('[data-ref="selectnum"]'),this.els.selectmeta=this.els.rail.querySelector('[data-ref="selectmeta"]'),this.els.selectvalidity=this.els.rail.querySelector('[data-ref="selectvalidity"]'),this.els.selectclear=this.els.rail.querySelector('[data-ref="selectclear"]'),this.els.rail.querySelector('[data-ref="selectall"]')?.addEventListener("click",()=>this.selectAll()),this.els.selectclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-select-cat]").forEach(i=>{i.addEventListener("click",()=>{let o=i.dataset.selectCat,a=[...this.labelToSeat.values()].filter(r=>r.categoryKey===o&&this.canSelectObject(r)),l=new Set(this.selectionLabels());a.length>0&&a.every(r=>l.has(r.label))?this.deselectCategories([o]):this.selectCategories([o])})}),this.paintSelectSelection(this.getSelection())}paintSelectSelection(e){if(!this.els.selectnum||!this.els.selectmeta)return;let t=e.length;this.els.selectnum.textContent=t.toLocaleString(),this.els.selectmeta.textContent=t===1?"object selected":"objects selected",this.els.selectclear.disabled=t===0;let s=this.getSelectionValidity();this.els.selectvalidity&&(this.els.selectvalidity.textContent=s?s.isValid?`Ready \u2014 exactly ${s.required.toLocaleString()} selected.`:`Select ${s.remaining.toLocaleString()} more to continue.`:`${Math.max(0,this.selectionCap()-t).toLocaleString()} selections remaining.`);let i=new Set(e.map(o=>o.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(o=>{let a=o.dataset.selectCat,l=[...this.labelToSeat.values()].filter(h=>h.categoryKey===a&&this.canSelectObject(h)),r=l.filter(h=>i.has(h.label)).length,c=l.length>0&&r===l.length;o.classList.toggle("on",c),o.setAttribute("aria-pressed",String(c));let n=o.querySelector("[data-cat-count]");n&&(n.textContent=r?`${r}/${l.length}`:l.length.toLocaleString()),o.disabled=l.length===0})}renderFilterSectionsRail(){let e=new Map;for(let t of this.filterableSections())e.set(t.label,[...e.get(t.label)??[],t]);this.els.rail.innerHTML=`
526
+ </button>`).join("")}</div>`:""}`,this.els.selectnum=this.els.rail.querySelector('[data-ref="selectnum"]'),this.els.selectmeta=this.els.rail.querySelector('[data-ref="selectmeta"]'),this.els.selectvalidity=this.els.rail.querySelector('[data-ref="selectvalidity"]'),this.els.selectclear=this.els.rail.querySelector('[data-ref="selectclear"]'),this.els.rail.querySelector('[data-ref="selectall"]')?.addEventListener("click",()=>this.selectAll()),this.els.selectclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-select-cat]").forEach(i=>{i.addEventListener("click",()=>{let a=i.dataset.selectCat,o=[...this.labelToSeat.values()].filter(r=>r.categoryKey===a&&this.canSelectObject(r)),l=new Set(this.selectionLabels());o.length>0&&o.every(r=>l.has(r.label))?this.deselectCategories([a]):this.selectCategories([a])})}),this.paintSelectSelection(this.getSelection())}paintSelectSelection(e){if(!this.els.selectnum||!this.els.selectmeta)return;let t=e.length;this.els.selectnum.textContent=t.toLocaleString(),this.els.selectmeta.textContent=t===1?"object selected":"objects selected",this.els.selectclear.disabled=t===0;let s=this.getSelectionValidity();this.els.selectvalidity&&(this.els.selectvalidity.textContent=s?s.isValid?`Ready \u2014 exactly ${s.required.toLocaleString()} selected.`:`Select ${s.remaining.toLocaleString()} more to continue.`:`${Math.max(0,this.selectionCap()-t).toLocaleString()} selections remaining.`);let i=new Set(e.map(a=>a.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(a=>{let o=a.dataset.selectCat,l=[...this.labelToSeat.values()].filter(d=>d.categoryKey===o&&this.canSelectObject(d)),r=l.filter(d=>i.has(d.label)).length,c=l.length>0&&r===l.length;a.classList.toggle("on",c),a.setAttribute("aria-pressed",String(c));let n=a.querySelector("[data-cat-count]");n&&(n.textContent=r?`${r}/${l.length}`:l.length.toLocaleString()),a.disabled=l.length===0})}renderFilterSectionsRail(){let e=new Map;for(let t of this.filterableSections())e.set(t.label,[...e.get(t.label)??[],t]);this.els.rail.innerHTML=`
403
527
  ${this.railHeader("Filter sections","host","Narrow the map to one section for your own reporting. Sections sharing a label stay together and the map frames their combined inventory. Nothing changes for buyers.")}
404
- ${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,o=s.reduce((a,l)=>a+l.seatCount,0);return`<button type="button" class="slm-sectionrow${i?" on":""}" data-filter-section="${p(t)}" aria-pressed="${i}">
405
- <span class="slm-sectiontop"><span>${p(t)}</span><span>${o.toLocaleString()}</span></span>
528
+ ${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,a=s.reduce((o,l)=>o+l.seatCount,0);return`<button type="button" class="slm-sectionrow${i?" on":""}" data-filter-section="${p(t)}" aria-pressed="${i}">
529
+ <span class="slm-sectiontop"><span>${p(t)}</span><span>${a.toLocaleString()}</span></span>
406
530
  <span class="slm-sectionmeta"><span>${s.length===1?"One section":`${s.length.toLocaleString()} matching sections`}</span><span class="slm-sectionlocate">${i?"Filtered":"Filter"}</span></span>
407
531
  </button>`}).join("")}</div>
408
532
  <button type="button" class="slm-btn ghost" data-clear-filter ${this.filteredSectionLabel?"":"disabled"}>Clear filter</button>`:'<div class="slm-empty">This chart has no filterable sections.</div>'}`,this.els.rail.querySelectorAll("[data-filter-section]").forEach(t=>{t.addEventListener("click",()=>this.setFilteredSection(t.dataset.filterSection))}),this.els.rail.querySelector("[data-clear-filter]")?.addEventListener("click",()=>this.clearFilteredSection())}categorySeats(e){return[...this.labelToSeat.values()].filter(t=>t.categoryKey===e&&this.canSelectObject(t))}renderCategoriesRail(){let e=this.doc?.categories??[];this.els.rail.innerHTML=`
@@ -431,60 +555,47 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
431
555
  <span class="dot" style="background:${p(s.color??"#6e7bff")}"></span>
432
556
  <span class="slm-categorycopy"><b>${p(s.label??s.key)}</b><small data-cat-current>0 seats now</small></span>
433
557
  <span class="slm-categoryact" data-cat-action>Move here</span>
434
- </button>`).join("")}</div>`;let t=s=>this.els.rail.querySelector(`[data-ref="${s}"]`);this.els.categorynum=t("categorynum"),this.els.categorymeta=t("categorymeta"),this.els.categoryhelp=t("categoryhelp"),this.els.categoryclear=t("categoryclear"),t("categoryall").addEventListener("click",()=>this.selectAll()),this.els.categoryclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-pick-category]").forEach(s=>{s.addEventListener("click",()=>{let i=s.dataset.pickCategory,o=this.categorySeats(i),a=new Set(this.selectionLabels());o.length>0&&o.every(l=>a.has(l.label))?this.deselectCategories([i]):this.selectCategories([i])})}),this.els.rail.querySelectorAll("[data-assign-category]").forEach(s=>{s.addEventListener("click",()=>{this.setCategory(s.dataset.assignCategory)})}),this.paintCategorySelection(this.getSelection())}paintCategorySelection(e){if(!this.els.categorynum)return;let t=e.length;this.els.categorynum.textContent=t.toLocaleString(),this.els.categoryclear.disabled=t===0;let s=new Map;for(let a of e)s.set(a.categoryKey,(s.get(a.categoryKey)??0)+1);let i=a=>this.doc?.categories.find(l=>l.key===a)?.label??a;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([a,l])=>`${l.toLocaleString()} ${i(a)}`).join(", ")}`),this.els.categoryhelp&&(this.els.categoryhelp.textContent=t===0?"Select seats first \u2014 then pick the category they should sell under.":`Choose the category the ${t===1?"selected seat":`${t.toLocaleString()} selected seats`} should sell under. Applies immediately.`);let o=new Set(e.map(a=>a.label));this.els.rail?.querySelectorAll("[data-pick-category]").forEach(a=>{let l=a.dataset.pickCategory,r=this.categorySeats(l),c=r.filter(m=>o.has(m.label)).length,n=r.length>0&&c===r.length;a.classList.toggle("on",n),a.classList.toggle("partial",c>0&&!n),a.setAttribute("aria-pressed",String(n));let h=a.querySelector("[data-cat-count]");h&&(h.textContent=c?`${c.toLocaleString()}/${r.length.toLocaleString()}`:r.length.toLocaleString()),a.disabled=r.length===0}),this.els.rail?.querySelectorAll("[data-assign-category]").forEach(a=>{let l=a.dataset.assignCategory,r=[...this.labelToSeat.values()].filter(u=>u.categoryKey===l).length,c=s.get(l)??0,n=t>0&&c===t;a.disabled=t===0||n,a.classList.toggle("current",n);let h=a.querySelector("[data-cat-current]");h&&(h.textContent=`${r.toLocaleString()} ${r===1?"seat":"seats"} now`);let m=a.querySelector("[data-cat-action]");m&&(m.textContent=t===0?"Move here":n?"Already here":`Move ${(t-c).toLocaleString()} here`)})}renderTablesRail(){let e=this.tables(),t="Decide how each table sells for this event: every chair on its own, or the whole table as one booking. A table with held, booked, or blocked chairs is locked until that inventory is released, and channel allocations are kept.";if(this.inventoryModelVersion!==2){this.els.rail.innerHTML=`
558
+ </button>`).join("")}</div>`;let t=s=>this.els.rail.querySelector(`[data-ref="${s}"]`);this.els.categorynum=t("categorynum"),this.els.categorymeta=t("categorymeta"),this.els.categoryhelp=t("categoryhelp"),this.els.categoryclear=t("categoryclear"),t("categoryall").addEventListener("click",()=>this.selectAll()),this.els.categoryclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-pick-category]").forEach(s=>{s.addEventListener("click",()=>{let i=s.dataset.pickCategory,a=this.categorySeats(i),o=new Set(this.selectionLabels());a.length>0&&a.every(l=>o.has(l.label))?this.deselectCategories([i]):this.selectCategories([i])})}),this.els.rail.querySelectorAll("[data-assign-category]").forEach(s=>{s.addEventListener("click",()=>{this.setCategory(s.dataset.assignCategory)})}),this.paintCategorySelection(this.getSelection())}paintCategorySelection(e){if(!this.els.categorynum)return;let t=e.length;this.els.categorynum.textContent=t.toLocaleString(),this.els.categoryclear.disabled=t===0;let s=new Map;for(let o of e)s.set(o.categoryKey,(s.get(o.categoryKey)??0)+1);let i=o=>this.doc?.categories.find(l=>l.key===o)?.label??o;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([o,l])=>`${l.toLocaleString()} ${i(o)}`).join(", ")}`),this.els.categoryhelp&&(this.els.categoryhelp.textContent=t===0?"Select seats first \u2014 then pick the category they should sell under.":`Choose the category the ${t===1?"selected seat":`${t.toLocaleString()} selected seats`} should sell under. Applies immediately.`);let a=new Set(e.map(o=>o.label));this.els.rail?.querySelectorAll("[data-pick-category]").forEach(o=>{let l=o.dataset.pickCategory,r=this.categorySeats(l),c=r.filter(m=>a.has(m.label)).length,n=r.length>0&&c===r.length;o.classList.toggle("on",n),o.classList.toggle("partial",c>0&&!n),o.setAttribute("aria-pressed",String(n));let d=o.querySelector("[data-cat-count]");d&&(d.textContent=c?`${c.toLocaleString()}/${r.length.toLocaleString()}`:r.length.toLocaleString()),o.disabled=r.length===0}),this.els.rail?.querySelectorAll("[data-assign-category]").forEach(o=>{let l=o.dataset.assignCategory,r=[...this.labelToSeat.values()].filter(b=>b.categoryKey===l).length,c=s.get(l)??0,n=t>0&&c===t;o.disabled=t===0||n,o.classList.toggle("current",n);let d=o.querySelector("[data-cat-current]");d&&(d.textContent=`${r.toLocaleString()} ${r===1?"seat":"seats"} now`);let m=o.querySelector("[data-cat-action]");m&&(m.textContent=t===0?"Move here":n?"Already here":`Move ${(t-c).toLocaleString()} here`)})}renderTablesRail(){let e=this.tables(),t="Decide how each table sells for this event: every chair on its own, or the whole table as one booking. A table with held, booked, or blocked chairs is locked until that inventory is released, and channel allocations are kept.";if(this.inventoryModelVersion!==2){this.els.rail.innerHTML=`
435
559
  ${this.railHeader("Tables","event",t)}
436
560
  <div class="slm-empty">This event still uses the older inventory model, which cannot switch tables between per-chair and whole-table selling. Upgrade the event's inventory model to unlock this tool.</div>`;return}if(!e.length){this.els.rail.innerHTML=`
437
561
  ${this.railHeader("Tables","event",t)}
438
- <div class="slm-empty">This chart has no tables. Add tables in the designer and they will appear here.</div>`;return}let s=h=>h.variableOccupancy?"variable":h.bookAsWhole?"whole":"individual",i=h=>{let m=0,u=0,b=0;for(let[W,G]of this.labelToSeat){if(G.rowId!==h.id)continue;let L=this.status.get(W);L==="held"?m++:L==="booked"?u++:L==="blocked"&&b++}let f=[u&&`${u} booked`,m&&`${m} held`,b&&`${b} blocked`].filter(Boolean);return f.length?f.join(" \xB7 "):null},o=e.map(h=>({table:h,current:s(h),locked:i(h)})),a=o.filter(h=>h.current==="individual").length,l=o.filter(h=>h.current==="whole").length,r=o.length-a-l,c=[`${a.toLocaleString()} per chair`,`${l.toLocaleString()} whole table`,r?`${r.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),n=this.tableBookingSaving;this.els.rail.innerHTML=`
562
+ <div class="slm-empty">This chart has no tables. Add tables in the designer and they will appear here.</div>`;return}let s=d=>d.variableOccupancy?"variable":d.bookAsWhole?"whole":"individual",i=d=>{let m=0,b=0,g=0;for(let[u,f]of this.labelToSeat){if(f.rowId!==d.id)continue;let x=this.status.get(u);x==="held"?m++:x==="booked"?b++:x==="blocked"&&g++}let v=[b&&`${b} booked`,m&&`${m} held`,g&&`${g} blocked`].filter(Boolean);return v.length?v.join(" \xB7 "):null},a=e.map(d=>({table:d,current:s(d),locked:i(d)})),o=a.filter(d=>d.current==="individual").length,l=a.filter(d=>d.current==="whole").length,r=a.length-o-l,c=[`${o.toLocaleString()} per chair`,`${l.toLocaleString()} whole table`,r?`${r.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),n=this.tableBookingSaving;this.els.rail.innerHTML=`
439
563
  ${this.railHeader("Tables","event",t)}
440
- <div class="slm-tablesummary"><b>${o.length.toLocaleString()} ${o.length===1?"table":"tables"}</b><span>${p(c)}</span></div>
564
+ <div class="slm-tablesummary"><b>${a.length.toLocaleString()} ${a.length===1?"table":"tables"}</b><span>${p(c)}</span></div>
441
565
  <p class="slm-eyebrow" style="margin-top:12px">Set every table at once</p>
442
566
  <div class="slm-row">
443
567
  <button class="slm-btn ghost" data-table-all="individual"${n?" disabled":""} title="Sell every chair on its own">All per chair</button>
444
568
  <button class="slm-btn ghost" data-table-all="whole"${n?" disabled":""} title="Sell every table as one booking">All whole table</button>
445
569
  </div>
446
570
  <p class="slm-eyebrow" style="margin-top:12px">Or one table at a time</p>
447
- <div class="slm-tablelist">${o.map(({table:h,current:m,locked:u})=>`<div class="slm-tablerow${u?" locked":""}">
448
- <span class="slm-tablecopy"><b>${p(h.displayLabel??h.label)}</b><small>${h.seatCount.toLocaleString()} chairs${u?` \xB7 <span class="slm-tablelock">Locked: ${p(u)}</span>`:""}</small></span>
449
- <select class="slm-select" data-table-mode="${p(h.id)}" aria-label="Booking mode for ${p(h.displayLabel??h.label)}"
450
- ${n||u?"disabled":""} ${u?`title="Release the ${p(u)} chairs before changing how this table sells"`:""}>
571
+ <div class="slm-tablelist">${a.map(({table:d,current:m,locked:b})=>`<div class="slm-tablerow${b?" locked":""}">
572
+ <span class="slm-tablecopy"><b>${p(d.displayLabel??d.label)}</b><small>${d.seatCount.toLocaleString()} chairs${b?` \xB7 <span class="slm-tablelock">Locked: ${p(b)}</span>`:""}</small></span>
573
+ <select class="slm-select" data-table-mode="${p(d.id)}" aria-label="Booking mode for ${p(d.displayLabel??d.label)}"
574
+ ${n||b?"disabled":""} ${b?`title="Release the ${p(b)} chairs before changing how this table sells"`:""}>
451
575
  <option value="individual"${m==="individual"?" selected":""}>Per chair</option>
452
576
  <option value="whole"${m==="whole"?" selected":""}>Whole table</option>
453
577
  ${m==="variable"?'<option value="variable" selected>Flexible group</option>':""}
454
578
  </select>
455
579
  </div>`).join("")}</div>
456
- <p class="slm-note">Changes apply immediately to this event. Flexible group sizes (minimum and maximum guests) are set through the API, never guessed here.</p>`,this.els.rail.querySelectorAll("[data-table-all]").forEach(h=>{h.addEventListener("click",()=>{this.setTableBooking(o.filter(m=>!m.locked).map(m=>m.table.id),h.dataset.tableAll)})}),this.els.rail.querySelectorAll("[data-table-mode]").forEach(h=>{h.addEventListener("change",()=>{this.setTableBooking([h.dataset.tableMode],h.value)})})}renderInspectRail(e){let t=e[e.length-1];if(!t){this.els.rail.innerHTML=`
580
+ <p class="slm-note">Changes apply immediately to this event. Flexible group sizes (minimum and maximum guests) are set through the API, never guessed here.</p>`,this.els.rail.querySelectorAll("[data-table-all]").forEach(d=>{d.addEventListener("click",()=>{this.setTableBooking(a.filter(m=>!m.locked).map(m=>m.table.id),d.dataset.tableAll)})}),this.els.rail.querySelectorAll("[data-table-mode]").forEach(d=>{d.addEventListener("change",()=>{this.setTableBooking([d.dataset.tableMode],d.value)})})}renderInspectRail(e){let t=e[e.length-1];if(!t){this.els.rail.innerHTML=`
457
581
  ${this.railHeader("Inspect","read","Click one seat on the map to read its live status, category, section and booking context. Nothing changes in this view.")}
458
- <div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",i={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},o=this.sectionByObject.get(t.rowId)??g,a=this.sectionLabelById.get(o)??"Other seats",l=this.doc?.categories.find(m=>m.key===t.categoryKey),r=this.controlRoomSnapshot?.bookedValue.bySection.find(m=>m.sectionId===o),c=this.doc?.objects.find(m=>m.id===t.rowId),n=c?.type==="row"?{label:"Row",value:c.label}:c?.type==="table"?{label:"Table",value:c.label}:t.kind==="booth"?{label:"Type",value:"Booth"}:null,h=t.kind==="booth"?"Booth":"Seat";this.els.rail.innerHTML=`
459
- ${this.railHeader("Inspect","read",`Live status and section performance for this ${h.toLowerCase()}. Click another seat to switch.`)}
460
- <div class="slm-inspect-card">
461
- <div class="slm-inspect-label">${p(t.label)}</div>
462
- <div class="slm-inspect-grid">
463
- <div><span>Status</span><b>${i[s]}</b></div>
464
- <div><span>Section</span><b>${p(a)}</b></div>
465
- ${n?`<div><span>${n.label}</span><b>${p(n.value)}</b></div>`:""}
466
- <div><span>Category</span><b>${p(l?.label??t.categoryKey)}</b></div>
467
- <div><span>Booked in section</span><b>${r?`${r.booked} of ${r.total}`:"\u2014"}</b></div>
468
- <div><span>Section booked value</span><b>${r&&this.controlRoomSnapshot?y(r.bookedValue,this.controlRoomSnapshot.currency):"\u2014"}</b></div>
469
- </div>
470
- </div>`}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(A(this.availabilityRules)),this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(e){this.opts.onError?.(e)}}async withAuthRetry(e){try{return await e()}catch(t){if(t instanceof v&&t.status===401&&this.opts.onTokenRefresh&&!this.tokenRefreshInFlight)return await this.rotateToken(),e();throw t}}updateEffectiveAvailability(e,t){let s=!1;Array.isArray(e)&&(this.effectiveHidden=new Set(e.filter(i=>typeof i=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(i=>typeof i=="string")),s=!0),s&&(this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment())}applySectionCanvasTreatment(){this.renderer&&(this.mode==="sections"?(this.renderer.setDimmedSections([...this.effectiveHidden]),this.renderer.setClosedSections([...this.effectiveClosed])):this.mode==="filterSections"&&this.filteredSectionLabel?this.applyFilteredSectionCanvas():(this.renderer.setDimmedSections(null),this.renderer.setClosedSections(null)))}sectionRowsInput(){return{sectionsBase:this.sectionsBase,doc:this.doc,availabilityRules:this.availabilityRules,effectiveHidden:this.effectiveHidden,effectiveClosed:this.effectiveClosed}}renderSectionsRail(){let{rows:e,hiddenSections:t,closedSections:s}=w(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
582
+ <div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",i={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},a=this.sectionByObject.get(t.rowId)??y,o=this.sectionLabelById.get(a)??"Other seats",l=this.doc?.categories.find(c=>c.key===t.categoryKey);this.els.rail.innerHTML=`
583
+ <div class="slm-seat-heading"><h2>${p(t.label)}</h2><span data-seat-status>${i[s]}</span></div>
584
+ <p class="slm-note">${p(o)} \xB7 ${p(l?.label??t.categoryKey)}</p>
585
+ <div data-ref="seat-history"></div>`;let r=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new S(r,(c,n)=>this.withAuthRetry(()=>this.api.seatHistory(this.key,t.label,c,n)))}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(I(this.availabilityRules)),this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(e){this.opts.onError?.(e)}}async withAuthRetry(e){try{return await e()}catch(t){if(t instanceof k&&t.status===401&&this.opts.onTokenRefresh&&!this.tokenRefreshInFlight)return await this.rotateToken(),e();throw t}}updateEffectiveAvailability(e,t){let s=!1;Array.isArray(e)&&(this.effectiveHidden=new Set(e.filter(i=>typeof i=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(i=>typeof i=="string")),s=!0),s&&(this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment())}applySectionCanvasTreatment(){this.renderer&&(this.mode==="sections"?(this.renderer.setDimmedSections([...this.effectiveHidden]),this.renderer.setClosedSections([...this.effectiveClosed])):this.mode==="filterSections"&&this.filteredSectionLabel?this.applyFilteredSectionCanvas():(this.renderer.setDimmedSections(null),this.renderer.setClosedSections(null)))}sectionRowsInput(){return{sectionsBase:this.sectionsBase,doc:this.doc,availabilityRules:this.availabilityRules,effectiveHidden:this.effectiveHidden,effectiveClosed:this.effectiveClosed}}renderSectionsRail(){let{rows:e,hiddenSections:t,closedSections:s}=E(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
471
586
  ${this.railHeader("Sections","event","Draw sections or zones in the designer to schedule availability per area. This chart has none yet.")}
472
- <div class="slm-empty">No sections on this chart.</div>`;return}let i=[];t&&i.push(`${t} hidden`),s&&i.push(`${s} closed`);let o=i.length?i.join(" \xB7 "):"All sections open and on sale",a=t>0||s>0;this.els.rail.innerHTML=`
587
+ <div class="slm-empty">No sections on this chart.</div>`;return}let i=[];t&&i.push(`${t} hidden`),s&&i.push(`${s} closed`);let a=i.length?i.join(" \xB7 "):"All sections open and on sale",o=t>0||s>0;this.els.rail.innerHTML=`
473
588
  ${this.railHeader("Sections","event","Decide when each zone or section goes on sale for this event. 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.")}
474
- <div class="slm-availlist" data-ref="availlist">${e.map(l=>_(l,this.availabilitySaving)).join("")}</div>
589
+ <div class="slm-availlist" data-ref="availlist">${e.map(l=>Q(l,this.availabilitySaving)).join("")}</div>
475
590
  <div class="slm-availsummary">
476
- <span class="slm-availdot${a?" warn":""}"></span>
477
- <span>${p(o)}</span>
591
+ <span class="slm-availdot${o?" warn":""}"></span>
592
+ <span>${p(a)}</span>
478
593
  </div>
479
594
  <div class="slm-availcallout">
480
595
  <span class="slm-availstar" aria-hidden="true">\u2726</span>
481
596
  <p><b>Auto-reveal at % sold</b> is demand-triggered release: the balcony opens itself the moment the stalls cross the threshold \u2014 no one has to be watching.</p>
482
- </div>`,this.wireSectionRail(),this.applySectionCanvasTreatment()}wireSectionRail(){let e=this.els.rail;e&&(e.querySelectorAll("[data-avail-id]").forEach(t=>{t.addEventListener("change",()=>this.setSectionMode(t.dataset.availId,t.value))}),e.querySelectorAll("[data-avail-reveal]").forEach(t=>{t.addEventListener("change",()=>{let s=new Date(t.value).getTime();Number.isFinite(s)&&this.setSectionRulePatch(t.dataset.availReveal,{revealAt:s})})}),e.querySelectorAll("[data-avail-pct]").forEach(t=>{t.addEventListener("change",()=>{let s=Math.max(1,Math.min(100,Number(t.value)||0));this.setSectionRulePatch(t.dataset.availPct,{thresholdPct:s})})}))}setSectionMode(e,t){let s=w(this.sectionRowsInput()).rows.find(l=>l.id===e),i=s?.seatLabels??this.availabilityRules[e]?.labels??[],o={...this.availabilityRules},a=j(t,i,this.availabilityRules[e]);if(a?o[e]=a:delete o[e],s?.kind==="zone"&&this.sectionsBase)for(let l of this.sectionsBase.sections)l.zone===e&&delete o[l.id];this.persistAvailability(o)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let o=w(this.sectionRowsInput()).rows.find(a=>a.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:o}})}async persistAvailability(e){let t=this.availabilityRules;this.availabilityRules=e,this.availabilitySaving=!0,this.mode==="sections"&&this.renderSectionsRail();try{let s=await this.withAuthRetry(()=>this.api.setAvailability(this.key,e));this.availabilityRules=s.rules,this.effectiveHidden=new Set(s.hidden),this.effectiveClosed=new Set(A(s.rules)),this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(s){this.availabilityRules=t,this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.toastErr("Couldn't update availability. Try again."),this.opts.onError?.(s)}}paintLegend(e){this.els.legend&&(this.els.legend.innerHTML=V.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
483
- <span class="slm-leglabel">${t.label}</span><span class="slm-legcount">${e[t.key].toLocaleString()}</span></div>`).join(""))}paintFeed(){if(!this.els.feed)return;if(!this.feed.length){this.els.feed.innerHTML=`<div class="slm-empty">No activity yet \u2014 it'll stream in live.</div>`;return}let e=Date.now(),t={free:"#6e7bff",held:"#f4b740",booked:"#22a06b",blocked:"#8b94ac"};this.els.feed.innerHTML=this.feed.map(s=>{let i=s.count>1?` +${s.count-1}`:"",o=s.sectionLabels??[],a=o.length===1?o[0]:o.length>1?`${o.length} sections`:"";return`<button type="button" class="slm-feedrow" data-feed-id="${p(s.id)}" title="Locate this activity on the map">
484
- <span class="slm-feeddot" style="background:${t[s.status]}"></span>
485
- <span class="slm-feedtext">${a?`<span class="slm-feedsection">${p(a)}</span>`:""}${s.count===1?"Seat":"Seats"} <b>${p(s.label)}${i}</b> ${p(s.verb)}</span>
486
- <span class="slm-feedmeta"><span class="slm-feedtime">${E(s.at,e)}</span><span class="slm-feedlocate">Locate</span></span>
487
- </button>`}).join("")}renderBlockRail(){let t=(this.doc?.categories??[]).map(n=>`<button class="slm-chip" type="button" data-cat="${p(n.key)}" aria-pressed="false">
597
+ </div>`,this.wireSectionRail(),this.applySectionCanvasTreatment()}wireSectionRail(){let e=this.els.rail;e&&(e.querySelectorAll("[data-avail-id]").forEach(t=>{t.addEventListener("click",()=>this.setSectionMode(t.dataset.availId,t.dataset.availValue))}),e.querySelectorAll("[data-avail-picker]").forEach(t=>{t.querySelector("summary").addEventListener("click",s=>{this.availabilitySaving&&s.preventDefault(),e.querySelectorAll("[data-avail-picker]").forEach(i=>{i!==t&&(i.open=!1)})}),t.addEventListener("focusout",s=>{t.contains(s.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",s=>{if(s.key==="Escape"&&(t.open=!1,t.querySelector("summary").focus(),s.preventDefault()),s.key==="ArrowDown"||s.key==="ArrowUp"){if(this.availabilitySaving)return;s.preventDefault(),t.open=!0;let i=[...t.querySelectorAll("button")],a=i.indexOf(document.activeElement);i[(a+(s.key==="ArrowDown"?1:i.length-1)+i.length)%i.length]?.focus()}})}),e.querySelectorAll("[data-avail-reveal]").forEach(t=>{t.addEventListener("change",()=>{let s=new Date(t.value).getTime();Number.isFinite(s)&&this.setSectionRulePatch(t.dataset.availReveal,{revealAt:s})})}),e.querySelectorAll("[data-avail-pct]").forEach(t=>{t.addEventListener("change",()=>{let s=Math.max(1,Math.min(100,Number(t.value)||0));this.setSectionRulePatch(t.dataset.availPct,{thresholdPct:s})})}))}setSectionMode(e,t){let s=E(this.sectionRowsInput()).rows.find(l=>l.id===e),i=s?.seatLabels??this.availabilityRules[e]?.labels??[],a={...this.availabilityRules},o=U(t,i,this.availabilityRules[e]);if(o?a[e]=o:delete a[e],s?.kind==="zone"&&this.sectionsBase)for(let l of this.sectionsBase.sections)l.zone===e&&delete a[l.id];this.persistAvailability(a)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let a=E(this.sectionRowsInput()).rows.find(o=>o.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:a}})}async persistAvailability(e){let t=this.availabilityRules;this.availabilityRules=e,this.availabilitySaving=!0,this.mode==="sections"&&this.renderSectionsRail();try{let s=await this.withAuthRetry(()=>this.api.setAvailability(this.key,e));this.availabilityRules=s.rules,this.effectiveHidden=new Set(s.hidden),this.effectiveClosed=new Set(I(s.rules)),this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(s){this.availabilityRules=t,this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.toastErr("Couldn't update availability. Try again."),this.opts.onError?.(s)}}paintLegend(e){this.els.legend&&(this.els.legend.innerHTML=G.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
598
+ <span class="slm-leglabel">${t.label}</span><span class="slm-legcount">${e[t.key].toLocaleString()}</span></div>`).join(""))}paintFeed(){this.activityPanel?.update(this.feed)}renderBlockRail(){let t=(this.doc?.categories??[]).map(n=>`<button class="slm-chip" type="button" data-cat="${p(n.key)}" aria-pressed="false">
488
599
  <span class="dot" style="background:${p(n.color??"#6e7bff")}"></span>
489
600
  <span>${p(n.label??n.key)}</span>
490
601
  <span class="slm-chipcount" data-cat-count>0</span>
@@ -492,12 +603,14 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
492
603
  </button>`).join(""),s=this.sectionOptions.length?`<div class="slm-field"><label>Select a whole section</label>
493
604
  <select class="slm-select" data-ref="section"><option value="">Choose a section\u2026</option>
494
605
  ${this.sectionOptions.map(n=>`<option value="${p(n.id)}">${p(n.label)}</option>`).join("")}</select></div>`:"",i=this.sectionOptions.map(n=>`<option value="${p(n.id)}">${p(n.label)}</option>`).join("");this.els.rail.innerHTML=`
495
- ${this.railHeader("Block","event","Take seats off sale for this event, or put blocked seats back. Drag a box on the map, press \u2318A for all, or pick a whole category or section below. Booked and held seats are never touched.")}
606
+ <div class="slm-monitor-tabs" role="tablist" aria-label="Blocking tools"><button role="tab" data-block-tab="edit" aria-selected="${!this.blockBrowse}">Block seats</button><button role="tab" data-block-tab="browse" aria-selected="${this.blockBrowse}">Find blocked</button></div>
607
+ <p class="slm-note">\u25A7 Blocked \xB7 \u25CF Green: booked \xB7 \u25CF Gold: held</p>
496
608
  <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>
497
609
  <div class="slm-row">
498
610
  <button class="slm-btn" data-ref="doblock" disabled>Block</button>
499
611
  <button class="slm-btn ghost" data-ref="dounblock" disabled>Put back on sale</button>
500
612
  </div>
613
+ <div data-block-editor ${this.blockBrowse?"hidden":""}>
501
614
  <div class="slm-row">
502
615
  <button class="slm-btn ghost" data-ref="selall">Select all</button>
503
616
  <button class="slm-btn ghost" data-ref="clearsel">Clear</button>
@@ -511,7 +624,8 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
511
624
  <input type="datetime-local" class="slm-input" data-ref="release" />
512
625
  <p class="slm-note" data-ref="releasenote">Leave empty to block permanently.</p>
513
626
  </div>
514
- <section class="slm-blocked" aria-labelledby="slm-blocked-title">
627
+ </div>
628
+ <section ${this.blockBrowse?"":"hidden"} class="slm-blocked" aria-labelledby="slm-blocked-title">
515
629
  <div class="slm-blockedhead">
516
630
  <p class="slm-eyebrow" id="slm-blocked-title">Blocked inventory</p>
517
631
  <span class="slm-blockedtotal"><b data-ref="blockedcount">0</b> out of sale</span>
@@ -529,12 +643,9 @@ import{c as T,d as M,f as H}from"./chunk-RZ2VKZ44.js";import{A as ye,C as Se,a a
529
643
  </div>
530
644
  <div class="slm-blockedlist" data-ref="blockedlist"></div>
531
645
  </section>
532
- <div class="slm-field">
646
+ <details ${this.blockBrowse?"":"hidden"}><summary>More actions</summary><div class="slm-field">
533
647
  <button class="slm-btn ghost" data-ref="markall" style="width:100%" disabled>Put all blocked seats on sale</button>
534
648
  <p class="slm-note slm-allnote" data-ref="markallnote">For a full reset only. You will be asked to confirm.</p>
535
- </div>
536
- `;let o=n=>this.els.rail.querySelector(`[data-ref="${n}"]`);this.els.selnum=o("selnum"),this.els.doblock=o("doblock"),this.els.dounblock=o("dounblock"),this.els.selmeta=o("selmeta"),this.els.blockedcount=o("blockedcount"),this.els.blockedshowing=o("blockedshowing"),this.els.blockedlist=o("blockedlist"),this.els.selblocked=o("selblocked"),this.els.markall=o("markall"),this.els.markallnote=o("markallnote"),o("doblock").addEventListener("click",()=>{this.block()}),o("dounblock").addEventListener("click",()=>{this.unblock()}),o("selall").addEventListener("click",()=>this.selectAll()),o("clearsel").addEventListener("click",()=>this.clearSelection()),o("markall").addEventListener("click",()=>this.confirmUnblockAll()),this.els.rail.querySelectorAll("[data-cat]").forEach(n=>n.addEventListener("click",()=>this.toggleCategory(n.dataset.cat)));let a=this.els.rail.querySelector('[data-ref="section"]');a?.addEventListener("change",()=>{a.value&&(this.selectSection(a.value),a.value="")});let l=o("blockedsearch"),r=o("blockedsection");l.value=this.blockedQuery,r.value=this.blockedSection,l.addEventListener("input",()=>{this.blockedQuery=l.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),r.addEventListener("change",()=>{this.blockedSection=r.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),o("selblocked").addEventListener("click",()=>{this.toggleLabels(this.filteredBlockedSeats().map(n=>n.label))}),o("blockedlist").addEventListener("click",n=>{let h=n.target,m=h.closest("[data-blocked-label]");m?.dataset.blockedLabel?this.toggleLabels([m.dataset.blockedLabel]):h.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let c=o("release");c.addEventListener("change",()=>{let n=c.value?new Date(c.value).getTime():NaN;this.releaseAt=Number.isFinite(n)&&n>Date.now()?n:null;let h=o("releasenote");h.textContent=this.releaseAt?`New blocks auto-release ${new Date(this.releaseAt).toLocaleString()}.`:c.value?"Pick a time in the future.":"Leave empty to block permanently."}),this.paintSelBar(this.getSelection())}toggleCategory(e){let t=[];for(let[s,i]of this.labelToSeat.entries())i.categoryKey===e&&this.isBlockSelectable(s)&&t.push(s);this.toggleLabels(t)}toggleLabels(e){if(!this.renderer)return;let t=e.filter(o=>this.labelToSeat.has(o)&&this.isBlockSelectable(o));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(o=>s.has(o))){let o=t.map(a=>this.labelToId.get(a)).filter(a=>!!a);this.renderer.deselect(o)}else this.renderer.selectByLabels(t);this.syncSelection()}isBlockSelectable(e){let t=this.status.get(e)??"free";return t==="free"||t==="blocked"}paintSelBar(e){if(!this.els.selnum)return;this.els.selnum.textContent=e.length.toLocaleString();let t=e.filter(a=>(this.status.get(a.label)??"free")==="free").length,s=e.filter(a=>this.status.get(a.label)==="blocked").length;this.els.selmeta.textContent=e.length?`${t.toLocaleString()} available \xB7 ${s.toLocaleString()} blocked`:"selected";let i=this.els.doblock,o=this.els.dounblock;i.disabled=t===0,o.disabled=s===0,i.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",o.textContent=s?`Put ${s.toLocaleString()} on sale`:"Put back on sale",this.paintCategoryControls(e),this.paintBlockedInventory()}paintCategoryControls(e){let t=new Set(e.map(s=>s.label));this.els.rail?.querySelectorAll("[data-cat]").forEach(s=>{let i=s.dataset.cat,o=[];for(let[n,h]of this.labelToSeat.entries())h.categoryKey===i&&this.isBlockSelectable(n)&&o.push(n);let a=o.filter(n=>t.has(n)).length,l=o.length>0&&a===o.length,r=a>0&&!l;s.disabled=o.length===0,s.classList.toggle("on",l),s.classList.toggle("partial",r),s.setAttribute("aria-pressed",l?"true":r?"mixed":"false"),s.setAttribute("title",l?`Remove all ${o.length.toLocaleString()} seats in this category from the selection`:r?`Select the remaining ${(o.length-a).toLocaleString()} seats in this category`:`Select all ${o.length.toLocaleString()} seats in this category`);let c=s.querySelector("[data-cat-count]");c&&(c.textContent=a?`${a.toLocaleString()}/${o.length.toLocaleString()}`:o.length.toLocaleString())})}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,i]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let o=this.sectionByObject.get(i.rowId)??g;if(!(this.blockedSection&&o!==this.blockedSection)){if(e){let a=this.doc?.categories.find(h=>h.key===i.categoryKey)?.label??i.categoryKey,l=this.sectionLabelById.get(o)??"Other seats",r=this.doc?.objects.find(h=>h.id===i.rowId),c=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${a} ${l} ${c}`.toLocaleLowerCase().includes(e))continue}t.push(i)}}return t.sort((s,i)=>s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))}paintBlockedInventory(){if(!this.els.blockedlist)return;let e=[...this.status.entries()].filter(([,n])=>n==="blocked").length,t=this.filteredBlockedSeats(),s=t.slice(0,this.blockedResultLimit),i=new Set(this.selectionLabels()),o=t.filter(n=>i.has(n.label)).length,a=t.length>0&&o===t.length;this.els.blockedcount.textContent=e.toLocaleString(),this.els.blockedshowing.textContent=t.length?`Showing ${s.length.toLocaleString()} of ${t.length.toLocaleString()}`:e?"No matches":"No blocked seats";let l=this.els.selblocked;l.disabled=t.length===0,l.textContent=a?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`,this.els.blockedlist.innerHTML=s.length?s.map(n=>{let h=this.sectionByObject.get(n.rowId)??g,m=this.sectionLabelById.get(h)??"Other seats",u=this.doc?.categories.find(f=>f.key===n.categoryKey)?.label??n.categoryKey,b=i.has(n.label);return`<button type="button" class="slm-blockeditem${b?" on":""}" data-blocked-label="${p(n.label)}" aria-pressed="${b}">
537
- <span class="slm-blockedcheck" aria-hidden="true">\u2713</span>
538
- <span class="slm-blockedcopy"><span class="slm-blockedlabel">${p(n.label)}</span>
539
- <span class="slm-blockedmeta">${p(m)} \xB7 ${p(u)}</span></span>
540
- </button>`}).join("")+(t.length>s.length?'<button type="button" class="slm-blockedmore" data-blocked-more>Show 100 more</button>':""):`<div class="slm-blockedempty">${e?"No blocked seats match this search or section.":"No seats are blocked. Newly blocked seats will appear here."}</div>`;let r=this.els.markall,c=r.dataset.confirm==="true";r.disabled=e===0,r.textContent=c?`Confirm: put all ${e.toLocaleString()} on sale`:`Put all ${e.toLocaleString()} blocked seats on sale`}confirmUnblockAll(){let e=this.els.markall;if(!(!e||e.disabled)){if(e.dataset.confirm==="true"){this.resetUnblockAllConfirm(),this.unblockAll();return}e.dataset.confirm="true",e.classList.add("danger"),this.els.markallnote.textContent="This changes every blocked seat. Click the red button again to confirm.",this.paintBlockedInventory(),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=setTimeout(()=>this.resetUnblockAllConfirm(),6e3)}}resetUnblockAllConfirm(){this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=null;let e=this.els.markall;e&&(delete e.dataset.confirm,e.classList.remove("danger"),this.els.markallnote&&(this.els.markallnote.textContent="For a full reset only. You will be asked to confirm."),this.paintBlockedInventory())}done(e,t,s){if(this.toastOk(s),t.length){let i=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;i&&this.paintSpatialActivity(i)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(i=>this.opts.onError?.(i)),this.opts.onActionComplete?.({action:e,labels:t,count:t.length})}toastOk(e){this.toast(e,"ok")}toastErr(e){this.toast(e,"err")}toast(e,t){let s=this.els.toast;s&&(s.textContent=e,s.className=`slm-toast on ${t}`,this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{s.className="slm-toast"},3200))}fail(e){this.opts.onError?.(e),this.els.rail&&(this.els.rail.innerHTML=`<div class="slm-empty">Couldn't load this event. Check the event key and token.</div>`)}};export{pe as ACCESS_LINK_DEFAULTS,Se as ChannelsMode,C as ManageApi,v as ManageApiError,Z as PUBLIC_CHANNEL_ID,Y as PUBLIC_CHANNEL_NAME,$ as SeatManager,ce as accessIntentDescription,re as accessIntentLabel,ne as accessLine,me as accessLinkBadge,fe as accessLinkErrorCopy,ue as accessLinkIsLive,be as accessLinkPolicyLines,ae as bucketRows,ye as bucketRowsHtml,ge as dropReviewRows,de as intentForbidsCopy,he as intentSwitchBlockedCopy,Q as isPublicChannelId,X as markerLetter,ee as markerOf,ie as mutationCount,oe as needsMoveConfirmation,se as planAssignment,le as retryAfterCopy,te as selectionSources,ve as stateBadge,J as suggestMarker};
649
+ </div></details>
650
+ `,this.els.rail.querySelectorAll("[data-block-tab]").forEach(n=>n.addEventListener("click",()=>{this.blockBrowse=n.dataset.blockTab==="browse",this.renderBlockRail()}));let a=n=>this.els.rail.querySelector(`[data-ref="${n}"]`);this.els.selnum=a("selnum"),this.els.doblock=a("doblock"),this.els.dounblock=a("dounblock"),this.els.selmeta=a("selmeta"),this.els.blockedcount=a("blockedcount"),this.els.blockedshowing=a("blockedshowing"),this.els.blockedlist=a("blockedlist"),this.els.selblocked=a("selblocked"),this.els.markall=a("markall"),this.els.markallnote=a("markallnote"),a("doblock").addEventListener("click",()=>{this.block()}),a("dounblock").addEventListener("click",()=>{this.unblock()}),a("selall").addEventListener("click",()=>this.selectAll()),a("clearsel").addEventListener("click",()=>this.clearSelection()),a("markall").addEventListener("click",()=>this.confirmUnblockAll()),this.els.rail.querySelectorAll("[data-cat]").forEach(n=>n.addEventListener("click",()=>this.toggleCategory(n.dataset.cat)));let o=this.els.rail.querySelector('[data-ref="section"]');o?.addEventListener("change",()=>{o.value&&(this.selectSection(o.value),o.value="")});let l=a("blockedsearch"),r=a("blockedsection");l.value=this.blockedQuery,r.value=this.blockedSection,l.addEventListener("input",()=>{this.blockedQuery=l.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),r.addEventListener("change",()=>{this.blockedSection=r.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),a("selblocked").addEventListener("click",()=>{this.toggleLabels(this.filteredBlockedSeats().map(n=>n.label))}),a("blockedlist").addEventListener("click",n=>{let d=n.target,m=d.closest("[data-block-seat-find]");if(m?.dataset.blockSeatFind){let u=this.labelToSeat.get(m.dataset.blockSeatFind);u&&(this.setFollowLive(!1),this.focusActivitySeats([u.label],this.sectionByObject.get(u.rowId)??y));return}let b=d.closest("[data-block-locate]"),g=d.closest("[data-block-group]");if(b||g){let u=b?.dataset.blockLocate??g?.dataset.blockGroup,f=this.filteredBlockedSeats().filter(x=>x.rowId===u);b&&f.length&&(this.setFollowLive(!1),this.focusActivitySeats(f.map(x=>x.label),this.sectionByObject.get(f[0].rowId)??y)),g&&this.toggleLabels(f.map(x=>x.label));return}let v=d.closest("[data-blocked-label]");v?.dataset.blockedLabel?this.toggleLabels([v.dataset.blockedLabel]):d.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let c=a("release");c.addEventListener("change",()=>{let n=c.value?new Date(c.value).getTime():NaN;this.releaseAt=Number.isFinite(n)&&n>Date.now()?n:null;let d=a("releasenote");d.textContent=this.releaseAt?`New blocks auto-release ${new Date(this.releaseAt).toLocaleString()}.`:c.value?"Pick a time in the future.":"Leave empty to block permanently."}),this.paintSelBar(this.getSelection())}toggleCategory(e){let t=[];for(let[s,i]of this.labelToSeat.entries())i.categoryKey===e&&this.isBlockSelectable(s)&&t.push(s);this.toggleLabels(t)}toggleLabels(e){if(!this.renderer)return;let t=e.filter(a=>this.labelToSeat.has(a)&&this.isBlockSelectable(a));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(a=>s.has(a))){let a=t.map(o=>this.labelToId.get(o)).filter(o=>!!o);this.renderer.deselect(a)}else this.renderer.selectByLabels(t);this.syncSelection()}isBlockSelectable(e){let t=this.status.get(e)??"free";return t==="free"||t==="blocked"}paintSelBar(e){if(!this.els.selnum)return;this.els.selnum.textContent=e.length.toLocaleString();let t=e.filter(o=>(this.status.get(o.label)??"free")==="free").length,s=e.filter(o=>this.status.get(o.label)==="blocked").length;this.els.selmeta.textContent=e.length?`${t.toLocaleString()} available \xB7 ${s.toLocaleString()} blocked`:"selected";let i=this.els.doblock,a=this.els.dounblock;i.disabled=t===0,a.disabled=s===0,i.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",a.textContent=s?`Put ${s.toLocaleString()} on sale`:"Put back on sale",this.paintCategoryControls(e),this.paintBlockedInventory()}paintCategoryControls(e){let t=new Set(e.map(s=>s.label));this.els.rail?.querySelectorAll("[data-cat]").forEach(s=>{let i=s.dataset.cat,a=[];for(let[n,d]of this.labelToSeat.entries())d.categoryKey===i&&this.isBlockSelectable(n)&&a.push(n);let o=a.filter(n=>t.has(n)).length,l=a.length>0&&o===a.length,r=o>0&&!l;s.disabled=a.length===0,s.classList.toggle("on",l),s.classList.toggle("partial",r),s.setAttribute("aria-pressed",l?"true":r?"mixed":"false"),s.setAttribute("title",l?`Remove all ${a.length.toLocaleString()} seats in this category from the selection`:r?`Select the remaining ${(a.length-o).toLocaleString()} seats in this category`:`Select all ${a.length.toLocaleString()} seats in this category`);let c=s.querySelector("[data-cat-count]");c&&(c.textContent=o?`${o.toLocaleString()}/${a.length.toLocaleString()}`:a.length.toLocaleString())})}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,i]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let a=this.sectionByObject.get(i.rowId)??y;if(!(this.blockedSection&&a!==this.blockedSection)){if(e){let o=this.doc?.categories.find(d=>d.key===i.categoryKey)?.label??i.categoryKey,l=this.sectionLabelById.get(a)??"Other seats",r=this.doc?.objects.find(d=>d.id===i.rowId),c=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${o} ${l} ${c}`.toLocaleLowerCase().includes(e))continue}t.push(i)}}return t.sort((s,i)=>s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))}paintBlockedInventory(){if(!this.els.blockedlist)return;let e=[...this.status.entries()].filter(([,d])=>d==="blocked").length,t=this.filteredBlockedSeats(),s=t.slice(0,this.blockedResultLimit),i=new Set(this.selectionLabels()),a=t.filter(d=>i.has(d.label)).length,o=t.length>0&&a===t.length;this.els.blockedcount.textContent=e.toLocaleString(),this.els.blockedshowing.textContent=t.length?`Showing ${s.length.toLocaleString()} of ${t.length.toLocaleString()}`:e?"No matches":"No blocked seats";let l=this.els.selblocked;l.disabled=t.length===0,l.textContent=o?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`;let r=new Map;for(let d of t){let m=r.get(d.rowId)??[];m.push(d),r.set(d.rowId,m)}this.els.blockedshowing.textContent=`${t.length.toLocaleString()} seats \xB7 ${r.size} rows`,this.els.blockedlist.innerHTML=[...r.entries()].slice(0,this.blockedResultLimit).map(([d,m])=>{let b=this.sectionByObject.get(d)??y,g=this.sectionLabelById.get(b)??"Other seats",v=this.doc?.objects.find(f=>f.id===d),u=v&&"label"in v?v.label:m[0].label;return`<div class="slm-block-group"><div class="slm-block-grouphead"><button type="button" data-block-locate="${p(d)}" title="Show this row and nearby seats on the map"><b>${p(u)}</b><small>${p(g)} \xB7 ${m.length} blocked</small></button><button type="button" data-block-group="${p(d)}">Select row</button></div>
651
+ <details><summary>Choose seats</summary>${m.map(f=>`<div class="slm-block-seatline"><button type="button" class="slm-blockeditem${i.has(f.label)?" on":""}" data-blocked-label="${p(f.label)}" aria-pressed="${i.has(f.label)}"><span class="slm-blockedcheck" aria-hidden="true">\u2713</span><span>${p(f.label)}</span></button><button type="button" data-block-seat-find="${p(f.label)}" aria-label="Show ${p(f.label)} and nearby seats">Show</button></div>`).join("")}</details></div>`}).join("")||'<div class="slm-blockedempty">No blocked seats match.</div>',r.size>this.blockedResultLimit&&(this.els.blockedlist.innerHTML+="<button data-blocked-more>Show more rows</button>");let c=this.els.markall,n=c.dataset.confirm==="true";c.disabled=e===0,c.textContent=n?`Confirm: put all ${e.toLocaleString()} on sale`:`Put all ${e.toLocaleString()} blocked seats on sale`}confirmUnblockAll(){let e=this.els.markall;if(!(!e||e.disabled)){if(e.dataset.confirm==="true"){this.resetUnblockAllConfirm(),this.unblockAll();return}e.dataset.confirm="true",e.classList.add("danger"),this.els.markallnote.textContent="This changes every blocked seat. Click the red button again to confirm.",this.paintBlockedInventory(),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=setTimeout(()=>this.resetUnblockAllConfirm(),6e3)}}resetUnblockAllConfirm(){this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=null;let e=this.els.markall;e&&(delete e.dataset.confirm,e.classList.remove("danger"),this.els.markallnote&&(this.els.markallnote.textContent="For a full reset only. You will be asked to confirm."),this.paintBlockedInventory())}done(e,t,s){if(this.toastOk(s),t.length){let i=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;i&&this.paintSpatialActivity(i)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(i=>this.opts.onError?.(i)),this.opts.onActionComplete?.({action:e,labels:t,count:t.length})}toastOk(e){this.toast(e,"ok")}toastErr(e){this.toast(e,"err")}toast(e,t){let s=this.els.toast;s&&(s.textContent=e,s.className=`slm-toast on ${t}`,this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{s.className="slm-toast"},3200))}fail(e){this.opts.onError?.(e),this.els.rail&&(this.els.rail.innerHTML=`<div class="slm-empty">Couldn't load this event. Check the event key and token.</div>`)}};export{xe as ACCESS_LINK_DEFAULTS,Ee as ChannelsMode,H as ManageApi,k as ManageApiError,ie as PUBLIC_CHANNEL_ID,ae as PUBLIC_CHANNEL_NAME,z as SeatManager,ve as accessIntentDescription,ge as accessIntentLabel,be as accessLine,ke as accessLinkBadge,Le as accessLinkErrorCopy,Se as accessLinkIsLive,we as accessLinkPolicyLines,me as bucketRows,Ce as bucketRowsHtml,Te as dropReviewRows,fe as intentForbidsCopy,ye as intentSwitchBlockedCopy,oe as isPublicChannelId,le as markerLetter,re as markerOf,he as mutationCount,pe as needsMoveConfirmation,de as planAssignment,ue as retryAfterCopy,ce as selectionSources,Me as stateBadge,ne as suggestMarker};