@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.cjs CHANGED
@@ -1,22 +1,22 @@
1
- "use strict";var Re=Object.defineProperty;var Lt=Object.getOwnPropertyDescriptor;var Ct=Object.getOwnPropertyNames;var $t=Object.prototype.hasOwnProperty;var V=(l,e,t)=>()=>{if(t)throw t[0];try{return l&&(e=l(l=0)),e}catch(s){throw t=[s],s}};var qe=(l,e)=>{for(var t in e)Re(l,t,{get:e[t],enumerable:!0})},Rt=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ct(e))!$t.call(l,n)&&n!==t&&Re(l,n,{get:()=>e[n],enumerable:!(s=Lt(e,n))||s.enumerable});return l};var Tt=l=>Rt(Re({},"__esModule",{value:!0}),l);async function je(l){let t=(l.headers.get("content-type")??"").includes("application/json")?await l.json().catch(()=>null):null;if(!l.ok){let s=t;throw new y(l.status,s?.error??`request_failed_${l.status}`,s?.code,s?.conflicts,s?.details,typeof s?.message=="string"?s.message:void 0)}return t}function R(l){return l&&typeof l=="object"?l:{}}function ie(l,e,t=0){return typeof l=="number"&&Number.isFinite(l)?l:typeof e=="number"&&Number.isFinite(e)?e:t}function Ne(l,e){return l===null?null:typeof l=="number"&&Number.isFinite(l)?l:l!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function Ve(l){let e=R(l),t=ie(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function At(l){let e=R(l),t=R(e.report),s=Array.isArray(t.byCategory)?t.byCategory.map(i=>{let a=R(i),o=ie(a.bookedValue,a.bookedRevenue);return{...a,bookedValue:o,bookedRevenue:o}}):[],n=Array.isArray(t.bySection)?t.bySection.map(Ve):void 0;return{...e,report:{...t,byCategory:s,...n?{bySection:n}:{}}}}function Mt(l){let e=R(l),t=R(e.bookedValue),s=R(e.revenue),n=Object.keys(t).length?t:s,i=Array.isArray(t.bySection)?t.bySection:Array.isArray(s.bySection)?s.bySection:[],a={...n,gross:ie(t.gross,s.gross),bySection:i.map(Ve)},o=R(e.velocity),r=Array.isArray(o.bySection)?o.bySection.map(d=>{let c=R(d),p=ie(c.bookedValue,c.grossRevenue);return{...c,bookedValue:p,grossRevenue:p}}):[];return{...e,bookedValue:a,revenue:a,velocity:{...o,bySection:r}}}function Et(l){let e=R(l),t=R(e.report),s=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,n=Array.isArray(t.rows)?t.rows.map(o=>{let r=R(o),d=R(r.attribution),c=Ne(d.bookedValue,d.revenue);return{...r,attribution:{...d,bookedValue:c,revenue:c}}}):[],i=R(t.totals),a=Ne(i.bookedValue,i.revenue);return{...e,report:{...t,includesBookedValue:s,includesRevenue:s,rows:n,totals:{...i,bookedValue:a,revenue:a}}}}function Te(l){let e=R(l),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var y,U,ae=V(()=>{"use strict";y=class extends Error{constructor(e,t,s,n,i,a){super(t),this.name="ManageApiError",this.status=e,this.code=s,this.conflicts=n,this.details=i,this.serverMessage=a}};U=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let s=t.method??"GET",n={Authorization:`Bearer ${this.token}`},i;return t.body!==void 0&&(n["Content-Type"]="application/json",i=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:s,headers:n,body:i,credentials:"omit"}).then(a=>je(a))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await je(t),t.blob()}chart(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/chart`)}asset(e,t){return/^[a-zA-Z0-9._-]+$/.test(t)?this.authBlob(`/v1/events/${encodeURIComponent(e)}/assets/${encodeURIComponent(t)}`):Promise.reject(new y(404,"not_found","not_found"))}objects(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/objects`)}subscribeTicket(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/subscribe-tickets`,{method:"POST"})}socketUrl(e){return`${this.base.replace(/^http/,"ws")}/pub/events/${encodeURIComponent(e)}/subscribe?surface=manager`}block(e,t,s={}){let n={labels:t};return typeof s.releaseAt=="number"&&(n.releaseAt=s.releaseAt),s.reason&&(n.reason=s.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:n})}unblock(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock`,{method:"POST",body:{labels:t}})}unblockAll(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock-all`,{method:"POST"})}unbook(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:s}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:s}})}setTableBooking(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:s,...n}})}bookings(e,t={}){let s=new URLSearchParams;t.q&&s.set("q",t.q),t.state&&s.set("state",t.state),t.cursor&&s.set("cursor",t.cursor),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${n?`?${n}`:""}`)}booking(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings/${encodeURIComponent(t)}`)}listBookings(e,t={}){return this.bookings(e,t)}retrieveBooking(e,t){return this.booking(e,t)}availability(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`)}setAvailability(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`,{method:"POST",body:{rules:t}})}channels(e,t={}){let s=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${s}`)}channelAllocation(e,t={}){let s=new URLSearchParams;t.afterLabel&&s.set("afterLabel",t.afterLabel),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${n?`?${n}`:""}`)}channelAudit(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${n?`?${n}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:s}})}updateChannelPricing(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:s,expectedPricingVersion:n}})}setChannelPaused(e,t,s){let n=s?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${n}`,{method:"POST",body:{}})}archiveChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:s}})}applyChannelAssignment(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/assignments`,{method:"POST",body:{targetChannelId:t.targetChannelId||null,labels:t.labels,assignmentVersion:t.assignmentVersion}})}channelPreview(e,t,s={}){let n=new URLSearchParams;t.length&&n.set("channelIds",t.join(",")),s.includePublic!=null&&n.set("includePublic",s.includePublic?"1":"0");let i=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${i?`?${i}`:""}`)}setChannelAccessIntent(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:s,...n.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...n.reason?{reason:n.reason}:{}}})}createAccessLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:s})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}/rotate`,{method:"POST",body:{endActiveSessions:n}})}revokeAccessLink(e,t,s,n=!1){let i=n?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}${i}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(At)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(Mt)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(Et)}createChannelReportLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:s}).then(n=>{let i=R(n);return{...i,link:Te(i.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(s=>{let n=R(s);return{links:Array.isArray(n.links)?n.links.map(Te):[]}})}revokeChannelReportLink(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(s)}`,{method:"DELETE"}).then(n=>{let i=R(n);return{...i,link:Te(i.link)}})}log(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${n?`?${n}`:""}`)}async reportCsv(e){let t=await fetch(`${this.base}/v1/events/${encodeURIComponent(e)}/report.csv`,{headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});if(!t.ok)throw new y(t.status,`request_failed_${t.status}`);return t.blob()}}});function B(l){return l==null||l===""||l===C}function z(l,e){let t=(l??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function J(l,e){let t=new Set([...e].map(i=>z(i,"")).filter(Boolean)),s=z(l,"");return{letter:lt.includes(s)&&!t.has(s)?s:[...lt].find(i=>!t.has(i))??(s||"X"),color:he[t.size%he.length]}}function pe(l,e=0){return B(l.id)?{letter:z(l.marker,"P"),color:l.color||Ot}:{letter:z(l.marker||l.name,"?"),color:l.color||he[e%he.length]}}function ue(l,e,t){let s=new Map;for(let a of l){let o=Be(e.get(a));s.set(o,(s.get(o)??0)+1)}let n=[{id:C,name:t?.publicSale?.name??T},...(t?.channels??[]).map(a=>({id:a.id,name:a.name}))],i=[];for(let a of n){let o=s.get(a.id);o&&i.push({channelId:a.id,name:a.name,count:o}),s.delete(a.id)}for(let[a,o]of s)i.push({channelId:a,name:B(a)?T:"Another channel",count:o});return i}function Be(l){return B(l)?C:l}function He(l){return{count:l.length,labels:l.slice(0,rt),truncated:l.length>rt}}function me(l){let{labels:e,allocation:t,statusOf:s,nameOf:n}=l,i=Be(l.targetChannelId),a=new Set,o=0,r=0,d=new Map,c=[],p=[],m=[];for(let g of e){if(a.has(g))continue;a.add(g);let b=s(g);if(!b){m.push(g);continue}let f=Be(t.get(g));if(f===i){r+=1;continue}if(b==="held"){c.push(g);continue}if(b==="booked"){p.push(g);continue}f===C?o+=1:d.set(f,(d.get(f)??0)+1)}let v=[...d.entries()].map(([g,b])=>({channelId:g,name:n(g),count:b}));return{changedFromPublic:{count:o},movedFromOtherChannel:{count:v.reduce((g,b)=>g+b.count,0),channels:v},alreadyInTarget:{count:r},skippedHeld:He(c),skippedBooked:He(p),notFound:He(m)}}function K(l){return l.changedFromPublic.count+l.movedFromOtherChannel.count}function be(l){return l.movedFromOtherChannel.count>0}function ge(l,e){let t=[];l.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:l.changedFromPublic.count,text:`${l.changedFromPublic.count.toLocaleString()} from ${T}`});for(let s of l.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:s.count,text:`${s.count.toLocaleString()} moved out of ${s.name??"another channel"}`,why:"needs this confirmation"});return l.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:l.alreadyInTarget.count,text:`${l.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),l.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:l.skippedHeld.count,text:`${l.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:de(l.skippedHeld)}),l.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:l.skippedBooked.count,text:`${l.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:de(l.skippedBooked)}),l.notFound.count&&t.push({kind:"skip",icon:"?",count:l.notFound.count,text:`${l.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:de(l.notFound)}),t}function de(l){if(!l.labels.length)return;let e=l.labels.slice(0,4).join(", ");return l.truncated||l.labels.length>4?`${e}\u2026`:e}function ve(l){let e=l?.retryAfterMs??(l?.latestHoldExpiresAt?Math.max(0,l.latestHoldExpiresAt-Date.now()):0);if(!e)return"in a moment";let t=Math.ceil(e/6e4);return t<=1?"in about a minute":`in about ${t} minutes`}function fe(l){if(!l||!l.intent)return"\u2014";let e=l.intent==="server"?"Website integration":l.intent==="hosted_link"?"Buyer link":l.intent==="internal"?"Your staff sell these":"Protected reserve",t=l.hasActiveGrants?"in use now":l.lastMintAt?`last used ${new Date(l.lastMintAt).toLocaleDateString()}`:null,s=l.detail??t;return s?`${e} \xB7 ${s}`:e}function F(l){return l==="internal"?"Sell through your own staff":l==="server"?"Integrate a website or app":l==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function ye(l){switch(l){case"internal":return"Only your own box office can sell these seats, through your secret key. Buyer links and website integrations are refused.";case"server":return"Your website's backend mints each buyer a short-lived session for these seats. Buyer links are refused; the code lives on the Embed page.";case"hosted_link":return"SeatLayer makes a link you send to a named group. They open it and buy only these seats. No other route can sell them.";default:return"Nobody can buy these seats. Every way of letting a buyer in \u2014 a buyer link, your website, even your own staff \u2014 is refused while this is the route. The seats stay out of public sale."}}function zt(l){return l==="hosted_link"?"hosted_link":l==="server"?"server":l==="staff"?"internal":null}function Y(l){let e=De(l?.accessIntent),t=zt(l?.route),s=`This channel is set to "${F(e)}"`;return t?`${s}, so it cannot do that. Switch it to "${F(t)}" first.`:`${s}, so it cannot do that. Choose a different route for this channel first.`}function De(l){return l==="internal"||l==="server"||l==="hosted_link"||l==="none"?l:"none"}function ce(l,e,t){return`${l.toLocaleString()} ${l===1?e:t}`}function ke(l){let e=Math.max(0,l?.liveAccessLinks??0),t=Math.max(0,l?.activeSessions??0),s=De(l?.from),n=De(l?.to),a=`${[e?ce(e,"buyer link is live","buyer links are live"):null,t?ce(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${F(s)}". Moving it to "${F(n)}" changes what happens to them.`,o=[];return e&&o.push(`${ce(e,"buyer link closes","buyer links close")} immediately. Anyone who has not opened it yet never will \u2014 send a new link if you still need one.`),t&&o.push(`${ce(t,"buyer who is already in a checkout keeps","buyers who are already in a checkout keep")} their seats and can finish paying. Nobody is thrown out. No new buyers come in this way, so the old route empties on its own within 12 hours.`),{headline:a,consequences:o}}function we(l){switch(l.status??l.state){case"active":return{text:"Active",kind:"active"};case"expired":return{text:"Expired",kind:"archived"};case"exhausted":return{text:"All used",kind:"paused"};case"rotated":return{text:"Replaced",kind:"archived"};default:return{text:"Revoked",kind:"archived"}}}function te(l){return l.state==="active"&&l.status==="active"}function Ft(l){return Number.isFinite(l)?new Date(l).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function se(l){return[{k:"Expires",v:Ft(l.expiresAt)},{k:"Redemptions",v:`${l.redemptions.toLocaleString()} of ${l.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${l.maxQuantity.toLocaleString()} seat${l.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:l.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function q(l){let e=l?.serverMessage?.trim();switch(l?.code){case"invalid_expiry":case"invalid_max_redemptions":case"invalid_max_quantity":case"invalid_session_ttl":case"invalid_label":return e||"That setting is outside what a hosted link allows. Adjust it and try again.";case"too_many_access_links":return e||"This channel already has as many live links as it can hold. Revoke one before creating another.";case"access_link_not_active":return"That link is no longer active, so it cannot be rotated or revoked.";case"channel_unavailable":return"This channel is paused or archived, so it cannot let new buyers in. Resume it first.";case"channel_access_intent_forbids":return Y(l?.details);case"end_active_sessions_required":return"Choose what happens to the buyers who already came in through this link.";case"not_found":return"That link is no longer here. Refresh and try again.";default:return l?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function ct(l){return(l?.channels??[]).map(e=>({kind:"skip",icon:"\u26A0",count:e.count,text:`${e.count.toLocaleString()} would leave ${e.name??"a channel"}`,why:"the new chart no longer has these seats",peek:e.labels?.length?de({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function xe(l){return l==="builtin"?"Built-in":l==="active"?"Active":l==="paused"?"Paused":"Archived"}var C,T,he,Ot,lt,rt,ee,Se=V(()=>{"use strict";C="public",T="Public sale";he=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],Ot="#f4b740",lt="ABCDEFGHJKLMNPQRSTUVWXYZ";rt=12;ee={maxRedemptions:100,maxQuantity:4}});function W(l){return l.map((e,t)=>`
1
+ "use strict";var Me=Object.defineProperty;var It=Object.getOwnPropertyDescriptor;var Ht=Object.getOwnPropertyNames;var Pt=Object.prototype.hasOwnProperty;var j=(l,e,t)=>()=>{if(t)throw t[0];try{return l&&(e=l(l=0)),e}catch(s){throw t=[s],s}};var Ue=(l,e)=>{for(var t in e)Me(l,t,{get:e[t],enumerable:!0})},Bt=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ht(e))!Pt.call(l,n)&&n!==t&&Me(l,n,{get:()=>e[n],enumerable:!(s=It(e,n))||s.enumerable});return l};var Dt=l=>Bt(Me({},"__esModule",{value:!0}),l);function ne(l){l.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dataset.themed="true";let t=document.createElement("details");t.className="slm-themed-picker";let s=document.createElement("summary"),n=document.createElement("div");n.className="slm-themed-options";let i=e.getAttribute("aria-label")||Array.from(e.labels??[]).map(o=>o.textContent).join(" ")||"Choose option";s.setAttribute("aria-label",i.trim()),t.append(s,n),e.after(t),e.hidden=!0;let a=()=>{s.textContent=e.selectedOptions[0]?.textContent??"Choose\u2026",s.setAttribute("aria-disabled",String(e.disabled)),n.replaceChildren(...Array.from(e.options).map(o=>{let r=document.createElement("button");return r.type="button",r.textContent=o.textContent,r.setAttribute("aria-label",o.textContent??""),r.disabled=e.disabled||o.disabled,r.setAttribute("aria-pressed",String(o.selected)),r.onclick=()=>{e.value=o.value,t.open=!1,a(),s.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),a()},r}))};a(),e.addEventListener("change",a),s.onclick=o=>{if(e.disabled){o.preventDefault();return}a(),l.querySelectorAll(".slm-themed-picker").forEach(r=>{r!==t&&(r.open=!1)})},t.addEventListener("focusout",o=>{t.contains(o.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",o=>{if(o.key==="Escape"&&(o.preventDefault(),o.stopPropagation(),t.open=!1,s.focus()),o.key==="ArrowDown"||o.key==="ArrowUp"){if(e.disabled)return;o.preventDefault(),t.open=!0;let r=Array.from(n.querySelectorAll("button:not(:disabled)")),c=r.indexOf(document.activeElement);r[(c+(o.key==="ArrowDown"?1:r.length-1)+r.length)%r.length]?.focus()}})})}var Ie=j(()=>{"use strict"});async function We(l){let t=(l.headers.get("content-type")??"").includes("application/json")?await l.json().catch(()=>null):null;if(!l.ok){let s=t;throw new y(l.status,s?.error??`request_failed_${l.status}`,s?.code,s?.conflicts,s?.details,typeof s?.message=="string"?s.message:void 0)}return t}function E(l){return l&&typeof l=="object"?l:{}}function le(l,e,t=0){return typeof l=="number"&&Number.isFinite(l)?l:typeof e=="number"&&Number.isFinite(e)?e:t}function Xe(l,e){return l===null?null:typeof l=="number"&&Number.isFinite(l)?l:l!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function Ge(l){let e=E(l),t=le(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function zt(l){let e=E(l),t=E(e.report),s=Array.isArray(t.byCategory)?t.byCategory.map(i=>{let a=E(i),o=le(a.bookedValue,a.bookedRevenue);return{...a,bookedValue:o,bookedRevenue:o}}):[],n=Array.isArray(t.bySection)?t.bySection.map(Ge):void 0;return{...e,report:{...t,byCategory:s,...n?{bySection:n}:{}}}}function Ft(l){let e=E(l),t=E(e.bookedValue),s=E(e.revenue),n=Object.keys(t).length?t:s,i=Array.isArray(t.bySection)?t.bySection:Array.isArray(s.bySection)?s.bySection:[],a={...n,gross:le(t.gross,s.gross),bySection:i.map(Ge)},o=E(e.velocity),r=Array.isArray(o.bySection)?o.bySection.map(c=>{let d=E(c),h=le(d.bookedValue,d.grossRevenue);return{...d,bookedValue:h,grossRevenue:h}}):[];return{...e,bookedValue:a,revenue:a,velocity:{...o,bySection:r}}}function qt(l){let e=E(l),t=E(e.report),s=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,n=Array.isArray(t.rows)?t.rows.map(o=>{let r=E(o),c=E(r.attribution),d=Xe(c.bookedValue,c.revenue);return{...r,attribution:{...c,bookedValue:d,revenue:d}}}):[],i=E(t.totals),a=Xe(i.bookedValue,i.revenue);return{...e,report:{...t,includesBookedValue:s,includesRevenue:s,rows:n,totals:{...i,bookedValue:a,revenue:a}}}}function He(l){let e=E(l),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var y,U,re=j(()=>{"use strict";y=class extends Error{constructor(e,t,s,n,i,a){super(t),this.name="ManageApiError",this.status=e,this.code=s,this.conflicts=n,this.details=i,this.serverMessage=a}};U=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let s=t.method??"GET",n={Authorization:`Bearer ${this.token}`},i;return t.body!==void 0&&(n["Content-Type"]="application/json",i=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:s,headers:n,body:i,credentials:"omit"}).then(a=>We(a))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await We(t),t.blob()}chart(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/chart`)}asset(e,t){return/^[a-zA-Z0-9._-]+$/.test(t)?this.authBlob(`/v1/events/${encodeURIComponent(e)}/assets/${encodeURIComponent(t)}`):Promise.reject(new y(404,"not_found","not_found"))}objects(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/objects`)}subscribeTicket(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/subscribe-tickets`,{method:"POST"})}socketUrl(e){return`${this.base.replace(/^http/,"ws")}/pub/events/${encodeURIComponent(e)}/subscribe?surface=manager`}block(e,t,s={}){let n={labels:t};return typeof s.releaseAt=="number"&&(n.releaseAt=s.releaseAt),s.reason&&(n.reason=s.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:n})}unblock(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock`,{method:"POST",body:{labels:t}})}unblockAll(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock-all`,{method:"POST"})}unbook(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:s}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:s}})}setTableBooking(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:s,...n}})}bookings(e,t={}){let s=new URLSearchParams;t.q&&s.set("q",t.q),t.state&&s.set("state",t.state),t.cursor&&s.set("cursor",t.cursor),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${n?`?${n}`:""}`)}booking(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings/${encodeURIComponent(t)}`)}listBookings(e,t={}){return this.bookings(e,t)}retrieveBooking(e,t){return this.booking(e,t)}availability(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`)}setAvailability(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`,{method:"POST",body:{rules:t}})}channels(e,t={}){let s=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${s}`)}channelAllocation(e,t={}){let s=new URLSearchParams;t.afterLabel&&s.set("afterLabel",t.afterLabel),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${n?`?${n}`:""}`)}channelAudit(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${n?`?${n}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:s}})}updateChannelPricing(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:s,expectedPricingVersion:n}})}setChannelPaused(e,t,s){let n=s?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${n}`,{method:"POST",body:{}})}archiveChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:s}})}applyChannelAssignment(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/assignments`,{method:"POST",body:{targetChannelId:t.targetChannelId||null,labels:t.labels,assignmentVersion:t.assignmentVersion}})}channelPreview(e,t,s={}){let n=new URLSearchParams;t.length&&n.set("channelIds",t.join(",")),s.includePublic!=null&&n.set("includePublic",s.includePublic?"1":"0");let i=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${i?`?${i}`:""}`)}setChannelAccessIntent(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:s,...n.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...n.reason?{reason:n.reason}:{}}})}createAccessLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:s})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}/rotate`,{method:"POST",body:{endActiveSessions:n}})}revokeAccessLink(e,t,s,n=!1){let i=n?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}${i}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(zt)}seatHistory(e,t,s,n){let i=new URLSearchParams({label:t});return s&&i.set("before",String(s)),n&&i.set("action",n),this.auth(`/v1/events/${encodeURIComponent(e)}/seat-history?${i}`)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(Ft)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(qt)}createChannelReportLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:s}).then(n=>{let i=E(n);return{...i,link:He(i.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(s=>{let n=E(s);return{links:Array.isArray(n.links)?n.links.map(He):[]}})}revokeChannelReportLink(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(s)}`,{method:"DELETE"}).then(n=>{let i=E(n);return{...i,link:He(i.link)}})}log(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${n?`?${n}`:""}`)}async reportCsv(e){let t=await fetch(`${this.base}/v1/events/${encodeURIComponent(e)}/report.csv`,{headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});if(!t.ok)throw new y(t.status,`request_failed_${t.status}`);return t.blob()}}});function B(l){return l==null||l===""||l===T}function z(l,e){let t=(l??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function Q(l,e){let t=new Set([...e].map(i=>z(i,"")).filter(Boolean)),s=z(l,"");return{letter:ut.includes(s)&&!t.has(s)?s:[...ut].find(i=>!t.has(i))??(s||"X"),color:be[t.size%be.length]}}function ge(l,e=0){return B(l.id)?{letter:z(l.marker,"P"),color:l.color||Kt}:{letter:z(l.marker||l.name,"?"),color:l.color||be[e%be.length]}}function ve(l,e,t){let s=new Map;for(let a of l){let o=Fe(e.get(a));s.set(o,(s.get(o)??0)+1)}let n=[{id:T,name:t?.publicSale?.name??A},...(t?.channels??[]).map(a=>({id:a.id,name:a.name}))],i=[];for(let a of n){let o=s.get(a.id);o&&i.push({channelId:a.id,name:a.name,count:o}),s.delete(a.id)}for(let[a,o]of s)i.push({channelId:a,name:B(a)?A:"Another channel",count:o});return i}function Fe(l){return B(l)?T:l}function ze(l){return{count:l.length,labels:l.slice(0,bt),truncated:l.length>bt}}function fe(l){let{labels:e,allocation:t,statusOf:s,nameOf:n}=l,i=Fe(l.targetChannelId),a=new Set,o=0,r=0,c=new Map,d=[],h=[],u=[];for(let v of e){if(a.has(v))continue;a.add(v);let g=s(v);if(!g){u.push(v);continue}let m=Fe(t.get(v));if(m===i){r+=1;continue}if(g==="held"){d.push(v);continue}if(g==="booked"){h.push(v);continue}m===T?o+=1:c.set(m,(c.get(m)??0)+1)}let f=[...c.entries()].map(([v,g])=>({channelId:v,name:n(v),count:g}));return{changedFromPublic:{count:o},movedFromOtherChannel:{count:f.reduce((v,g)=>v+g.count,0),channels:f},alreadyInTarget:{count:r},skippedHeld:ze(d),skippedBooked:ze(h),notFound:ze(u)}}function K(l){return l.changedFromPublic.count+l.movedFromOtherChannel.count}function ye(l){return l.movedFromOtherChannel.count>0}function ke(l,e){let t=[];l.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:l.changedFromPublic.count,text:`${l.changedFromPublic.count.toLocaleString()} from ${A}`});for(let s of l.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:s.count,text:`${s.count.toLocaleString()} moved out of ${s.name??"another channel"}`,why:"needs this confirmation"});return l.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:l.alreadyInTarget.count,text:`${l.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),l.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:l.skippedHeld.count,text:`${l.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:ue(l.skippedHeld)}),l.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:l.skippedBooked.count,text:`${l.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:ue(l.skippedBooked)}),l.notFound.count&&t.push({kind:"skip",icon:"?",count:l.notFound.count,text:`${l.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:ue(l.notFound)}),t}function ue(l){if(!l.labels.length)return;let e=l.labels.slice(0,4).join(", ");return l.truncated||l.labels.length>4?`${e}\u2026`:e}function xe(l){let e=l?.retryAfterMs??(l?.latestHoldExpiresAt?Math.max(0,l.latestHoldExpiresAt-Date.now()):0);if(!e)return"in a moment";let t=Math.ceil(e/6e4);return t<=1?"in about a minute":`in about ${t} minutes`}function we(l){if(!l||!l.intent)return"\u2014";let e=l.intent==="server"?"Website integration":l.intent==="hosted_link"?"Buyer link":l.intent==="internal"?"Your staff sell these":"Protected reserve",t=l.hasActiveGrants?"in use now":l.lastMintAt?`last used ${new Date(l.lastMintAt).toLocaleDateString()}`:null,s=l.detail??t;return s?`${e} \xB7 ${s}`:e}function F(l){return l==="internal"?"Sell through your own staff":l==="server"?"Integrate a website or app":l==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function Se(l){switch(l){case"internal":return"Only your own box office can sell these seats, through your secret key. Buyer links and website integrations are refused.";case"server":return"Your website's backend mints each buyer a short-lived session for these seats. Buyer links are refused; the code lives on the Embed page.";case"hosted_link":return"SeatLayer makes a link you send to a named group. They open it and buy only these seats. No other route can sell them.";default:return"Nobody can buy these seats. Every way of letting a buyer in \u2014 a buyer link, your website, even your own staff \u2014 is refused while this is the route. The seats stay out of public sale."}}function Yt(l){return l==="hosted_link"?"hosted_link":l==="server"?"server":l==="staff"?"internal":null}function Y(l){let e=qe(l?.accessIntent),t=Yt(l?.route),s=`This channel is set to "${F(e)}"`;return t?`${s}, so it cannot do that. Switch it to "${F(t)}" first.`:`${s}, so it cannot do that. Choose a different route for this channel first.`}function qe(l){return l==="internal"||l==="server"||l==="hosted_link"||l==="none"?l:"none"}function me(l,e,t){return`${l.toLocaleString()} ${l===1?e:t}`}function Le(l){let e=Math.max(0,l?.liveAccessLinks??0),t=Math.max(0,l?.activeSessions??0),s=qe(l?.from),n=qe(l?.to),a=`${[e?me(e,"buyer link is live","buyer links are live"):null,t?me(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${F(s)}". Moving it to "${F(n)}" changes what happens to them.`,o=[];return e&&o.push(`${me(e,"buyer link closes","buyer links close")} immediately. Anyone who has not opened it yet never will \u2014 send a new link if you still need one.`),t&&o.push(`${me(t,"buyer who is already in a checkout keeps","buyers who are already in a checkout keep")} their seats and can finish paying. Nobody is thrown out. No new buyers come in this way, so the old route empties on its own within 12 hours.`),{headline:a,consequences:o}}function Ce(l){switch(l.status??l.state){case"active":return{text:"Active",kind:"active"};case"expired":return{text:"Expired",kind:"archived"};case"exhausted":return{text:"All used",kind:"paused"};case"rotated":return{text:"Replaced",kind:"archived"};default:return{text:"Revoked",kind:"archived"}}}function ee(l){return l.state==="active"&&l.status==="active"}function Wt(l){return Number.isFinite(l)?new Date(l).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function te(l){return[{k:"Expires",v:Wt(l.expiresAt)},{k:"Redemptions",v:`${l.redemptions.toLocaleString()} of ${l.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${l.maxQuantity.toLocaleString()} seat${l.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:l.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function N(l){let e=l?.serverMessage?.trim();switch(l?.code){case"invalid_expiry":case"invalid_max_redemptions":case"invalid_max_quantity":case"invalid_session_ttl":case"invalid_label":return e||"That setting is outside what a hosted link allows. Adjust it and try again.";case"too_many_access_links":return e||"This channel already has as many live links as it can hold. Revoke one before creating another.";case"access_link_not_active":return"That link is no longer active, so it cannot be rotated or revoked.";case"channel_unavailable":return"This channel is paused or archived, so it cannot let new buyers in. Resume it first.";case"channel_access_intent_forbids":return Y(l?.details);case"end_active_sessions_required":return"Choose what happens to the buyers who already came in through this link.";case"not_found":return"That link is no longer here. Refresh and try again.";default:return l?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function gt(l){return(l?.channels??[]).map(e=>({kind:"skip",icon:"\u26A0",count:e.count,text:`${e.count.toLocaleString()} would leave ${e.name??"a channel"}`,why:"the new chart no longer has these seats",peek:e.labels?.length?ue({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function Te(l){return l==="builtin"?"Built-in":l==="active"?"Active":l==="paused"?"Paused":"Archived"}var T,A,be,Kt,ut,bt,J,Re=j(()=>{"use strict";T="public",A="Public sale";be=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],Kt="#f4b740",ut="ABCDEFGHJKLMNPQRSTUVWXYZ";bt=12;J={maxRedemptions:100,maxQuantity:4}});function W(l){return l.map((e,t)=>`
2
2
  <div class="slm-ch-bucket" style="animation-delay:${Math.min(t,4)*30}ms">
3
- <span class="ico ${e.kind}" aria-hidden="true">${h(e.icon)}</span>
4
- <span><b>${e.count.toLocaleString()}</b> ${h(e.text.replace(/^[\d,.\s]+/,""))}
5
- ${e.why?`<span class="why">\u2014 ${h(e.why)}</span>`:""}</span>
6
- ${e.peek?`<span class="peek">${h(e.peek)}</span>`:"<span></span>"}
7
- </div>`).join("")}function h(l){return String(l??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function ht(l){return new Date(l-new Date(l).getTimezoneOffset()*6e4).toISOString().slice(0,16)}function Oe(l,e){let t=l.querySelector(e)?.value.trim()??"",s=Number(t);return t!==""&&Number.isInteger(s)?s:null}function ze(l){let e=l.querySelector("[data-ch-lk-url]");if(e)try{let t=document.createRange();t.selectNodeContents(e);let s=window.getSelection();s?.removeAllRanges(),s?.addRange(t)}catch{}}var dt,Le=V(()=>{"use strict";dt=`
3
+ <span class="ico ${e.kind}" aria-hidden="true">${p(e.icon)}</span>
4
+ <span><b>${e.count.toLocaleString()}</b> ${p(e.text.replace(/^[\d,.\s]+/,""))}
5
+ ${e.why?`<span class="why">\u2014 ${p(e.why)}</span>`:""}</span>
6
+ ${e.peek?`<span class="peek">${p(e.peek)}</span>`:"<span></span>"}
7
+ </div>`).join("")}function p(l){return String(l??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function ft(l){return new Date(l-new Date(l).getTimezoneOffset()*6e4).toISOString().slice(0,16)}function je(l,e){let t=l.querySelector(e)?.value.trim()??"",s=Number(t);return t!==""&&Number.isInteger(s)?s:null}function Ne(l){let e=l.querySelector("[data-ch-lk-url]");if(e)try{let t=document.createRange();t.selectNodeContents(e);let s=window.getSelection();s?.removeAllRanges(),s?.addRange(t)}catch{}}var vt,$e=j(()=>{"use strict";vt=`
8
8
  <p class="slm-eyebrow" style="margin-top:18px">On your website</p>
9
9
  <p class="slm-hint">There is nothing more to set up on this screen. Your own server mints a short-lived buyer
10
10
  access session for this channel with the SeatLayer server SDK and hands it to the widget. A channel name
11
11
  on its own never grants access.</p>
12
12
  <p class="slm-note"><a class="slm-linkbtn" href="https://docs.seatlayer.io/server-api/channels"
13
- target="_blank" rel="noreferrer noopener">Read the website integration guide \u2192</a></p>`});function pt(l){let e=l.canvas,t=l.layer;if(!e||!t)return;let s=l.host.mapLayer.getBoundingClientRect(),n=Math.max(1,Math.round(s.width)),i=Math.max(1,Math.round(s.height)),a=typeof devicePixelRatio=="number"?Math.min(3,Math.max(1,devicePixelRatio)):1;(e.width!==n*a||e.height!==i*a)&&(e.width=n*a,e.height=i*a);let o=l.resolveCtx();if(!o)return;o.setTransform(a,0,0,a,0,0),o.clearRect(0,0,n,i);let r=l.host.isSeatDetail(),d=Math.max(3,l.host.seatPixelSize()),c=d/2,p=l.view==="preview"?l.previewProjection:null,m=p?new Set(p.available===!1?[]:p.eligible??[]):null,v=new Map,g=!r&&l.host.sections().length>1?new Map:null,b=l.view==="preview"&&r&&d<=15?new Map:null;for(let f of l.host.seats()){let P=l.host.statusOf(f.label)??"free",H=l.allocation.get(f.label)??C;if(H!==C){let x=v.get(H)??{x:0,y:0,n:0};x.x+=f.x,x.y+=f.y,x.n+=1,v.set(H,x)}if(!r){let x=l.host.sectionOfLabel(f.label),w=x?l.host.worldToScreen({x:f.x,y:f.y}):null;if(g&&x&&w){let k=g.get(x.id)??{label:x.label,minX:w.x,minY:w.y,maxX:w.x,maxY:w.y};k.minX=Math.min(k.minX,w.x),k.minY=Math.min(k.minY,w.y),k.maxX=Math.max(k.maxX,w.x),k.maxY=Math.max(k.maxY,w.y),g.set(x.id,k)}continue}if(P!=="free")continue;let _=null,M=null;if(l.view==="preview"?m?.has(f.label)?(_=qt,M=jt):(_=Nt,M=Vt):H!==C&&(_=l.markerFor(H).color,M=Ut),!_)continue;let S=l.host.worldToScreen({x:f.x,y:f.y});if(S&&!(S.x<-d||S.y<-d||S.x>n+d||S.y>i+d)){if(b){let x=l.host.sectionOfLabel(f.label);if(x){let w=b.get(x.id)??{label:x.label,minX:S.x,minY:S.y,maxX:S.x,maxY:S.y};w.minX=Math.min(w.minX,S.x),w.minY=Math.min(w.minY,S.y),w.maxX=Math.max(w.maxX,S.x),w.maxY=Math.max(w.maxY,S.y),b.set(x.id,w)}}if(o.fillStyle=_,l.view==="preview"||H!==C){let x=Math.max(2,c+Math.min(1.5,c*.06));o.globalAlpha=1,o.beginPath(),o.arc(S.x,S.y,x,0,Math.PI*2),o.fill(),o.strokeStyle=M??_,o.lineWidth=l.view==="preview"?Math.max(1,Math.min(1.75,d*.13)):Math.max(1,Math.min(1.5,d*.1)),o.stroke(),l.view==="preview"&&m?.has(f.label)&&d>=22&&Kt(o,f.label,S.x,S.y,x)}else o.globalAlpha=.85,o.fillRect(S.x-c,S.y-c,d,d)}}o.globalAlpha=1,b&&Wt(o,b),Yt(g,l),Gt(v,l,o)}function Kt(l,e,t,s,n){let i=n*1.55,a=Math.min(13,Math.max(7,n*.55)),o=6;for(;a>=o&&(l.font=`800 ${a}px var(--slm-font, system-ui, sans-serif)`,!(l.measureText(e).width<=i));)a-=.5;a<o||(l.fillStyle="#ffffff",l.textAlign="center",l.textBaseline="middle",l.fillText(e,t,s))}function Yt(l,e){let t=e.layer;if(t&&(t.querySelectorAll(".slm-ch-section-target").forEach(s=>s.remove()),!!l))for(let[s,n]of l){let i=n.maxX-n.minX,a=n.maxY-n.minY;if(i<20||a<20)continue;let o=document.createElement("button");o.type="button",o.className="slm-ch-section-target",o.style.left=`${n.minX-8}px`,o.style.top=`${n.minY-8}px`,o.style.width=`${i+16}px`,o.style.height=`${a+16}px`,o.setAttribute("aria-label",`Open ${n.label} seats`),o.addEventListener("click",()=>e.onSectionTargetClick(s)),t.appendChild(o)}}function Wt(l,e){for(let t of e.values()){let s=t.maxX-t.minX,n=t.maxY-t.minY;if(s<52||n<26)continue;let i=(t.minX+t.maxX)/2,a=(t.minY+t.maxY)/2,o=Math.max(11,Math.min(15,n*.16));l.font=`800 ${o}px var(--slm-font, system-ui, sans-serif)`;let r=Math.min(s-8,l.measureText(t.label).width+18),d=o+10;l.fillStyle="rgba(11, 16, 28, .88)",l.fillRect(i-r/2,a-d/2,r,d),l.fillStyle="#f8fafc",l.textAlign="center",l.textBaseline="middle",l.fillText(t.label,i,a)}}function Gt(l,e,t){let s=e.layer;if(!s||(s.querySelectorAll(".slm-ch-flag").forEach(i=>i.remove()),e.view==="preview"))return;let n=[...l.entries()].sort((i,a)=>a[1].n-i[1].n).slice(0,_t);for(let[i,a]of n){let o=e.list?.channels.find(p=>p.id===i);if(!o)continue;let r=e.host.worldToScreen({x:a.x/a.n,y:a.y/a.n});if(!r)continue;let d=e.markerFor(i),c=document.createElement("span");c.className="slm-ch-flag",c.style.left=`${r.x}px`,c.style.top=`${r.y}px`,c.innerHTML=`<span class="mk" style="background:${h(d.color)}">${h(d.letter)}</span>${h(o.name)}${o.state==="paused"?" \xB7 Paused":""}`,s.appendChild(c)}}var _t,qt,jt,Nt,Vt,Ut,ut=V(()=>{"use strict";Se();Le();_t=8,qt="#6e7bff",jt="#b9c0ff",Nt="#303846",Vt="#4b5669",Ut="#101723"});var mt,bt=V(()=>{"use strict";mt=`
13
+ target="_blank" rel="noreferrer noopener">Read the website integration guide \u2192</a></p>`});function yt(l){let e=l.canvas,t=l.layer;if(!e||!t)return;let s=l.host.mapLayer.getBoundingClientRect(),n=Math.max(1,Math.round(s.width)),i=Math.max(1,Math.round(s.height)),a=typeof devicePixelRatio=="number"?Math.min(3,Math.max(1,devicePixelRatio)):1;(e.width!==n*a||e.height!==i*a)&&(e.width=n*a,e.height=i*a);let o=l.resolveCtx();if(!o)return;o.setTransform(a,0,0,a,0,0),o.clearRect(0,0,n,i);let r=l.host.isSeatDetail(),c=Math.max(3,l.host.seatPixelSize()),d=c/2,h=l.view==="preview"?l.previewProjection:null,u=h?new Set(h.available===!1?[]:h.eligible??[]):null,f=new Map,v=!r&&l.host.sections().length>1?new Map:null,g=l.view==="preview"&&r&&c<=15?new Map:null;for(let m of l.host.seats()){let k=l.host.statusOf(m.label)??"free",R=l.allocation.get(m.label)??T;if(R!==T){let L=f.get(R)??{x:0,y:0,n:0};L.x+=m.x,L.y+=m.y,L.n+=1,f.set(R,L)}if(!r){let L=l.host.sectionOfLabel(m.label),w=L?l.host.worldToScreen({x:m.x,y:m.y}):null;if(v&&L&&w){let x=v.get(L.id)??{label:L.label,minX:w.x,minY:w.y,maxX:w.x,maxY:w.y};x.minX=Math.min(x.minX,w.x),x.minY=Math.min(x.minY,w.y),x.maxX=Math.max(x.maxX,w.x),x.maxY=Math.max(x.maxY,w.y),v.set(L.id,x)}continue}if(k!=="free")continue;let q=null,I=null;if(l.view==="preview"?u?.has(m.label)?(q=Gt,I=Zt):(q=Qt,I=Jt):R!==T&&(q=l.markerFor(R).color,I=es),!q)continue;let C=l.host.worldToScreen({x:m.x,y:m.y});if(C&&!(C.x<-c||C.y<-c||C.x>n+c||C.y>i+c)){if(g){let L=l.host.sectionOfLabel(m.label);if(L){let w=g.get(L.id)??{label:L.label,minX:C.x,minY:C.y,maxX:C.x,maxY:C.y};w.minX=Math.min(w.minX,C.x),w.minY=Math.min(w.minY,C.y),w.maxX=Math.max(w.maxX,C.x),w.maxY=Math.max(w.maxY,C.y),g.set(L.id,w)}}if(o.fillStyle=q,l.view==="preview"||R!==T){let L=Math.max(2,d+Math.min(1.5,d*.06));o.globalAlpha=1,o.beginPath(),o.arc(C.x,C.y,L,0,Math.PI*2),o.fill(),o.strokeStyle=I??q,o.lineWidth=l.view==="preview"?Math.max(1,Math.min(1.75,c*.13)):Math.max(1,Math.min(1.5,c*.1)),o.stroke(),l.view==="preview"&&u?.has(m.label)&&c>=22&&ts(o,m.label,C.x,C.y,L)}else o.globalAlpha=.85,o.fillRect(C.x-d,C.y-d,c,c)}}o.globalAlpha=1,g&&ns(o,g),ss(v,l),is(f,l,o)}function ts(l,e,t,s,n){let i=n*1.55,a=Math.min(13,Math.max(7,n*.55)),o=6;for(;a>=o&&(l.font=`800 ${a}px var(--slm-font, system-ui, sans-serif)`,!(l.measureText(e).width<=i));)a-=.5;a<o||(l.fillStyle="#ffffff",l.textAlign="center",l.textBaseline="middle",l.fillText(e,t,s))}function ss(l,e){let t=e.layer;if(t&&(t.querySelectorAll(".slm-ch-section-target").forEach(s=>s.remove()),!!l))for(let[s,n]of l){let i=n.maxX-n.minX,a=n.maxY-n.minY;if(i<20||a<20)continue;let o=document.createElement("button");o.type="button",o.className="slm-ch-section-target",o.style.left=`${n.minX-8}px`,o.style.top=`${n.minY-8}px`,o.style.width=`${i+16}px`,o.style.height=`${a+16}px`,o.setAttribute("aria-label",`Open ${n.label} seats`),o.addEventListener("click",()=>e.onSectionTargetClick(s)),t.appendChild(o)}}function ns(l,e){for(let t of e.values()){let s=t.maxX-t.minX,n=t.maxY-t.minY;if(s<52||n<26)continue;let i=(t.minX+t.maxX)/2,a=(t.minY+t.maxY)/2,o=Math.max(11,Math.min(15,n*.16));l.font=`800 ${o}px var(--slm-font, system-ui, sans-serif)`;let r=Math.min(s-8,l.measureText(t.label).width+18),c=o+10;l.fillStyle="rgba(11, 16, 28, .88)",l.fillRect(i-r/2,a-c/2,r,c),l.fillStyle="#f8fafc",l.textAlign="center",l.textBaseline="middle",l.fillText(t.label,i,a)}}function is(l,e,t){let s=e.layer;if(!s||(s.querySelectorAll(".slm-ch-flag").forEach(i=>i.remove()),e.view==="preview"))return;let n=[...l.entries()].sort((i,a)=>a[1].n-i[1].n).slice(0,Xt);for(let[i,a]of n){let o=e.list?.channels.find(h=>h.id===i);if(!o)continue;let r=e.host.worldToScreen({x:a.x/a.n,y:a.y/a.n});if(!r)continue;let c=e.markerFor(i),d=document.createElement("span");d.className="slm-ch-flag",d.style.left=`${r.x}px`,d.style.top=`${r.y}px`,d.innerHTML=`<span class="mk" style="background:${p(c.color)}">${p(c.letter)}</span>${p(o.name)}${o.state==="paused"?" \xB7 Paused":""}`,s.appendChild(d)}}var Xt,Gt,Zt,Qt,Jt,es,kt=j(()=>{"use strict";Re();$e();Xt=8,Gt="#6e7bff",Zt="#b9c0ff",Qt="#303846",Jt="#4b5669",es="#101723"});var xt,wt=j(()=>{"use strict";xt=`
14
14
  .slm{--slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;--slm-mo-ambient:2000ms;
15
15
  --slm-mo-out:cubic-bezier(.2,.8,.2,1);--slm-mo-in-out:cubic-bezier(.4,0,.2,1);--slm-mo-exit:cubic-bezier(.4,0,1,1);
16
16
  --slm-mo-spring:cubic-bezier(.34,1.3,.64,1)}
17
17
 
18
18
  /* map overlay: ONE layer, faded in as a whole (never per seat) */
19
- .slm-ch-layer{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity var(--slm-mo-base) var(--slm-mo-out)}
19
+ .slm-ch-layer{position:absolute;inset:0;overflow:hidden;pointer-events:none;opacity:0;transition:opacity var(--slm-mo-base) var(--slm-mo-out)}
20
20
  .slm-ch-layer.on{opacity:1}
21
21
  .slm-ch-canvas{position:absolute;inset:0;width:100%;height:100%}
22
22
  .slm-ch-flag{position:absolute;display:flex;align-items:center;gap:5px;padding:3px 8px;border-radius:999px;
@@ -68,7 +68,13 @@
68
68
  .slm-ch-mapnav .slm-ch-viewseg{margin:8px 0 5px}
69
69
  .slm-ch-mapnav p{margin:0;font-size:11px;line-height:1.45;color:var(--slm-muted)}
70
70
  .slm-ch-list{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}
71
- .slm-ch-row{padding:10px 11px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface);
71
+ .slm-ch-listhead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:8px 0}
72
+ .slm-ch-listhead h2{margin:0;font-size:14px}
73
+ .slm .slm-ch-listhead .slm-linkbtn{font-size:11px;color:var(--slm-text)}
74
+ .slm[data-theme=light] .slm-ch-badge.active,.slm[data-theme=light] .slm-ch-counts .free b{color:#137047}
75
+ .slm[data-theme=light] .slm-ch-badge.paused,.slm[data-theme=light] .slm-ch-badge.builtin{color:#815705}
76
+ .slm[data-theme=light] .slm-ch-badge.archived{color:var(--slm-muted)}
77
+ .slm-ch-row{padding:8px 9px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface);
72
78
  text-align:left;width:100%;display:block;transition:border-color var(--slm-mo-quick) var(--slm-mo-out)}
73
79
  .slm-ch-row:hover{border-color:var(--slm-muted)}
74
80
  .slm-ch-row.on{border-color:var(--slm-accent);box-shadow:0 0 0 1px color-mix(in srgb,var(--slm-accent) 40%,transparent)}
@@ -83,7 +89,7 @@
83
89
  .slm-ch-badge.active{background:rgba(34,160,107,.16);color:#5bd39b}
84
90
  .slm-ch-badge.paused,.slm-ch-badge.builtin{background:rgba(244,183,64,.15);color:#f7ca6b}
85
91
  .slm-ch-badge.archived{background:rgba(139,148,172,.18);color:#c2c9d8}
86
- .slm-ch-counts{display:flex;gap:10px;flex-wrap:wrap;margin-top:7px;font-size:11px;color:var(--slm-muted);
92
+ .slm-ch-counts{display:flex;gap:10px;flex-wrap:wrap;margin-top:5px;font-size:11px;color:var(--slm-muted);
87
93
  font-variant-numeric:tabular-nums}
88
94
  .slm-ch-counts b{color:var(--slm-text);font-weight:800}
89
95
  .slm-ch-counts .free b{color:#5bd39b}
@@ -132,11 +138,11 @@
132
138
  .slm-ch-dist .slm-btn{width:100%;margin-top:2px}
133
139
  .slm-ch-alert{display:flex;align-items:flex-start;gap:9px;padding:11px 13px;border-radius:10px;font-size:12.5px;
134
140
  line-height:1.5;margin-bottom:12px}
135
- .slm-ch-alert.warn{background:rgba(244,183,64,.1);border:1px solid rgba(244,183,64,.4);color:#f4d58a}
136
- .slm-ch-alert.info{background:rgba(110,123,255,.12);border:1px solid rgba(110,123,255,.44);color:#c5cbff}
137
- .slm-ch-alert.err{background:rgba(229,72,77,.1);border:1px solid rgba(229,72,77,.45);color:#f1a4a6}
138
- .slm-ch-alert b{color:#fff}
139
- .slm-ch-alert button{display:block;margin-top:6px;color:#fff;font-weight:800;min-height:36px}
141
+ .slm-ch-alert.warn{background:rgba(244,183,64,.1);border:1px solid rgba(244,183,64,.4);color:var(--slm-text)}
142
+ .slm-ch-alert.info{background:rgba(110,123,255,.12);border:1px solid rgba(110,123,255,.44);color:var(--slm-text)}
143
+ .slm-ch-alert.err{background:rgba(229,72,77,.1);border:1px solid rgba(229,72,77,.45);color:var(--slm-text)}
144
+ .slm-ch-alert b{color:inherit}
145
+ .slm-ch-alert button{display:block;margin-top:6px;color:var(--slm-text);font-weight:800;min-height:36px}
140
146
  .slm-ch-legend{display:flex;flex-direction:column;gap:6px;margin-top:10px}
141
147
  .slm-ch-legend .r{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--slm-muted)}
142
148
  .slm-ch-legend .sw{width:13px;height:13px;border-radius:3.5px;flex:none}
@@ -170,7 +176,7 @@
170
176
  .slm-ch-secret{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px dashed rgba(244,183,64,.55);
171
177
  border-radius:10px;background:rgba(244,183,64,.06);font-family:ui-monospace,Menlo,monospace;font-size:11px;
172
178
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
173
- .slm-ch-err{color:#f1a4a6;font-size:11.5px;margin-top:6px}
179
+ .slm-ch-err{color:var(--slm-text);font-size:11.5px;margin-top:6px}
174
180
  .slm-ch-price-list{display:flex;flex-direction:column;gap:7px}
175
181
  .slm-ch-price-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(100px,132px);align-items:center;gap:12px;
176
182
  padding:9px 0;border-bottom:1px solid var(--slm-line)}
@@ -253,19 +259,19 @@
253
259
  .slm-ch-staged.shake{outline:2px solid #e5484d;outline-offset:2px}
254
260
  .slm-ch-staged.done{outline:2px solid #5bd39b;outline-offset:2px}
255
261
  }
256
- `});var vt={};qe(vt,{CHANNELS_CSS:()=>mt,ChannelsMode:()=>ne,bucketRowsHtml:()=>W});var Xt,gt,A,ne,Fe=V(()=>{"use strict";Se();ae();ut();Le();bt();Le();Xt=3e4,gt=300,A=5e3,ne=class{constructor(e,t){this.active=!1;this.list=null;this.allocation=new Map;this.assignmentVersion=0;this.loadError=null;this.loading=!0;this.view="inspect";this.mapIntent="pan";this.focusedSectionId=null;this.showArchived=!1;this.detailChannelId=null;this.assignOpen=!1;this.targetChannelId="";this.conflict=!1;this.dialog=null;this.detent="medium";this.seatListLimit=gt;this.links=[];this.linksChannelId=null;this.linksState="idle";this.listSeq=0;this.linksSeq=0;this.previewAudience=[];this.previewIncludePublic=!1;this.previewProjection=null;this.previewState="idle";this.pollTimer=null;this.layer=null;this.canvas=null;this.ctx=void 0;this.bannerEl=null;this.stagedEl=null;this.liveEl=null;this.scrimEl=null;this.lastFocus=null;this.stagedDoneTimer=null;this.lastSelectionCount=0;this.lastCounts=new Map;this.assignmentRowsCache=null;this.railHtml=null;this.allocationVersion=null;this.onVisibility=null;this.host=e,this.caps=t}enter(){this.active||(this.active=!0,this.mapIntent="pan",this.assignOpen=!1,this.focusedSectionId=null,this.assignmentRowsCache=null,this.railHtml=null,this.ensureLayer(),this.host.root.classList.add("ch-mode"),this.applySheetClasses(),this.host.sections().length>1&&this.host.showSectionOverview(),this.paintRail(),this.onInteractionChange?.(),this.refresh(),this.pollTimer=setInterval(()=>{typeof document<"u"&&document.hidden||this.refresh({quiet:!0})},Xt),typeof document<"u"&&typeof document.addEventListener=="function"&&(this.onVisibility=()=>{this.active&&!document.hidden&&this.refresh({quiet:!0})},document.addEventListener("visibilitychange",this.onVisibility)))}leave(){this.active&&(this.active=!1,this.pollTimer&&clearInterval(this.pollTimer),this.pollTimer=null,this.onVisibility&&typeof document<"u"&&document.removeEventListener("visibilitychange",this.onVisibility),this.onVisibility=null,this.railHtml=null,this.closeDialog({restoreFocus:!1}),this.links=[],this.linksChannelId=null,this.linksState="idle",this.layer?.classList.remove("on"),this.host.root.classList.remove("ch-mode","ch-preview","ch-sheet","detent-collapsed","detent-medium","detent-full"),this.setBanner(!1),this.setStaged(null))}destroy(){this.leave(),this.stagedDoneTimer&&clearTimeout(this.stagedDoneTimer),this.layer?.remove(),this.layer=null}setCapabilities(e){this.caps=e,this.active&&this.paintRail()}isActive(){return this.active}canSelect(){return this.caps.manage&&this.view==="inspect"}usesMarqueeSelection(){return this.canSelect()&&this.mapIntent==="assign"}handleSectionFocus(e){this.active&&(this.focusedSectionId=e,this.paintRail())}applyRealtimeHint(){this.active&&this.refresh({quiet:!0})}handleSelectionChange(){this.active&&(this.paintSelection(),this.paintStagedBar())}handleViewChange(){this.active&&this.paintOverlay()}handleLayoutChange(){this.active&&(this.applySheetClasses(),this.paintOverlay())}async refresh(e={}){if(!this.caps.view)return;let t=++this.listSeq,s=()=>t!==this.listSeq;try{let n=await this.host.api.channels(this.host.eventKey,{includeArchived:this.showArchived});if(s())return;if(this.list=n,this.assignmentVersion=n.assignmentVersion,this.loadError=null,this.targetChannelId||(this.targetChannelId=n.channels.find(i=>i.state==="active")?.id??C),this.allocationVersion!==n.assignmentVersion){if(await this.loadAllocation(t),s())return;this.allocationVersion=n.assignmentVersion}if(this.detailChannelId&&await this.loadLinks(this.detailChannelId),s())return;this.loading=!1,this.active&&(this.paintRail(),this.paintOverlay())}catch(n){if(s())return;this.loading=!1,n instanceof y&&n.status===403&&(this.caps={view:!1,manage:!1}),this.loadError=n,e.quiet||this.host.onError(n),this.active&&this.paintRail()}}async loadAllocation(e){let t=new Map,s;for(let n=0;n<200;n+=1){if(e!==void 0&&e!==this.listSeq)return;let i=await this.host.api.channelAllocation(this.host.eventKey,{afterLabel:s,limit:1e3});for(let a of i.allocations)B(a.channelId)||t.set(a.label,a.channelId);if(this.assignmentVersion=i.assignmentVersion,!i.nextAfterLabel)break;s=i.nextAfterLabel}e!==void 0&&e!==this.listSeq||(this.allocation=t)}channelById(e){if(B(e))return{id:C,name:this.list?.publicSale?.name??T,marker:"P",color:null};let t=this.list?.channels.find(s=>s.id===e);return t?{id:e,name:t.name,marker:t.marker,color:t.color}:null}nameOf(e){return this.channelById(e)?.name??null}markerFor(e){let t=Math.max(0,this.list?.channels.findIndex(n=>n.id===e)??0),s=this.channelById(e);return pe(s??{id:e,name:"?",marker:null,color:null},t)}assignableChannels(){return[{id:C,name:this.list?.publicSale.name??T},...(this.list?.channels??[]).filter(e=>e.state!=="archived").map(e=>({id:e.id,name:e.name}))]}currentPlan(){let e=this.host.selectionLabels(),t=me({labels:e,targetChannelId:this.targetChannelId,allocation:this.allocation,statusOf:s=>this.host.statusOf(s),nameOf:s=>this.nameOf(s)});return{labels:e,buckets:t,target:this.targetChannelId}}ensureLayer(){if(this.layer)return;let e=document.createElement("div");e.className="slm-ch-layer",e.innerHTML=`
262
+ `});var Lt={};Ue(Lt,{CHANNELS_CSS:()=>xt,ChannelsMode:()=>se,bucketRowsHtml:()=>W});var as,St,M,se,_e=j(()=>{"use strict";Ie();Re();re();kt();$e();wt();$e();as=3e4,St=300,M=5e3,se=class{constructor(e,t){this.active=!1;this.list=null;this.allocation=new Map;this.assignmentVersion=0;this.loadError=null;this.loading=!0;this.view="inspect";this.mapIntent="pan";this.focusedSectionId=null;this.showArchived=!1;this.detailChannelId=null;this.assignOpen=!1;this.targetChannelId="";this.conflict=!1;this.dialog=null;this.detent="medium";this.seatListLimit=St;this.links=[];this.linksChannelId=null;this.linksState="idle";this.listSeq=0;this.linksSeq=0;this.previewAudience=[];this.previewIncludePublic=!1;this.previewProjection=null;this.previewState="idle";this.pollTimer=null;this.layer=null;this.canvas=null;this.ctx=void 0;this.bannerEl=null;this.stagedEl=null;this.liveEl=null;this.scrimEl=null;this.lastFocus=null;this.stagedDoneTimer=null;this.lastSelectionCount=0;this.lastCounts=new Map;this.assignmentRowsCache=null;this.railHtml=null;this.allocationVersion=null;this.onVisibility=null;this.host=e,this.caps=t}enter(){this.active||(this.active=!0,this.mapIntent="pan",this.assignOpen=!1,this.focusedSectionId=null,this.assignmentRowsCache=null,this.railHtml=null,this.ensureLayer(),this.host.root.classList.add("ch-mode"),this.applySheetClasses(),this.host.sections().length>1&&this.host.showSectionOverview(),this.paintRail(),this.onInteractionChange?.(),this.refresh(),this.pollTimer=setInterval(()=>{typeof document<"u"&&document.hidden||this.refresh({quiet:!0})},as),typeof document<"u"&&typeof document.addEventListener=="function"&&(this.onVisibility=()=>{this.active&&!document.hidden&&this.refresh({quiet:!0})},document.addEventListener("visibilitychange",this.onVisibility)))}leave(){this.active&&(this.active=!1,this.pollTimer&&clearInterval(this.pollTimer),this.pollTimer=null,this.onVisibility&&typeof document<"u"&&document.removeEventListener("visibilitychange",this.onVisibility),this.onVisibility=null,this.railHtml=null,this.closeDialog({restoreFocus:!1}),this.links=[],this.linksChannelId=null,this.linksState="idle",this.layer?.classList.remove("on"),this.host.root.classList.remove("ch-mode","ch-preview","ch-sheet","detent-collapsed","detent-medium","detent-full"),this.setBanner(!1),this.setStaged(null))}destroy(){this.leave(),this.stagedDoneTimer&&clearTimeout(this.stagedDoneTimer),this.layer?.remove(),this.layer=null}setCapabilities(e){this.caps=e,this.active&&this.paintRail()}isActive(){return this.active}canSelect(){return this.caps.manage&&this.view==="inspect"}usesMarqueeSelection(){return this.canSelect()&&this.mapIntent==="assign"}handleSectionFocus(e){this.active&&(this.focusedSectionId=e,this.paintRail())}applyRealtimeHint(){this.active&&this.refresh({quiet:!0})}handleSelectionChange(){this.active&&(this.paintSelection(),this.paintStagedBar())}handleViewChange(){this.active&&this.paintOverlay()}handleLayoutChange(){this.active&&(this.applySheetClasses(),this.paintOverlay())}async refresh(e={}){if(!this.caps.view)return;let t=++this.listSeq,s=()=>t!==this.listSeq;try{let n=await this.host.api.channels(this.host.eventKey,{includeArchived:this.showArchived});if(s())return;if(this.list=n,this.assignmentVersion=n.assignmentVersion,this.loadError=null,this.targetChannelId||(this.targetChannelId=n.channels.find(i=>i.state==="active")?.id??T),this.allocationVersion!==n.assignmentVersion){if(await this.loadAllocation(t),s())return;this.allocationVersion=n.assignmentVersion}if(this.detailChannelId&&await this.loadLinks(this.detailChannelId),s())return;this.loading=!1,this.active&&(this.paintRail(),this.paintOverlay())}catch(n){if(s())return;this.loading=!1,n instanceof y&&n.status===403&&(this.caps={view:!1,manage:!1}),this.loadError=n,e.quiet||this.host.onError(n),this.active&&this.paintRail()}}async loadAllocation(e){let t=new Map,s;for(let n=0;n<200;n+=1){if(e!==void 0&&e!==this.listSeq)return;let i=await this.host.api.channelAllocation(this.host.eventKey,{afterLabel:s,limit:1e3});for(let a of i.allocations)B(a.channelId)||t.set(a.label,a.channelId);if(this.assignmentVersion=i.assignmentVersion,!i.nextAfterLabel)break;s=i.nextAfterLabel}e!==void 0&&e!==this.listSeq||(this.allocation=t)}channelById(e){if(B(e))return{id:T,name:this.list?.publicSale?.name??A,marker:"P",color:null};let t=this.list?.channels.find(s=>s.id===e);return t?{id:e,name:t.name,marker:t.marker,color:t.color}:null}nameOf(e){return this.channelById(e)?.name??null}markerFor(e){let t=Math.max(0,this.list?.channels.findIndex(n=>n.id===e)??0),s=this.channelById(e);return ge(s??{id:e,name:"?",marker:null,color:null},t)}assignableChannels(){return[{id:T,name:this.list?.publicSale.name??A},...(this.list?.channels??[]).filter(e=>e.state!=="archived").map(e=>({id:e.id,name:e.name}))]}currentPlan(){let e=this.host.selectionLabels(),t=fe({labels:e,targetChannelId:this.targetChannelId,allocation:this.allocation,statusOf:s=>this.host.statusOf(s),nameOf:s=>this.nameOf(s)});return{labels:e,buckets:t,target:this.targetChannelId}}ensureLayer(){if(this.layer)return;let e=document.createElement("div");e.className="slm-ch-layer",e.innerHTML=`
257
263
  <canvas class="slm-ch-canvas" data-ch="canvas" aria-hidden="true"></canvas>
258
264
  <div class="slm-ch-banner" data-ch="banner" role="status"></div>
259
265
  <div class="slm-ch-staged" data-ch="staged" role="group" aria-label="Staged channel changes"></div>
260
- <div class="slm-ch-live" data-ch="live" role="status" aria-live="polite"></div>`,this.host.mapLayer.appendChild(e),this.layer=e,this.canvas=e.querySelector('[data-ch="canvas"]'),this.bannerEl=e.querySelector('[data-ch="banner"]'),this.stagedEl=e.querySelector('[data-ch="staged"]'),this.liveEl=e.querySelector('[data-ch="live"]'),requestAnimationFrame(()=>e.classList.add("on"))}announce(e){this.liveEl&&(this.liveEl.textContent=e)}paintOverlay(){let e=this.canvas,t=this.layer;!e||!t||pt({layer:t,canvas:e,resolveCtx:()=>{if(this.ctx===void 0)try{this.ctx=e.getContext("2d")}catch{this.ctx=null}return this.ctx},host:this.host,view:this.view,previewProjection:this.previewProjection,allocation:this.allocation,focusedSectionId:this.focusedSectionId,list:this.list,markerFor:s=>this.markerFor(s),onSectionTargetClick:s=>{this.focusedSectionId=s,this.host.focusSection(s),this.paintRail()}})}setStaged(e,t=""){let s=this.stagedEl;if(s){if(!e){s.classList.remove("on","done","shake"),s.innerHTML="";return}s.innerHTML=e,s.className=`slm-ch-staged on${t?` ${t}`:""}`}}paintStagedBar(){if(!this.active||this.view==="preview"||!this.caps.manage){this.setStaged(null);return}let{labels:e,buckets:t}=this.currentPlan();if(this.host.onStagedChange?.(K(t)),!e.length){this.setStaged(null);return}let s=this.nameOf(this.targetChannelId)??T,n=K(t),i=e.length>A,a=t.skippedHeld.count+t.skippedBooked.count,o=[`<b>${e.length.toLocaleString()}</b> selected`,`<b>+${n.toLocaleString()}</b> to ${h(s)}`];t.alreadyInTarget.count&&o.push(`<b>${t.alreadyInTarget.count.toLocaleString()}</b> already in`),a&&o.push(`<b>${a.toLocaleString()}</b> can't move now`),this.setStaged(`
266
+ <div class="slm-ch-live" data-ch="live" role="status" aria-live="polite"></div>`,this.host.mapLayer.appendChild(e),this.layer=e,this.canvas=e.querySelector('[data-ch="canvas"]'),this.bannerEl=e.querySelector('[data-ch="banner"]'),this.stagedEl=e.querySelector('[data-ch="staged"]'),this.liveEl=e.querySelector('[data-ch="live"]'),requestAnimationFrame(()=>e.classList.add("on"))}announce(e){this.liveEl&&(this.liveEl.textContent=e)}paintOverlay(){let e=this.canvas,t=this.layer;!e||!t||yt({layer:t,canvas:e,resolveCtx:()=>{if(this.ctx===void 0)try{this.ctx=e.getContext("2d")}catch{this.ctx=null}return this.ctx},host:this.host,view:this.view,previewProjection:this.previewProjection,allocation:this.allocation,focusedSectionId:this.focusedSectionId,list:this.list,markerFor:s=>this.markerFor(s),onSectionTargetClick:s=>{this.focusedSectionId=s,this.host.focusSection(s),this.paintRail()}})}setStaged(e,t=""){let s=this.stagedEl;if(s){if(!e){s.classList.remove("on","done","shake"),s.innerHTML="";return}s.innerHTML=e,s.className=`slm-ch-staged on${t?` ${t}`:""}`}}paintStagedBar(){if(!this.active||this.view==="preview"||!this.caps.manage){this.setStaged(null);return}let{labels:e,buckets:t}=this.currentPlan();if(this.host.onStagedChange?.(K(t)),!e.length){this.setStaged(null);return}let s=this.nameOf(this.targetChannelId)??A,n=K(t),i=e.length>M,a=t.skippedHeld.count+t.skippedBooked.count,o=[`<b>${e.length.toLocaleString()}</b> selected`,`<b>+${n.toLocaleString()}</b> to ${p(s)}`];t.alreadyInTarget.count&&o.push(`<b>${t.alreadyInTarget.count.toLocaleString()}</b> already in`),a&&o.push(`<b>${a.toLocaleString()}</b> can't move now`),this.setStaged(`
261
267
  <span>${o.join(" \xB7 ")}</span>
262
268
  <span class="grow"></span>
263
269
  <button type="button" class="drop" data-ch-act="discard">Discard</button>
264
270
  <button type="button" class="go" data-ch-act="review"${i?" disabled":""}>
265
- ${i?`Maximum ${A.toLocaleString()} seats`:"Review changes"}
266
- </button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(r=>{r.addEventListener("click",()=>{r.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",s){let n=this.bannerEl;if(!n)return;if(this.host.root.classList.toggle("ch-preview",e),!e){n.classList.remove("on"),n.innerHTML="";return}let i=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},a=s==null?"":` \xB7 ${s.toLocaleString()} ${s===1?"seat":"seats"} available now`;n.innerHTML=`<span class="dot" style="background:${h(i.color)}"></span>
267
- Previewing buyer access \xB7 ${h(t)}${a} \xB7 read-only
268
- <button type="button" data-ch-act="exit-preview">Exit preview</button>`,n.classList.add("on"),n.querySelector('[data-ch-act="exit-preview"]')?.addEventListener("click",()=>this.setView("inspect"))}setView(e){if(this.view=e,e==="inspect")this.previewProjection=null,this.previewState="idle",this.setBanner(!1);else{if(!this.previewAudience.length){let t=this.list?.channels.find(s=>s.state==="active");this.previewAudience=[t?t.id:C]}this.loadPreview()}this.paintRail(),this.paintOverlay(),this.paintStagedBar(),this.onInteractionChange?.()}async loadPreview(){let e=[...this.previewAudience],t=e.map(s=>this.nameOf(s)??T).join(" + ");this.setBanner(!0,t),this.previewProjection=null,this.previewState="loading",this.active&&this.paintRail();try{this.previewProjection=await this.host.api.channelPreview(this.host.eventKey,e,{includePublic:this.previewIncludePublic||e.some(B)}),this.previewState="ready";let s=this.previewProjection.available===!1?void 0:this.previewProjection.counts?.eligible??this.previewProjection.eligible?.length;this.setBanner(!0,t,s)}catch(s){let n=s instanceof y?s.status:0;this.previewState=n===404||n===405||n===501?"unsupported":"error",this.previewProjection=null,this.previewState==="error"&&this.host.onError(s)}this.active&&(this.paintRail(),this.paintOverlay())}setRailHtml(e){if(e===this.railHtml)return!1;let t=this.host.rail,s=t.scrollTop;return t.innerHTML=e,this.railHtml=e,s&&(t.scrollTop=s),!0}paintRail(){if(!this.active)return;let e=this.host.rail;if(!this.caps.view){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
271
+ ${i?`Maximum ${M.toLocaleString()} seats`:"Review changes"}
272
+ </button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(r=>{r.addEventListener("click",()=>{r.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",s){let n=this.bannerEl;if(!n)return;if(this.host.root.classList.toggle("ch-preview",e),!e){n.classList.remove("on"),n.innerHTML="";return}let i=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},a=s==null?"":` \xB7 ${s.toLocaleString()} ${s===1?"seat":"seats"} available now`;n.innerHTML=`<span class="dot" style="background:${p(i.color)}"></span>
273
+ Previewing buyer access \xB7 ${p(t)}${a} \xB7 read-only
274
+ <button type="button" data-ch-act="exit-preview">Exit preview</button>`,n.classList.add("on"),n.querySelector('[data-ch-act="exit-preview"]')?.addEventListener("click",()=>this.setView("inspect"))}setView(e){if(this.view=e,e==="inspect")this.previewProjection=null,this.previewState="idle",this.setBanner(!1);else{if(!this.previewAudience.length){let t=this.list?.channels.find(s=>s.state==="active");this.previewAudience=[t?t.id:T]}this.loadPreview()}this.paintRail(),this.paintOverlay(),this.paintStagedBar(),this.onInteractionChange?.()}async loadPreview(){let e=[...this.previewAudience],t=e.map(s=>this.nameOf(s)??A).join(" + ");this.setBanner(!0,t),this.previewProjection=null,this.previewState="loading",this.active&&this.paintRail();try{this.previewProjection=await this.host.api.channelPreview(this.host.eventKey,e,{includePublic:this.previewIncludePublic||e.some(B)}),this.previewState="ready";let s=this.previewProjection.available===!1?void 0:this.previewProjection.counts?.eligible??this.previewProjection.eligible?.length;this.setBanner(!0,t,s)}catch(s){let n=s instanceof y?s.status:0;this.previewState=n===404||n===405||n===501?"unsupported":"error",this.previewProjection=null,this.previewState==="error"&&this.host.onError(s)}this.active&&(this.paintRail(),this.paintOverlay())}setRailHtml(e){if(e===this.railHtml)return!1;let t=this.host.rail,s=t.scrollTop;return t.innerHTML=e,this.railHtml=e,s&&(t.scrollTop=s),!0}paintRail(){if(!this.active)return;let e=this.host.rail;if(!this.caps.view){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
269
275
  <p class="slm-hint">You need channel-management permission on this event to see allocations.</p>`);return}if(this.loading&&!this.list){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
270
276
  <div class="slm-ch-busy" role="status" data-ch-state="list-loading">Loading channels and allocations\u2026</div>`);return}if(!this.list&&this.loadError){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
271
277
  <div class="slm-ch-alert err" role="alert" data-ch-state="list-error"><span>\u26A0</span>
@@ -273,49 +279,38 @@
273
279
  Everything else on this event still works.
274
280
  <button type="button" data-ch-act="retry">Try again</button></span></div>`)&&e.querySelector('[data-ch-act="retry"]')?.addEventListener("click",()=>{this.refresh()});return}let t=this.host.selectionLabels(),s=this.host.isCompact()?'<div class="slm-ch-grab"><span class="slm-ch-grabbar"></span></div>':"",n=this.viewSegmentHtml(),i=this.view==="preview"?this.previewRailHtml():this.detailChannelId?this.detailRailHtml(this.detailChannelId):t.length&&this.caps.manage?this.selectionRailHtml(t):this.listRailHtml();this.setRailHtml(`${s}${n}${i}`)&&this.wireRail(),this.paintStagedBar()}viewSegmentHtml(){let e=this.view==="inspect"?" on":"",t=this.view==="preview"?" on":"";return`<div class="slm-ch-viewseg" role="group" aria-label="Channels view">
275
281
  <button type="button" class="${e.trim()}" data-ch-view="inspect"
276
- aria-pressed="${this.view==="inspect"}">Inspect allocation</button>
282
+ aria-pressed="${this.view==="inspect"}">Allocation</button>
277
283
  <button type="button" class="${t.trim()}" data-ch-view="preview"
278
- aria-pressed="${this.view==="preview"}">Preview buyer access</button>
279
- </div>${this.mapNavigationHtml()}`}mapNavigationHtml(){if(this.host.sections().length<2)return"";let e=this.focusedSectionId?this.host.sections().find(i=>i.id===this.focusedSectionId)?.label??"section":null,t=this.mapIntent==="pan"?" on":"",s=this.mapIntent==="assign"?" on":"",n=this.view==="inspect"&&this.caps.manage?`<div class="slm-ch-viewseg" role="group" aria-label="Map interaction">
280
- <button type="button" class="${t.trim()}" data-ch-map="pan" aria-pressed="${this.mapIntent==="pan"}">Pan map</button>
281
- <button type="button" class="${s.trim()}" data-ch-map="assign" aria-pressed="${this.mapIntent==="assign"}">Assign seats</button>
282
- </div>
283
- <p>${this.mapIntent==="pan"?"Drag to explore. Click a section to open its seats.":"Drag across seats to select them for allocation."}</p>`:"<p>Drag to explore. Click a section to open its seats.</p>";return`<div class="slm-ch-mapnav">
284
- <div class="slm-ch-mapnav-head"><span>${e?`Viewing ${h(e)}`:"Section overview"}</span>
285
- <button type="button" data-ch-act="sections">All sections</button></div>
286
- ${n}
287
- </div>`}countsHtml(e,t){let s=(n,i,a,o="")=>{let r=this.lastCounts.get(`${t}:${n}`),d=r!=null&&r!==i?" bump":"";return this.lastCounts.set(`${t}:${n}`,i),`<span class="${o}"><b class="${d.trim()}">${i.toLocaleString()}</b> ${a}</span>`};return`<span class="slm-ch-counts">
284
+ aria-pressed="${this.view==="preview"}">Buyer preview</button>
285
+ </div>${this.mapNavigationHtml()}`}mapNavigationHtml(){if(this.host.sections().length<2)return"";let e=this.focusedSectionId?this.host.sections().find(t=>t.id===this.focusedSectionId)?.label??"section":null;return e?`<div class="slm-ch-mapnav-head"><span>${p(e)}</span>
286
+ <button type="button" data-ch-act="sections">All sections</button></div>`:""}countsHtml(e,t){let s=(n,i,a,o="")=>{let r=this.lastCounts.get(`${t}:${n}`),c=r!=null&&r!==i?" bump":"";return this.lastCounts.set(`${t}:${n}`,i),`<span class="${o}"><b class="${c.trim()}">${i.toLocaleString()}</b> ${a}</span>`};return`<span class="slm-ch-counts">
288
287
  ${s("allocated",e.allocated,"allocated")}
289
288
  ${s("free",e.free,"free","free")}
290
289
  ${s("booked",e.booked,"sold")}
291
290
  ${e.held?s("held",e.held,"held"):""}
292
- </span>`}channelRowHtml(e,t={}){let s=this.markerFor(e.id),n=t.builtin?"builtin":e.state,i=e.state==="paused"||e.state==="archived"?" dim":"",a=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,o=`slm-ch-row${t.builtin?" public":""}${e.state==="archived"?" archived":""}${this.detailChannelId===e.id?" on":""}${a?" open":""}`,r=!t.builtin&&this.caps.manage?`<button type="button" class="slm-ch-more" data-ch-menu="${h(e.id)}"
293
- aria-label="More actions for ${h(e.name)}" aria-haspopup="dialog">\u22EF</button>`:"",d=a?` role="button" tabindex="0" data-ch-open="${h(e.id)}"
294
- aria-label="Open ${h(e.name)}"`:"";return`<div class="${o}"${d}>
291
+ </span>`}channelRowHtml(e,t={}){let s=this.markerFor(e.id),n=t.builtin?"builtin":e.state,i=e.state==="paused"||e.state==="archived"?" dim":"",a=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,o=`slm-ch-row${t.builtin?" public":""}${e.state==="archived"?" archived":""}${this.detailChannelId===e.id?" on":""}${a?" open":""}`,r=!t.builtin&&this.caps.manage?`<button type="button" class="slm-ch-more" data-ch-menu="${p(e.id)}"
292
+ aria-label="More actions for ${p(e.name)}" aria-haspopup="dialog">\u22EF</button>`:"",c=a?` role="button" tabindex="0" data-ch-open="${p(e.id)}"
293
+ aria-label="Open ${p(e.name)}"`:"";return`<div class="${o}"${c}>
295
294
  <span class="slm-ch-head">
296
- <span class="slm-ch-mk${i}" style="background:${h(s.color)}" aria-hidden="true">${h(s.letter)}</span>
297
- <span class="slm-ch-name">${h(e.name)}</span>
298
- <span class="slm-ch-badge ${n}">${h(xe(t.builtin?"builtin":e.state))}</span>
295
+ <span class="slm-ch-mk${i}" style="background:${p(s.color)}" aria-hidden="true">${p(s.letter)}</span>
296
+ <span class="slm-ch-name">${p(e.name)}</span>
297
+ <span class="slm-ch-badge ${n}">${p(Te(t.builtin?"builtin":e.state))}</span>
299
298
  ${r}
300
299
  </span>
301
300
  ${this.countsHtml(e.counts,e.id||"public")}
302
- ${t.builtin?"":`<span class="slm-ch-access">${h(fe(e.access))}</span>`}
303
- </div>`}listRailHtml(){let e=this.list,t=e.channels.filter(r=>r.state==="archived").length,s=e.channels.filter(r=>this.showArchived||r.state!=="archived"),n=[this.channelRowHtml(e.publicSale,{builtin:!0}),...s.map((r,d)=>this.channelRowHtml(r,{index:d}))].join(""),i=s.length?"":`<p class="slm-note" data-ch-state="list-empty">${t&&!this.showArchived?`No open channels \u2014 every seat is on public sale. ${t.toLocaleString()} archived channel${t===1?" is":"s are"} hidden below.`:"No private channels yet \u2014 every seat is on public sale."}</p>`,a=this.caps.manage?'<button type="button" class="slm-btn ghost" style="width:100%" data-ch-act="create">+ Create channel</button>':"",o=this.caps.manage?"":'<p class="slm-note">You can see how inventory is allocated. Changing it needs channel-management permission.</p>';return`
304
- <p class="slm-eyebrow">Sales channels</p>
305
- <p class="slm-hint">Channel colours and names are only visible to organizers, never to buyers.</p>
301
+ ${t.builtin?"":`<span class="slm-ch-access">${p(we(e.access))}</span>`}
302
+ </div>`}listRailHtml(){let e=this.list,t=e.channels.filter(r=>r.state==="archived").length,s=e.channels.filter(r=>this.showArchived||r.state!=="archived"),n=[this.channelRowHtml(e.publicSale,{builtin:!0}),...s.map((r,c)=>this.channelRowHtml(r,{index:c}))].join(""),i=s.length?"":`<p class="slm-note" data-ch-state="list-empty">${t&&!this.showArchived?`No open channels \u2014 every seat is on public sale. ${t.toLocaleString()} archived channel${t===1?" is":"s are"} hidden below.`:"No private channels yet \u2014 every seat is on public sale."}</p>`,a=this.caps.manage?'<button type="button" class="slm-linkbtn" data-ch-act="create">+ New channel</button>':"",o=this.caps.manage?"":'<p class="slm-note">You can see how inventory is allocated. Changing it needs channel-management permission.</p>';return`
303
+ <div class="slm-ch-listhead"><h2>Sales channels</h2>${a}</div>
306
304
  <div class="slm-ch-list">${n}</div>
307
305
  ${i}
308
- ${a}
309
306
  ${o}
310
307
  ${this.assignEntryHtml()}
311
- <p class="slm-note" style="margin-top:10px">
308
+ <p class="slm-note" style="margin-top:10px" ${t||this.showArchived?"":"hidden"}>
312
309
  <button type="button" class="slm-linkbtn" data-ch-act="toggle-archived" aria-pressed="${this.showArchived}"
313
310
  style="text-align:left">${this.showArchived?"Hide":"Show"} archived${t?` (${t})`:""}</button>
314
311
  </p>`}assignEntryHtml(){return this.caps.manage?this.assignOpen?`<div style="margin-top:8px">${this.assignmentToolsHtml({collapsible:!0})}</div>`:`
315
- <button type="button" class="slm-btn ghost" style="width:100%;margin-top:8px"
316
- data-ch-act="assign-open" aria-expanded="false">Assign seats to a channel</button>
317
- <p class="slm-note">Move whole sections, rows, a dragged area or single seats out of public sale
318
- and into a channel. Nothing moves until you review and apply.</p>`:""}assignmentToolsHtml(e={}){let t=this.assignableChannels().map(o=>`<option value="${h(o.id)}"${o.id===this.targetChannelId?" selected":""}>${h(o.name)}</option>`).join(""),s=this.host.sections().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-sections">Sections</button>':"",n=this.assignmentRows().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-rows">Rows</button>':"",i=this.mapIntent==="assign"?"slm-btn":"slm-btn ghost";return`
312
+ <button type="button" class="slm-btn" style="width:100%;margin-top:8px"
313
+ data-ch-act="assign-open" aria-expanded="false">Assign seats</button>`:""}assignmentToolsHtml(e={}){let t=this.assignableChannels().map(o=>`<option value="${p(o.id)}"${o.id===this.targetChannelId?" selected":""}>${p(o.name)}</option>`).join(""),s=this.host.sections().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-sections">Sections</button>':"",n=this.assignmentRows().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-rows">Rows</button>':"",i=this.mapIntent==="assign"?"slm-btn":"slm-btn ghost";return`
319
314
  <p class="slm-eyebrow">${e.collapsible?`<button type="button" class="slm-linkbtn" data-ch-act="assign-close"
320
315
  aria-expanded="true" style="float:right;font-weight:800">Done</button>`:""}Assign inventory</p>
321
316
  <div class="slm-field">
@@ -332,19 +327,19 @@
332
327
  <button type="button" class="slm-btn ghost" data-ch-act="seatlist">Seat list \u2328</button>
333
328
  </div>
334
329
  <p class="slm-note" style="margin-bottom:18px">Choose a destination, then add whole sections,
335
- multiple rows, a dragged area, or individual seats.</p>`}selectionRailHtml(e){let t=ue(e,this.allocation,this.list),s=this.conflict?`<div class="slm-ch-alert err" role="alert"><span>\u26A0</span>
330
+ multiple rows, a dragged area, or individual seats.</p>`}selectionRailHtml(e){let t=ve(e,this.allocation,this.list),s=this.conflict?`<div class="slm-ch-alert err" role="alert"><span>\u26A0</span>
336
331
  <span><b>Assignments changed while you were editing.</b> Nothing was applied.
337
332
  Your ${e.length.toLocaleString()}-seat selection is kept.
338
- <button type="button" data-ch-act="refresh-review">Refresh and review \u2192</button></span></div>`:"",n=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let i=e.length>A,a=t.map(o=>{let r=this.markerFor(o.channelId);return`<div class="slm-ch-selsrc-row">
339
- <span class="mk" style="background:${h(r.color)}" aria-hidden="true">${h(r.letter)}</span>
340
- <b>${o.count.toLocaleString()}</b><span>${h(o.name)}</span></div>`}).join("");return`
333
+ <button type="button" data-ch-act="refresh-review">Refresh and review \u2192</button></span></div>`:"",n=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let i=e.length>M,a=t.map(o=>{let r=this.markerFor(o.channelId);return`<div class="slm-ch-selsrc-row">
334
+ <span class="mk" style="background:${p(r.color)}" aria-hidden="true">${p(r.letter)}</span>
335
+ <b>${o.count.toLocaleString()}</b><span>${p(o.name)}</span></div>`}).join("");return`
341
336
  ${s}
342
337
  ${this.assignmentToolsHtml()}
343
338
  <div class="slm-selbar"><span class="slm-selnum slm-ch-selnum${n}">${e.length.toLocaleString()}</span>
344
339
  <span class="slm-sellabel">selected</span></div>
345
340
  <div class="slm-ch-selsrc" aria-live="polite" aria-label="Selection sources">${a}</div>
346
341
  ${i?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span>
347
- <b>This selection is too large to apply at once.</b> Choose at most ${A.toLocaleString()}
342
+ <b>This selection is too large to apply at once.</b> Choose at most ${M.toLocaleString()}
348
343
  seats, for example by splitting the venue into row groups.</span></div>`:""}
349
344
  <p class="slm-note">Changes are staged \u2014 nothing moves until you review and apply.
350
345
  Seats in checkout or already sold are never moved.</p>
@@ -372,40 +367,40 @@
372
367
  </div>
373
368
  <p class="slm-note">Only buyers admitted to this channel see and pay these prices. Existing holds keep the price already promised.</p>`:"";return`
374
369
  ${t}
375
- <p class="slm-eyebrow">Channel \xB7 ${h(s.name)}</p>
370
+ <p class="slm-eyebrow">Channel \xB7 ${p(s.name)}</p>
376
371
  <div class="slm-ch-list">${this.channelRowHtml(s)}</div>
377
372
  ${o}
378
373
  ${i}
379
- ${n}`}distributeHtml(e){let t=e.access?.intent??"none",s=e.access?.hasActiveGrants===!0,n=this.linksState!=="unsupported",i=this.links.some(te),a=t==="none"?"Protected reserve \u2014 no route can sell these seats. Every buyer path is refused.":t==="internal"?"Your staff sell these seats. No buyer-facing route is open.":s?t==="server"?"Your website is letting buyers in. Only they can buy these seats.":"A buyer link is live. Only people with that link can buy these seats.":t==="server"?"Set up for your website \u2014 no buyer has come through yet. Seats stay reserved.":"Set up for buyer links \u2014 no buyer has come through yet. Seats stay reserved.",o=(r,d,c,p)=>{let m=r===t;return`<div class="slm-ch-dist${m?" on":""}" data-ch-route="${h(r)}">
380
- <b>${h(F(r))}${m?'<span class="cur">Current route</span>':""}</b>
381
- <span class="why">${h(ye(r))}</span>
382
- ${m&&!c?"":`<button type="button" class="slm-btn${p&&!m?"":" ghost"}"
383
- data-ch-act="${h(d)}">${h(c)}</button>`}
374
+ ${n}`}distributeHtml(e){let t=e.access?.intent??"none",s=e.access?.hasActiveGrants===!0,n=this.linksState!=="unsupported",i=this.links.some(ee),a=t==="none"?"Protected reserve \u2014 no route can sell these seats. Every buyer path is refused.":t==="internal"?"Your staff sell these seats. No buyer-facing route is open.":s?t==="server"?"Your website is letting buyers in. Only they can buy these seats.":"A buyer link is live. Only people with that link can buy these seats.":t==="server"?"Set up for your website \u2014 no buyer has come through yet. Seats stay reserved.":"Set up for buyer links \u2014 no buyer has come through yet. Seats stay reserved.",o=(r,c,d,h)=>{let u=r===t;return`<div class="slm-ch-dist${u?" on":""}" data-ch-route="${p(r)}">
375
+ <b>${p(F(r))}${u?'<span class="cur">Current route</span>':""}</b>
376
+ <span class="why">${p(Se(r))}</span>
377
+ ${u&&!d?"":`<button type="button" class="slm-btn${h&&!u?"":" ghost"}"
378
+ data-ch-act="${p(c)}">${p(d)}</button>`}
384
379
  </div>`};return`
385
380
  <p class="slm-eyebrow" style="margin-top:14px">Distribute</p>
386
- <p class="slm-hint">${h(a)}</p>
381
+ <p class="slm-hint">${p(a)}</p>
387
382
  ${n?o("hosted_link","link-create",i?"Create another buyer link":"Create buyer link",!0):""}
388
383
  ${o("server","embed-code",t==="server"?"Get embed code":"Use a website or app",!1)}
389
384
  ${o("internal","route-internal",t==="internal"?"":"Hand to your staff",!1)}
390
385
  ${o("none","route-none",t==="none"?"":"Keep as reserve",!1)}
391
386
  ${this.hostedLinksHtml()}
392
- ${t==="server"?dt:""}`}async loadLinks(e){if(!this.caps.view)return;let t=++this.linksSeq,s=()=>t!==this.linksSeq||this.linksChannelId!==e;this.linksChannelId!==e&&(this.links=[],this.linksChannelId=e,this.linksState="loading");try{let n=await this.host.api.accessLinks(this.host.eventKey,e);if(s())return;this.links=n.links??[],this.linksState="ready"}catch(n){if(s())return;let i=n instanceof y?n.status:0;this.links=[],this.linksState=i===404||i===405||i===501?"unsupported":"error",this.linksState==="error"&&this.host.onError(n)}}hostedLinksHtml(){let e='<p class="slm-eyebrow" style="margin-top:18px">Buyer links</p>';return this.linksState==="unsupported"?`${e}<div class="slm-ch-alert warn" data-ch-state="links-unsupported"><span>\u2139</span>
387
+ ${t==="server"?vt:""}`}async loadLinks(e){if(!this.caps.view)return;let t=++this.linksSeq,s=()=>t!==this.linksSeq||this.linksChannelId!==e;this.linksChannelId!==e&&(this.links=[],this.linksChannelId=e,this.linksState="loading");try{let n=await this.host.api.accessLinks(this.host.eventKey,e);if(s())return;this.links=n.links??[],this.linksState="ready"}catch(n){if(s())return;let i=n instanceof y?n.status:0;this.links=[],this.linksState=i===404||i===405||i===501?"unsupported":"error",this.linksState==="error"&&this.host.onError(n)}}hostedLinksHtml(){let e='<p class="slm-eyebrow" style="margin-top:18px">Buyer links</p>';return this.linksState==="unsupported"?`${e}<div class="slm-ch-alert warn" data-ch-state="links-unsupported"><span>\u2139</span>
393
388
  <span><b>Buyer links need a newer server.</b> Everything else on this channel works normally.</span></div>`:this.linksState==="error"?`${e}<div class="slm-ch-alert err" role="alert" data-ch-state="links-error"><span>\u26A0</span>
394
389
  <span><b>Couldn't load this channel's links.</b> This is a failed read, not an empty list \u2014
395
390
  any live link is still working.
396
391
  <button type="button" data-ch-act="link-reload">Try again</button></span></div>`:this.linksState==="idle"||this.linksState==="loading"&&!this.links.length?`${e}<div class="slm-ch-busy" role="status" data-ch-state="links-loading">Loading buyer links\u2026</div>`:this.links.length?`${e}
397
392
  ${this.links.map(t=>this.linkCardHtml(t)).join("")}
398
393
  <p class="slm-note">A link is shown once, when you create it. SeatLayer keeps only a fingerprint of it, so it
399
- can never be shown again \u2014 if a link is lost, rotate it and send the fresh one.</p>`:""}linkCardHtml(e){let t=we(e),s=e.maxRedemptions>0?Math.min(100,Math.round(e.redemptions/e.maxRedemptions*100)):0,n=se(e).map(r=>`<div class="slm-ch-lkrow"><span class="k">${h(r.k)}</span>
400
- <span class="v">${h(r.v)}</span></div>`).join(""),i=e.activeSessions?`<div class="slm-ch-lkrow"><span class="k">Buyers inside now</span>
394
+ can never be shown again \u2014 if a link is lost, rotate it and send the fresh one.</p>`:""}linkCardHtml(e){let t=Ce(e),s=e.maxRedemptions>0?Math.min(100,Math.round(e.redemptions/e.maxRedemptions*100)):0,n=te(e).map(r=>`<div class="slm-ch-lkrow"><span class="k">${p(r.k)}</span>
395
+ <span class="v">${p(r.v)}</span></div>`).join(""),i=e.activeSessions?`<div class="slm-ch-lkrow"><span class="k">Buyers inside now</span>
401
396
  <span class="v">${e.activeSessions.toLocaleString()}</span></div>`:"",a=e.lastRedeemedAt?`<div class="slm-ch-lkrow"><span class="k">Last opened</span>
402
- <span class="v">${h(new Date(e.lastRedeemedAt).toLocaleString())}</span></div>`:"",o=this.caps.manage&&te(e)?`<div class="slm-ch-row2">
403
- <button type="button" class="slm-btn ghost" data-ch-rotate="${h(e.id)}">Rotate</button>
404
- <button type="button" class="slm-btn ghost" data-ch-revoke="${h(e.id)}">Revoke</button>
397
+ <span class="v">${p(new Date(e.lastRedeemedAt).toLocaleString())}</span></div>`:"",o=this.caps.manage&&ee(e)?`<div class="slm-ch-row2">
398
+ <button type="button" class="slm-btn ghost" data-ch-rotate="${p(e.id)}">Rotate</button>
399
+ <button type="button" class="slm-btn ghost" data-ch-revoke="${p(e.id)}">Revoke</button>
405
400
  </div>`:"";return`<div class="slm-ch-link">
406
401
  <span class="lk-head">
407
- <span class="lk-name">${h(e.label||"Buyer link")}</span>
408
- <span class="slm-ch-badge ${t.kind}">${h(t.text)}</span>
402
+ <span class="lk-name">${p(e.label||"Buyer link")}</span>
403
+ <span class="slm-ch-badge ${t.kind}">${p(t.text)}</span>
409
404
  </span>
410
405
  <div class="slm-ch-meter" role="img"
411
406
  aria-label="${e.redemptions.toLocaleString()} of ${e.maxRedemptions.toLocaleString()} redemptions used">
@@ -414,15 +409,15 @@
414
409
  <div class="slm-ch-lkrow"><span class="k">The URL</span>
415
410
  <span class="v">Revealed once at creation \u2014 not recoverable</span></div>
416
411
  ${o}
417
- </div>`}previewRailHtml(){let e=[{id:C,name:this.list?.publicSale.name??T},...(this.list?.channels??[]).filter(p=>p.state!=="archived").map(p=>({id:p.id,name:p.name}))],t=this.previewAudience[0]??C,s=e.map(p=>`<option value="${h(p.id)}"${p.id===t?" selected":""}>${h(p.name)}</option>`).join(""),n=this.previewState==="unsupported"?`<div class="slm-ch-alert warn" data-ch-state="preview-unsupported"><span>\u2139</span>
412
+ </div>`}previewRailHtml(){let e=[{id:T,name:this.list?.publicSale.name??A},...(this.list?.channels??[]).filter(h=>h.state!=="archived").map(h=>({id:h.id,name:h.name}))],t=this.previewAudience[0]??T,s=e.map(h=>`<option value="${p(h.id)}"${h.id===t?" selected":""}>${p(h.name)}</option>`).join(""),n=this.previewState==="unsupported"?`<div class="slm-ch-alert warn" data-ch-state="preview-unsupported"><span>\u2139</span>
418
413
  <span><b>Preview needs a newer server.</b> Allocation management works normally;
419
414
  the buyer-view simulation will appear once this event's API is updated.</span></div>`:"",i=this.previewState==="loading"?'<div class="slm-ch-busy" role="status" data-ch-state="preview-loading">Asking the server what this audience sees\u2026</div>':"",a=this.previewState==="error"?`<div class="slm-ch-alert err" role="alert" data-ch-state="preview-error"><span>\u26A0</span>
420
415
  <span><b>Couldn't load the buyer preview.</b> Nothing is wrong with this audience's seats \u2014
421
416
  the simulation itself failed to load.
422
417
  <button type="button" data-ch-act="preview-retry">Try again</button></span></div>`:"",o=this.previewProjection?.available===!1?`<div class="slm-ch-alert warn" role="status"><span>\u23F8</span>
423
- <span><b>This private sale is not available.</b> ${h((this.previewProjection.unavailable??[]).map(p=>`${this.nameOf(p.channelId)??"This channel"} is ${p.state}`).join("; ")||"The audience cannot buy right now")}.
424
- A buyer arriving with this access sees this message, not these seats.</span></div>`:"",r=this.previewProjection?.counts?.eligible??this.previewProjection?.eligible?.length,d=r!=null&&this.previewProjection?.available!==!1?`<div class="slm-ch-alert info"><span>\u2713</span><span><b>${r.toLocaleString()} ${r===1?"seat is":"seats are"} available now.</b>
425
- This is the exact buyer-visible allocation.${this.previewProjection?.includePublic===!1?" Public sale seats are <b>not</b> included in this access.":""}</span></div>`:"",c=B(t)?"":`
418
+ <span><b>This private sale is not available.</b> ${p((this.previewProjection.unavailable??[]).map(h=>`${this.nameOf(h.channelId)??"This channel"} is ${h.state}`).join("; ")||"The audience cannot buy right now")}.
419
+ A buyer arriving with this access sees this message, not these seats.</span></div>`:"",r=this.previewProjection?.counts?.eligible??this.previewProjection?.eligible?.length,c=r!=null&&this.previewProjection?.available!==!1?`<div class="slm-ch-alert info"><span>\u2713</span><span><b>${r.toLocaleString()} ${r===1?"seat is":"seats are"} available now.</b>
420
+ This is the exact buyer-visible allocation.${this.previewProjection?.includePublic===!1?" Public sale seats are <b>not</b> included in this access.":""}</span></div>`:"",d=B(t)?"":`
426
421
  <label class="slm-note" style="display:flex;gap:8px;align-items:center;margin:10px 0">
427
422
  <input type="checkbox" data-ch-includepublic ${this.previewIncludePublic?"checked":""} />
428
423
  Also include Public sale seats in this grant
@@ -432,7 +427,7 @@
432
427
  <label for="slm-ch-audience">Audience</label>
433
428
  <select class="slm-select" id="slm-ch-audience" data-ch-audience>${s}</select>
434
429
  </div>
435
- ${c}
430
+ ${d}
436
431
  <p class="slm-hint">This is the same projection the buyer SDK receives for this audience \u2014 not a local
437
432
  approximation. It is read-only: clicks open seat details, and no holds are created.</p>
438
433
  ${i}${a}${n}${o}
@@ -441,12 +436,12 @@
441
436
  <div class="r"><span class="sw" style="background:#3a4051"></span> Unavailable to this audience (one neutral state)</div>
442
437
  <div class="r"><span class="sw" style="background:#22a06b"></span> Sold \u2014 same as any buyer sees</div>
443
438
  </div>
444
- ${d}`}paintSelection(){this.caps.manage&&this.host.selectionLabels().length&&(this.assignOpen=!0),this.view==="inspect"&&!this.detailChannelId&&this.paintRail()}wireRail(){let e=this.host.rail;e.querySelectorAll("[data-ch-view]").forEach(a=>{a.addEventListener("click",()=>this.setView(a.dataset.chView))}),e.querySelectorAll("[data-ch-map]").forEach(a=>{a.addEventListener("click",()=>{this.mapIntent=a.dataset.chMap==="assign"?"assign":"pan",this.mapIntent==="assign"&&(this.assignOpen=!0),this.paintRail(),this.onInteractionChange?.()})}),e.querySelectorAll("[data-ch-open]").forEach(a=>{let o=()=>this.openChannel(a.dataset.chOpen);a.addEventListener("click",o),a.addEventListener("keydown",r=>{r.key!=="Enter"&&r.key!==" "&&r.key!=="Spacebar"||(r.preventDefault(),o())})}),e.querySelectorAll("[data-ch-menu]").forEach(a=>{a.addEventListener("click",o=>{o.stopPropagation(),this.openDialog({kind:"menu",channelId:a.dataset.chMenu})}),a.addEventListener("keydown",o=>{o.stopPropagation()})}),e.querySelectorAll("[data-ch-rotate]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRotate",channelId:this.detailChannelId,linkId:a.dataset.chRotate}))}),e.querySelectorAll("[data-ch-revoke]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRevoke",channelId:this.detailChannelId,linkId:a.dataset.chRevoke}))});let t=e.querySelector("[data-ch-target]");t?.addEventListener("change",()=>{this.targetChannelId=t.value,this.conflict=!1,this.paintRail()});let s=e.querySelector("[data-ch-audience]");s?.addEventListener("change",()=>{this.previewAudience=[s.value],this.loadPreview()});let n=e.querySelector("[data-ch-includepublic]");n?.addEventListener("change",()=>{this.previewIncludePublic=n.checked,this.loadPreview()}),e.querySelector(".slm-ch-grab")?.addEventListener("click",()=>this.cycleDetent()),e.querySelectorAll("[data-ch-act]").forEach(a=>{a.addEventListener("click",()=>this.railAction(a.dataset.chAct))})}openChannel(e){this.detailChannelId=e,this.paintRail(),this.loadLinks(e).then(()=>this.paintRail())}railAction(e){switch(e){case"sections":this.focusedSectionId=null,this.host.showSectionOverview(),this.paintRail();break;case"create":this.openDialog({kind:"create"});break;case"review":this.openDialog({kind:"review"});break;case"rename":this.openDialog({kind:"rename",channelId:this.detailChannelId});break;case"pricing":this.openDialog({kind:"pricing",channelId:this.detailChannelId});break;case"archive":this.openDialog({kind:"archive",channelId:this.detailChannelId});break;case"seatlist":this.openDialog({kind:"seatlist"});break;case"pause":this.togglePause();break;case"discard":this.host.clearSelection();break;case"back":this.detailChannelId=null,this.linksChannelId=null,this.links=[],this.linksState="idle",this.paintRail();break;case"link-create":this.openDialog({kind:"linkCreate",channelId:this.detailChannelId});break;case"embed-code":this.chooseWebsiteIntegration();break;case"route-internal":this.setAccessIntent("internal");break;case"route-none":this.setAccessIntent("none");break;case"link-reload":this.detailChannelId&&this.reloadLinks();break;case"retry":this.refresh();break;case"toggle-archived":this.showArchived=!this.showArchived,this.refresh();break;case"refresh-review":this.conflict=!1,this.refresh().then(()=>this.openDialog({kind:"review"}));break;case"pick-sections":this.openDialog({kind:"scope",scope:"sections"});break;case"pick-rows":this.openDialog({kind:"scope",scope:"rows"});break;case"drag-select":this.mapIntent="assign",this.paintRail(),this.onInteractionChange?.();break;case"pick-category":this.pickCategory();break;case"assign-open":this.assignOpen=!0,this.paintRail();break;case"assign-close":this.assignOpen=!1,this.mapIntent="pan",this.paintRail(),this.onInteractionChange?.();break;case"preview-retry":this.loadPreview();break;default:break}}assignmentRows(){return this.assignmentRowsCache||(this.assignmentRowsCache=this.host.rows()),this.assignmentRowsCache}pickCategory(){let e=this.host.categories();e.length&&this.promptChoice("Select a whole category",e.map(t=>({value:t.key,label:t.label})),t=>{this.host.selectByLabels(this.host.labelsInCategory(t))})}promptChoice(e,t,s){this.renderScrim(`
445
- <h3 id="slm-ch-dlg-title">${h(e)}</h3>
439
+ ${c}`}paintSelection(){this.caps.manage&&this.host.selectionLabels().length&&(this.assignOpen=!0),this.view==="inspect"&&!this.detailChannelId&&this.paintRail()}wireRail(){let e=this.host.rail;e.querySelectorAll("[data-ch-view]").forEach(a=>{a.addEventListener("click",()=>this.setView(a.dataset.chView))}),e.querySelectorAll("[data-ch-map]").forEach(a=>{a.addEventListener("click",()=>{this.mapIntent=a.dataset.chMap==="assign"?"assign":"pan",this.mapIntent==="assign"&&(this.assignOpen=!0),this.paintRail(),this.onInteractionChange?.()})}),e.querySelectorAll("[data-ch-open]").forEach(a=>{let o=()=>this.openChannel(a.dataset.chOpen);a.addEventListener("click",o),a.addEventListener("keydown",r=>{r.key!=="Enter"&&r.key!==" "&&r.key!=="Spacebar"||(r.preventDefault(),o())})}),e.querySelectorAll("[data-ch-menu]").forEach(a=>{a.addEventListener("click",o=>{o.stopPropagation(),this.openDialog({kind:"menu",channelId:a.dataset.chMenu})}),a.addEventListener("keydown",o=>{o.stopPropagation()})}),e.querySelectorAll("[data-ch-rotate]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRotate",channelId:this.detailChannelId,linkId:a.dataset.chRotate}))}),e.querySelectorAll("[data-ch-revoke]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRevoke",channelId:this.detailChannelId,linkId:a.dataset.chRevoke}))});let t=e.querySelector("[data-ch-target]");t?.addEventListener("change",()=>{this.targetChannelId=t.value,this.conflict=!1,this.paintRail()});let s=e.querySelector("[data-ch-audience]");s?.addEventListener("change",()=>{this.previewAudience=[s.value],this.loadPreview()});let n=e.querySelector("[data-ch-includepublic]");n?.addEventListener("change",()=>{this.previewIncludePublic=n.checked,this.loadPreview()}),e.querySelector(".slm-ch-grab")?.addEventListener("click",()=>this.cycleDetent()),e.querySelectorAll("[data-ch-act]").forEach(a=>{a.addEventListener("click",()=>this.railAction(a.dataset.chAct))})}openChannel(e){this.detailChannelId=e,this.paintRail(),this.loadLinks(e).then(()=>this.paintRail())}railAction(e){switch(e){case"sections":this.focusedSectionId=null,this.host.showSectionOverview(),this.paintRail();break;case"create":this.openDialog({kind:"create"});break;case"review":this.openDialog({kind:"review"});break;case"rename":this.openDialog({kind:"rename",channelId:this.detailChannelId});break;case"pricing":this.openDialog({kind:"pricing",channelId:this.detailChannelId});break;case"archive":this.openDialog({kind:"archive",channelId:this.detailChannelId});break;case"seatlist":this.openDialog({kind:"seatlist"});break;case"pause":this.togglePause();break;case"discard":this.host.clearSelection();break;case"back":this.detailChannelId=null,this.linksChannelId=null,this.links=[],this.linksState="idle",this.paintRail();break;case"link-create":this.openDialog({kind:"linkCreate",channelId:this.detailChannelId});break;case"embed-code":this.chooseWebsiteIntegration();break;case"route-internal":this.setAccessIntent("internal");break;case"route-none":this.setAccessIntent("none");break;case"link-reload":this.detailChannelId&&this.reloadLinks();break;case"retry":this.refresh();break;case"toggle-archived":this.showArchived=!this.showArchived,this.refresh();break;case"refresh-review":this.conflict=!1,this.refresh().then(()=>this.openDialog({kind:"review"}));break;case"pick-sections":this.openDialog({kind:"scope",scope:"sections"});break;case"pick-rows":this.openDialog({kind:"scope",scope:"rows"});break;case"drag-select":this.mapIntent="assign",this.paintRail(),this.onInteractionChange?.();break;case"pick-category":this.pickCategory();break;case"assign-open":this.assignOpen=!0,this.mapIntent="assign",this.paintRail(),this.onInteractionChange?.();break;case"assign-close":this.assignOpen=!1,this.mapIntent="pan",this.paintRail(),this.onInteractionChange?.();break;case"preview-retry":this.loadPreview();break;default:break}}assignmentRows(){return this.assignmentRowsCache||(this.assignmentRowsCache=this.host.rows()),this.assignmentRowsCache}pickCategory(){let e=this.host.categories();e.length&&this.promptChoice("Select a whole category",e.map(t=>({value:t.key,label:t.label})),t=>{this.host.selectByLabels(this.host.labelsInCategory(t))})}promptChoice(e,t,s){this.renderScrim(`
440
+ <h3 id="slm-ch-dlg-title">${p(e)}</h3>
446
441
  <div class="slm-field">
447
442
  <label for="slm-ch-choice">Choose one</label>
448
443
  <select class="slm-select" id="slm-ch-choice">
449
- ${t.map(n=>`<option value="${h(n.value)}">${h(n.label)}</option>`).join("")}
444
+ ${t.map(n=>`<option value="${p(n.value)}">${p(n.label)}</option>`).join("")}
450
445
  </select>
451
446
  </div>
452
447
  <div class="foot">
@@ -465,26 +460,26 @@
465
460
  <div class="foot">
466
461
  <button type="button" class="quiet" data-ch-close>Cancel</button>
467
462
  <button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
468
- </div>`,r=>{let d=new Map(n.map(k=>[k.id,k])),c=new Set,p=new Set,m=new Set(this.host.selectionLabels()),v=r.querySelector("[data-ch-add-scope]"),g=r.querySelector("[data-ch-error]"),b=r.querySelector("[data-ch-scope-list]"),f=r.querySelector("[data-ch-scope-search]"),P=r.querySelector("[data-ch-scope-summary]"),H=r.querySelector("[data-ch-scope-filter]"),_=200,M="",S=()=>{let k=new Set(m);for(let D of c)for(let O of d.get(D)?.labels??[])k.add(O);return k},x=()=>{let k=S(),D=k.size-m.size,O=k.size>A;v.disabled=D===0||O,v.textContent=O?`Maximum ${A.toLocaleString()} seats`:`Add ${D.toLocaleString()} seat${D===1?"":"s"}`,g.hidden=!O,g.textContent=O?`That would make ${k.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:"",P.textContent=`${c.size.toLocaleString()} row${c.size===1?"":"s"} \xB7 ${D.toLocaleString()} seat${D===1?"":"s"} added`},w=()=>{let k=[],D=0,O=0;o.forEach(([E,$],G)=>{let j=E.toLocaleLowerCase(),N=M?$.filter(I=>`${j} ${I.label.toLocaleLowerCase()}`.includes(M)):$;if(M&&!N.length)return;D+=N.length;let _e=$.every(I=>c.has(I.id)),kt=!_e&&$.some(I=>c.has(I.id)),X=!!M||p.has(G),wt=Math.max(0,_-O),Q=X?N.slice(0,wt):[];O+=Q.length;let xt=$.reduce((I,St)=>I+St.labels.length,0);k.push(`<div class="slm-ch-scopegroup">
469
- <button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${_e?"true":kt?"mixed":"false"}"
470
- aria-label="Select all ${$.length.toLocaleString()} rows in ${h(E)}" data-ch-scope-group="${G}">
471
- <span class="box" aria-hidden="true">\u2713</span><span>${h(E)}</span>
472
- <span class="meta">${$.length.toLocaleString()} rows \xB7 ${xt.toLocaleString()} seats</span>
463
+ </div>`,r=>{let c=new Map(n.map(x=>[x.id,x])),d=new Set,h=new Set,u=new Set(this.host.selectionLabels()),f=r.querySelector("[data-ch-add-scope]"),v=r.querySelector("[data-ch-error]"),g=r.querySelector("[data-ch-scope-list]"),m=r.querySelector("[data-ch-scope-search]"),k=r.querySelector("[data-ch-scope-summary]"),R=r.querySelector("[data-ch-scope-filter]"),q=200,I="",C=()=>{let x=new Set(u);for(let D of d)for(let O of c.get(D)?.labels??[])x.add(O);return x},L=()=>{let x=C(),D=x.size-u.size,O=x.size>M;f.disabled=D===0||O,f.textContent=O?`Maximum ${M.toLocaleString()} seats`:`Add ${D.toLocaleString()} seat${D===1?"":"s"}`,v.hidden=!O,v.textContent=O?`That would make ${x.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:"",k.textContent=`${d.size.toLocaleString()} row${d.size===1?"":"s"} \xB7 ${D.toLocaleString()} seat${D===1?"":"s"} added`},w=()=>{let x=[],D=0,O=0;o.forEach(([H,$],X)=>{let _=H.toLocaleLowerCase(),V=I?$.filter(P=>`${_} ${P.label.toLocaleLowerCase()}`.includes(I)):$;if(I&&!V.length)return;D+=V.length;let Ve=$.every(P=>d.has(P.id)),$t=!Ve&&$.some(P=>d.has(P.id)),G=!!I||h.has(X),Et=Math.max(0,q-O),Z=G?V.slice(0,Et):[];O+=Z.length;let At=$.reduce((P,Mt)=>P+Mt.labels.length,0);x.push(`<div class="slm-ch-scopegroup">
464
+ <button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${Ve?"true":$t?"mixed":"false"}"
465
+ aria-label="Select all ${$.length.toLocaleString()} rows in ${p(H)}" data-ch-scope-group="${X}">
466
+ <span class="box" aria-hidden="true">\u2713</span><span>${p(H)}</span>
467
+ <span class="meta">${$.length.toLocaleString()} rows \xB7 ${At.toLocaleString()} seats</span>
473
468
  </button>
474
- <button type="button" class="slm-ch-grouptoggle" aria-expanded="${X}" aria-label="${X?"Hide":"Show"} rows in ${h(E)}"
475
- data-ch-scope-toggle="${G}">${X?"Hide":"Show"}</button>
476
- </div>`),k.push(...Q.map(I=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
477
- aria-checked="${c.has(I.id)}" data-ch-scope-id="${h(I.id)}">
478
- <span class="box" aria-hidden="true">\u2713</span><span>${h(I.label)}</span>
479
- <span class="meta">${I.labels.length.toLocaleString()} seat${I.labels.length===1?"":"s"}</span>
480
- </button>`)),X&&N.length>Q.length&&k.push(`<p class="slm-ch-scopehint">${(N.length-Q.length).toLocaleString()} more row${N.length-Q.length===1?"":"s"}. Search to narrow the list.</p>`)}),b.innerHTML=k.join("")||(M?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${h(M)}\u201D.</div>`:`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no rows with selectable seats.
481
- Use Drag box or the seat list instead.</div>`),H.textContent=M?`Showing ${O.toLocaleString()} of ${D.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",b.querySelectorAll("[data-ch-scope-group]").forEach(E=>E.addEventListener("click",()=>{let $=o[Number(E.dataset.chScopeGroup)]?.[1]??[],G=$.every(j=>c.has(j.id));for(let j of $)G?c.delete(j.id):c.add(j.id);w(),x()})),b.querySelectorAll("[data-ch-scope-toggle]").forEach(E=>E.addEventListener("click",()=>{let $=Number(E.dataset.chScopeToggle);p.has($)?p.delete($):p.add($),w()})),b.querySelectorAll("[data-ch-scope-id]").forEach(E=>E.addEventListener("click",()=>{let $=E.dataset.chScopeId;c.has($)?c.delete($):c.add($),w(),x()}))};f.addEventListener("input",()=>{M=f.value.trim().toLocaleLowerCase(),w(),x()}),v.addEventListener("click",()=>{let k=[...S()];!c.size||k.length>A||(this.closeDialog(),this.host.selectByLabels(k))}),w(),x()});return}let a=[...i.entries()].map(([o,r])=>`
482
- <div class="slm-ch-seatgroup"><span>${h(o)}</span></div>
483
- ${r.map(d=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
484
- aria-checked="false" data-ch-scope-id="${h(d.id)}">
469
+ <button type="button" class="slm-ch-grouptoggle" aria-expanded="${G}" aria-label="${G?"Hide":"Show"} rows in ${p(H)}"
470
+ data-ch-scope-toggle="${X}">${G?"Hide":"Show"}</button>
471
+ </div>`),x.push(...Z.map(P=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
472
+ aria-checked="${d.has(P.id)}" data-ch-scope-id="${p(P.id)}">
473
+ <span class="box" aria-hidden="true">\u2713</span><span>${p(P.label)}</span>
474
+ <span class="meta">${P.labels.length.toLocaleString()} seat${P.labels.length===1?"":"s"}</span>
475
+ </button>`)),G&&V.length>Z.length&&x.push(`<p class="slm-ch-scopehint">${(V.length-Z.length).toLocaleString()} more row${V.length-Z.length===1?"":"s"}. Search to narrow the list.</p>`)}),g.innerHTML=x.join("")||(I?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${p(I)}\u201D.</div>`:`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no rows with selectable seats.
476
+ Use Drag box or the seat list instead.</div>`),R.textContent=I?`Showing ${O.toLocaleString()} of ${D.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",g.querySelectorAll("[data-ch-scope-group]").forEach(H=>H.addEventListener("click",()=>{let $=o[Number(H.dataset.chScopeGroup)]?.[1]??[],X=$.every(_=>d.has(_.id));for(let _ of $)X?d.delete(_.id):d.add(_.id);w(),L()})),g.querySelectorAll("[data-ch-scope-toggle]").forEach(H=>H.addEventListener("click",()=>{let $=Number(H.dataset.chScopeToggle);h.has($)?h.delete($):h.add($),w()})),g.querySelectorAll("[data-ch-scope-id]").forEach(H=>H.addEventListener("click",()=>{let $=H.dataset.chScopeId;d.has($)?d.delete($):d.add($),w(),L()}))};m.addEventListener("input",()=>{I=m.value.trim().toLocaleLowerCase(),w(),L()}),f.addEventListener("click",()=>{let x=[...C()];!d.size||x.length>M||(this.closeDialog(),this.host.selectByLabels(x))}),w(),L()});return}let a=[...i.entries()].map(([o,r])=>`
477
+ <div class="slm-ch-seatgroup"><span>${p(o)}</span></div>
478
+ ${r.map(c=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
479
+ aria-checked="false" data-ch-scope-id="${p(c.id)}">
485
480
  <span class="box" aria-hidden="true">\u2713</span>
486
- <span>${h(d.label)}</span>
487
- <span class="meta">${d.labels.length.toLocaleString()} seat${d.labels.length===1?"":"s"}</span>
481
+ <span>${p(c.label)}</span>
482
+ <span class="meta">${c.labels.length.toLocaleString()} seat${c.labels.length===1?"":"s"}</span>
488
483
  </button>`).join("")}`).join("");this.renderScrim(`
489
484
  <h3 id="slm-ch-dlg-title">Add whole sections</h3>
490
485
  <p class="sub">Choose one or more. They are added to the seats already selected on the map.</p>
@@ -494,21 +489,21 @@
494
489
  <div class="foot">
495
490
  <button type="button" class="quiet" data-ch-close>Cancel</button>
496
491
  <button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
497
- </div>`,o=>{let r=new Map(n.map(b=>[b.id,b])),d=new Set,c=new Set(this.host.selectionLabels()),p=o.querySelector("[data-ch-add-scope]"),m=o.querySelector("[data-ch-error]"),v=()=>{let b=new Set(c);for(let f of d)for(let P of r.get(f)?.labels??[])b.add(P);return b},g=()=>{let b=v(),f=b.size-c.size,P=b.size>A;p.disabled=f===0||P,p.textContent=P?`Maximum ${A.toLocaleString()} seats`:`Add ${f.toLocaleString()} seat${f===1?"":"s"}`,m.hidden=!P,m.textContent=P?`That would make ${b.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""};o.querySelectorAll("[data-ch-scope-id]").forEach(b=>{b.addEventListener("click",()=>{let f=b.dataset.chScopeId;d.has(f)?d.delete(f):d.add(f),b.setAttribute("aria-checked",String(d.has(f))),g()})}),p.addEventListener("click",()=>{let b=[...v()];!d.size||b.length>A||(this.closeDialog(),this.host.selectByLabels(b))}),g()})}openDialog(e){this.dialog=e,this.renderDialog()}renderDialog(){let e=this.dialog;e&&(e.kind==="create"?this.renderCreateDialog(e):e.kind==="review"?this.renderReviewDialog(e):e.kind==="scope"?this.renderScopeDialog(e):e.kind==="archive"?this.renderArchiveDialog(e):e.kind==="rename"?this.renderRenameDialog(e):e.kind==="pricing"?this.renderPricingDialog(e):e.kind==="seatlist"?this.renderSeatListDialog():e.kind==="menu"?this.renderMenuDialog(e):e.kind==="linkCreate"?this.renderLinkCreateDialog(e):e.kind==="linkRotate"?this.renderLinkRotateDialog(e):e.kind==="linkRevoke"?this.renderLinkRevokeDialog(e):e.kind==="intentSwitch"&&this.renderIntentSwitchDialog(e))}renderIntentSwitchDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=e.intentTo;if(!t||!s||!this.caps.manage){this.closeDialog();return}let{headline:n,consequences:i}=ke(e.switchBlocked);this.renderScrim(`
498
- <h3 id="slm-ch-dlg-title">Change how ${h(t.name)} reaches buyers?</h3>
499
- <p class="sub">${h(n)}</p>
492
+ </div>`,o=>{let r=new Map(n.map(g=>[g.id,g])),c=new Set,d=new Set(this.host.selectionLabels()),h=o.querySelector("[data-ch-add-scope]"),u=o.querySelector("[data-ch-error]"),f=()=>{let g=new Set(d);for(let m of c)for(let k of r.get(m)?.labels??[])g.add(k);return g},v=()=>{let g=f(),m=g.size-d.size,k=g.size>M;h.disabled=m===0||k,h.textContent=k?`Maximum ${M.toLocaleString()} seats`:`Add ${m.toLocaleString()} seat${m===1?"":"s"}`,u.hidden=!k,u.textContent=k?`That would make ${g.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""};o.querySelectorAll("[data-ch-scope-id]").forEach(g=>{g.addEventListener("click",()=>{let m=g.dataset.chScopeId;c.has(m)?c.delete(m):c.add(m),g.setAttribute("aria-checked",String(c.has(m))),v()})}),h.addEventListener("click",()=>{let g=[...f()];!c.size||g.length>M||(this.closeDialog(),this.host.selectByLabels(g))}),v()})}openDialog(e){this.dialog=e,this.renderDialog()}renderDialog(){let e=this.dialog;e&&(e.kind==="create"?this.renderCreateDialog(e):e.kind==="review"?this.renderReviewDialog(e):e.kind==="scope"?this.renderScopeDialog(e):e.kind==="archive"?this.renderArchiveDialog(e):e.kind==="rename"?this.renderRenameDialog(e):e.kind==="pricing"?this.renderPricingDialog(e):e.kind==="seatlist"?this.renderSeatListDialog():e.kind==="menu"?this.renderMenuDialog(e):e.kind==="linkCreate"?this.renderLinkCreateDialog(e):e.kind==="linkRotate"?this.renderLinkRotateDialog(e):e.kind==="linkRevoke"?this.renderLinkRevokeDialog(e):e.kind==="intentSwitch"&&this.renderIntentSwitchDialog(e))}renderIntentSwitchDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=e.intentTo;if(!t||!s||!this.caps.manage){this.closeDialog();return}let{headline:n,consequences:i}=Le(e.switchBlocked);this.renderScrim(`
493
+ <h3 id="slm-ch-dlg-title">Change how ${p(t.name)} reaches buyers?</h3>
494
+ <p class="sub">${p(n)}</p>
500
495
  <div class="slm-ch-alert warn" role="alert"><span>\u26A0</span><span>
501
- ${i.map(a=>`<span style="display:block;margin-bottom:6px">${h(a)}</span>`).join("")}
496
+ ${i.map(a=>`<span style="display:block;margin-bottom:6px">${p(a)}</span>`).join("")}
502
497
  </span></div>
503
498
  ${e.pendingLink?`<p class="slm-note">Your new buyer link is created as soon as
504
499
  the route changes \u2014 you will not have to fill the form in again.</p>`:""}
505
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
500
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
506
501
  <div class="foot">
507
502
  <button type="button" class="quiet" data-ch-close>Leave it as it is</button>
508
503
  <button type="button" class="slm-btn" data-ch-intent-ack${e.busy?" disabled":""}>
509
- ${e.busy?"Changing\u2026":`Change to "${h(F(s))}"`}</button>
504
+ ${e.busy?"Changing\u2026":`Change to "${p(F(s))}"`}</button>
510
505
  </div>`,a=>{a.querySelector("[data-ch-intent-ack]")?.addEventListener("click",()=>{this.acknowledgeIntentSwitch(s,e.pendingLink??null)})})}async acknowledgeIntentSwitch(e,t){let s=this.detailChannelId;if(!s){this.closeDialog();return}if(this.dialog&&(this.dialog.busy=!0,this.renderDialog()),!await this.setAccessIntent(e,{acknowledgeLiveAccess:!0})){this.dialog?.kind==="intentSwitch"&&(this.dialog.busy=!1,this.renderDialog());return}if(!t){this.closeDialog();return}this.dialog?.kind==="intentSwitch"&&(this.dialog.busy=!1,this.renderDialog()),await this.mintLink(s,t)}renderScrim(e,t){let s=this.scrimEl;s||(this.lastFocus=document.activeElement??null),s?.remove();let n=document.createElement("div");n.className="slm-ch-scrim",n.innerHTML=`<div class="slm-ch-dialog" role="dialog" aria-modal="true"
511
- aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,this.host.root.appendChild(n),this.scrimEl=n;let i=n.firstElementChild;i.querySelectorAll("[data-ch-close]").forEach(o=>{o.addEventListener("click",()=>this.closeDialog())}),n.addEventListener("keydown",o=>{if(o.key==="Escape"){o.stopPropagation(),this.closeDialog();return}if(o.key!=="Tab")return;let r=[...i.querySelectorAll('button:not([disabled]),select,input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!r.length)return;let d=r[0],c=r[r.length-1];o.shiftKey&&document.activeElement===d?(o.preventDefault(),c.focus()):!o.shiftKey&&document.activeElement===c&&(o.preventDefault(),d.focus())}),t(i),(i.querySelector("input,select,button")??i).focus()}closeDialog(e={}){this.dialog=null,this.scrimEl?.remove(),this.scrimEl=null,e.restoreFocus!==!1&&this.lastFocus?.focus?.(),this.lastFocus=null}renderCreateDialog(e){let t=(this.list?.channels??[]).map(n=>z(n.marker||n.name,"")),s=J("",t);this.renderScrim(`
506
+ aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,this.host.root.appendChild(n),this.scrimEl=n;let i=n.firstElementChild;i.querySelectorAll("[data-ch-close]").forEach(o=>{o.addEventListener("click",()=>this.closeDialog())}),n.addEventListener("keydown",o=>{if(o.key==="Escape"){o.stopPropagation(),this.closeDialog();return}if(o.key!=="Tab")return;let r=[...i.querySelectorAll('summary,button:not([disabled]),select:not([hidden]),input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!r.length)return;let c=r[0],d=r[r.length-1];o.shiftKey&&document.activeElement===c?(o.preventDefault(),d.focus()):!o.shiftKey&&document.activeElement===d&&(o.preventDefault(),c.focus())}),t(i),ne(i),(i.querySelector("input,summary,button")??i).focus()}closeDialog(e={}){this.dialog=null,this.scrimEl?.remove(),this.scrimEl=null,e.restoreFocus!==!1&&this.lastFocus?.focus?.(),this.lastFocus=null}renderCreateDialog(e){let t=(this.list?.channels??[]).map(n=>z(n.marker||n.name,"")),s=Q("",t);this.renderScrim(`
512
507
  <h3 id="slm-ch-dlg-title">Create channel</h3>
513
508
  <p class="sub">A named allocation only the right audience can buy from. You'll pick the seats next.</p>
514
509
  <div class="slm-field">
@@ -519,7 +514,7 @@
519
514
  <div class="slm-field">
520
515
  <label>Marker</label>
521
516
  <div style="display:flex;gap:8px;align-items:center">
522
- <span class="slm-ch-mk" data-ch-marker style="background:${h(s.color)};width:28px;height:28px;font-size:13px">${h(s.letter)}</span>
517
+ <span class="slm-ch-mk" data-ch-marker style="background:${p(s.color)};width:28px;height:28px;font-size:13px">${p(s.letter)}</span>
523
518
  <span class="slm-note" style="margin:0">Letter comes from the name; colour is chosen automatically from the next available palette. Buyers never see either.</span>
524
519
  </div>
525
520
  </div>
@@ -528,32 +523,32 @@
528
523
  <input class="slm-input" id="slm-ch-ref" maxlength="120" placeholder="e.g. travel-agency-a" />
529
524
  <p class="slm-note">A stable ID for your own system and webhooks.</p>
530
525
  </div>
531
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
526
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
532
527
  <div class="foot">
533
528
  <button type="button" class="quiet" data-ch-close>Cancel</button>
534
529
  <button type="button" class="slm-btn ghost" data-ch-create="plain">Create without allocating</button>
535
530
  <button type="button" class="slm-btn" data-ch-create="allocate">Create and allocate seats</button>
536
- </div>`,n=>{let i=n.querySelector("#slm-ch-name"),a=n.querySelector("[data-ch-marker]");i.addEventListener("input",()=>{let o=J(i.value,t);a.textContent=o.letter,a.style.background=o.color}),n.querySelectorAll("[data-ch-create]").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.chCreate==="allocate";this.createChannel(i.value,a.textContent??"",a.style.background,n.querySelector("#slm-ch-ref")?.value??"",r)})})})}async createChannel(e,t,s,n,i){let a=e.trim();if(!a){this.showDialogError("Give the channel a name your team will recognise.");return}try{let o=await this.host.api.createChannel(this.host.eventKey,{name:a,marker:z(t,"")||null,color:s||null,externalRef:n.trim()||null});this.closeDialog(),await this.refresh(),this.targetChannelId=o.channel.id,this.detailChannelId=i?null:o.channel.id,this.announce(`Channel ${a} created with 0 seats allocated.`),this.host.toast(i?`${a} created. Select seats on the map to allocate them.`:`${a} created.`,"ok"),this.paintRail()}catch(o){let r=o instanceof y?o.code:void 0;this.showDialogError(r==="channel_name_taken"?"That name is already used on this event. Pick another.":"Couldn't create the channel. Try again."),this.host.onError(o)}}showDialogError(e){let t=this.scrimEl?.querySelector("[data-ch-error]");t&&(t.textContent=e,t.hidden=!1)}renderReviewDialog(e){let{labels:t,buckets:s}=this.currentPlan(),n=e.applied,i=n?n.buckets:s,a=this.nameOf(n?.targetChannelId??this.targetChannelId)??T,o=ge(i,a),r=n?n.applied:K(s),d=!n&&t.length>0&&r===0,c=!n&&t.length>A,p=W(o),m=n?'<div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>':`<div class="foot">
531
+ </div>`,n=>{let i=n.querySelector("#slm-ch-name"),a=n.querySelector("[data-ch-marker]");i.addEventListener("input",()=>{let o=Q(i.value,t);a.textContent=o.letter,a.style.background=o.color}),n.querySelectorAll("[data-ch-create]").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.chCreate==="allocate";this.createChannel(i.value,a.textContent??"",a.style.background,n.querySelector("#slm-ch-ref")?.value??"",r)})})})}async createChannel(e,t,s,n,i){let a=e.trim();if(!a){this.showDialogError("Give the channel a name your team will recognise.");return}try{let o=await this.host.api.createChannel(this.host.eventKey,{name:a,marker:z(t,"")||null,color:s||null,externalRef:n.trim()||null});this.closeDialog(),await this.refresh(),this.targetChannelId=o.channel.id,this.detailChannelId=i?null:o.channel.id,this.announce(`Channel ${a} created with 0 seats allocated.`),this.host.toast(i?`${a} created. Select seats on the map to allocate them.`:`${a} created.`,"ok"),this.paintRail()}catch(o){let r=o instanceof y?o.code:void 0;this.showDialogError(r==="channel_name_taken"?"That name is already used on this event. Pick another.":"Couldn't create the channel. Try again."),this.host.onError(o)}}showDialogError(e){let t=this.scrimEl?.querySelector("[data-ch-error]");t&&(t.textContent=e,t.hidden=!1)}renderReviewDialog(e){let{labels:t,buckets:s}=this.currentPlan(),n=e.applied,i=n?n.buckets:s,a=this.nameOf(n?.targetChannelId??this.targetChannelId)??A,o=ke(i,a),r=n?n.applied:K(s),c=!n&&t.length>0&&r===0,d=!n&&t.length>M,h=W(o),u=n?'<div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>':`<div class="foot">
537
532
  <button type="button" class="quiet" data-ch-close>Back</button>
538
- <button type="button" class="slm-btn" data-ch-apply ${d||c||e.busy?"disabled":""}>
533
+ <button type="button" class="slm-btn" data-ch-apply ${c||d||e.busy?"disabled":""}>
539
534
  ${e.busy?"Applying\u2026":`Apply ${r.toLocaleString()} change${r===1?"":"s"}`}
540
535
  </button>
541
- </div>`,v=!n&&be(s)?'<p class="slm-note">Applying moves inventory out of another private channel. That is the line marked above.</p>':"",g=d?`<div class="slm-ch-alert warn"><span>\u2139</span><span>Nothing in this selection can move right now \u2014
542
- every seat is in a buyer's checkout, already sold, or already in ${h(a)}.</span></div>`:"",b=c?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span><b>Choose fewer seats.</b>
543
- One Apply can cover at most ${A.toLocaleString()} seats.</span></div>`:"";this.renderScrim(`
544
- <h3 id="slm-ch-dlg-title">${n?`Moved ${n.applied.toLocaleString()} seat${n.applied===1?"":"s"} to ${h(a)}`:`Move ${t.length.toLocaleString()} selected seat${t.length===1?"":"s"} to ${h(a)}`}</h3>
536
+ </div>`,f=!n&&ye(s)?'<p class="slm-note">Applying moves inventory out of another private channel. That is the line marked above.</p>':"",v=c?`<div class="slm-ch-alert warn"><span>\u2139</span><span>Nothing in this selection can move right now \u2014
537
+ every seat is in a buyer's checkout, already sold, or already in ${p(a)}.</span></div>`:"",g=d?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span><b>Choose fewer seats.</b>
538
+ One Apply can cover at most ${M.toLocaleString()} seats.</span></div>`:"";this.renderScrim(`
539
+ <h3 id="slm-ch-dlg-title">${n?`Moved ${n.applied.toLocaleString()} seat${n.applied===1?"":"s"} to ${p(a)}`:`Move ${t.length.toLocaleString()} selected seat${t.length===1?"":"s"} to ${p(a)}`}</h3>
545
540
  <p class="sub">${n?"These are the exact counts the server applied.":"Every selected seat is in exactly one line below."}</p>
546
- ${g}
547
- ${b}
548
- ${p||'<div class="slm-empty">Nothing selected.</div>'}
549
541
  ${v}
550
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
551
- ${m}`,f=>{f.querySelector("[data-ch-apply]")?.addEventListener("click",()=>{this.apply()})}),n&&this.announce(`Applied ${n.applied} change${n.applied===1?"":"s"} to ${a}.`)}async apply(){if(!this.dialog||!this.caps.manage)return;let{labels:e}=this.currentPlan();if(e.length){if(e.length>A){this.showDialogError(`Choose at most ${A.toLocaleString()} seats for one Apply.`);return}this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{let t=await this.host.api.applyChannelAssignment(this.host.eventKey,{targetChannelId:B(this.targetChannelId)?null:this.targetChannelId,labels:e,assignmentVersion:this.assignmentVersion});this.assignmentVersion=t.assignmentVersion,this.conflict=!1,await this.refresh({quiet:!0}),this.closeDialog({restoreFocus:!1}),this.host.clearSelection(),this.showApplied(t)}catch(t){if(t instanceof y&&t.status===409&&t.code==="channel_assignment_conflict"){this.conflict=!0,this.closeDialog(),this.shakeStaged(),this.paintRail(),this.announce("Assignments changed while you were editing. Nothing was applied and your selection is kept.");return}if(t instanceof y&&t.status===403){this.caps={view:this.caps.view,manage:!1},this.closeDialog(),this.paintRail(),this.host.toast("Changing channels needs channel-management permission.","err");return}this.dialog={kind:"review",busy:!1,error:"Couldn't apply those changes. Try again."},this.renderDialog(),this.host.onError(t)}}}showApplied(e){let t=this.nameOf(e.targetChannelId)??T,s=e.buckets.skippedHeld.count+e.buckets.skippedBooked.count+e.buckets.notFound.count;this.setStaged(`<span class="slm-ch-tick" aria-hidden="true">\u2713</span>
552
- <span>Assigned <b>${e.applied.toLocaleString()}</b> seat${e.applied===1?"":"s"} to ${h(t)}
542
+ ${g}
543
+ ${h||'<div class="slm-empty">Nothing selected.</div>'}
544
+ ${f}
545
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
546
+ ${u}`,m=>{m.querySelector("[data-ch-apply]")?.addEventListener("click",()=>{this.apply()})}),n&&this.announce(`Applied ${n.applied} change${n.applied===1?"":"s"} to ${a}.`)}async apply(){if(!this.dialog||!this.caps.manage)return;let{labels:e}=this.currentPlan();if(e.length){if(e.length>M){this.showDialogError(`Choose at most ${M.toLocaleString()} seats for one Apply.`);return}this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{let t=await this.host.api.applyChannelAssignment(this.host.eventKey,{targetChannelId:B(this.targetChannelId)?null:this.targetChannelId,labels:e,assignmentVersion:this.assignmentVersion});this.assignmentVersion=t.assignmentVersion,this.conflict=!1,await this.refresh({quiet:!0}),this.closeDialog({restoreFocus:!1}),this.host.clearSelection(),this.showApplied(t)}catch(t){if(t instanceof y&&t.status===409&&t.code==="channel_assignment_conflict"){this.conflict=!0,this.closeDialog(),this.shakeStaged(),this.paintRail(),this.announce("Assignments changed while you were editing. Nothing was applied and your selection is kept.");return}if(t instanceof y&&t.status===403){this.caps={view:this.caps.view,manage:!1},this.closeDialog(),this.paintRail(),this.host.toast("Changing channels needs channel-management permission.","err");return}this.dialog={kind:"review",busy:!1,error:"Couldn't apply those changes. Try again."},this.renderDialog(),this.host.onError(t)}}}showApplied(e){let t=this.nameOf(e.targetChannelId)??A,s=e.buckets.skippedHeld.count+e.buckets.skippedBooked.count+e.buckets.notFound.count;this.setStaged(`<span class="slm-ch-tick" aria-hidden="true">\u2713</span>
547
+ <span>Assigned <b>${e.applied.toLocaleString()}</b> seat${e.applied===1?"":"s"} to ${p(t)}
553
548
  ${s?` \xB7 ${s.toLocaleString()} skipped`:""}</span>
554
549
  <span class="grow"></span>
555
550
  <button type="button" class="drop" data-ch-applied-details>Details</button>`,"done"),this.stagedEl?.querySelector("[data-ch-applied-details]")?.addEventListener("click",()=>{this.openDialog({kind:"review",applied:e})}),this.announce(`Assigned ${e.applied} seat${e.applied===1?"":"s"} to ${t}${s?`; ${s} skipped`:""}.`),this.stagedDoneTimer&&clearTimeout(this.stagedDoneTimer),this.stagedDoneTimer=setTimeout(()=>this.setStaged(null),5e3)}shakeStaged(){let e=this.stagedEl;!e||!e.classList.contains("on")||(e.classList.remove("shake"),e.offsetWidth,e.classList.add("shake"))}renderMenuDialog(e){let t=this.list?.channels.find(n=>n.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.state==="paused";this.renderScrim(`
556
- <h3 id="slm-ch-dlg-title">${h(t.name)}</h3>
551
+ <h3 id="slm-ch-dlg-title">${p(t.name)}</h3>
557
552
  <p class="sub">Open the channel to allocate seats and hand out buyer access.
558
553
  These are the rest of its actions.</p>
559
554
  <div class="slm-ch-menu">
@@ -566,72 +561,72 @@
566
561
  Archiving closes the channel for good and returns its free seats to a destination you choose.
567
562
  Nothing is ever deleted silently.</p>
568
563
  <div class="foot"><button type="button" class="quiet" data-ch-close>Cancel</button></div>`,n=>{n.querySelectorAll("[data-ch-menu-act]").forEach(i=>{i.addEventListener("click",()=>{let a=i.dataset.chMenuAct;if(a==="open"){this.closeDialog(),this.openChannel(t.id);return}if(a==="rename"){this.openDialog({kind:"rename",channelId:t.id});return}if(a==="archive"){this.openDialog({kind:"archive",channelId:t.id});return}this.closeDialog(),this.togglePause(t.id)})})})}renderRenameDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t){this.closeDialog();return}this.renderScrim(`
569
- <h3 id="slm-ch-dlg-title">Rename ${h(t.name)}</h3>
564
+ <h3 id="slm-ch-dlg-title">Rename ${p(t.name)}</h3>
570
565
  <p class="sub">Only your team and your reports see this name.</p>
571
566
  <div class="slm-field">
572
567
  <label for="slm-ch-newname">Name</label>
573
- <input class="slm-input" id="slm-ch-newname" maxlength="80" value="${h(t.name)}" />
568
+ <input class="slm-input" id="slm-ch-newname" maxlength="80" value="${p(t.name)}" />
574
569
  </div>
575
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
570
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
576
571
  <div class="foot">
577
572
  <button type="button" class="quiet" data-ch-close>Cancel</button>
578
573
  <button type="button" class="slm-btn" data-ch-rename>Save name</button>
579
- </div>`,s=>{s.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let n=s.querySelector("#slm-ch-newname")?.value??"";if(!n.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,n.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(i=>{this.showDialogError(i instanceof y&&i.code==="channel_name_taken"?"That name is already used on this event.":"Couldn't rename the channel."),this.host.onError(i)})})})}renderPricingDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=this.host.api.updateChannelPricing;if(!t||!s||!this.caps.manage){this.closeDialog();return}let n=new Map((t.priceOverrides??[]).map(a=>[`${a.categoryKey}\0${a.tierId??""}`,a.price])),i=this.host.categories().flatMap(a=>(a.tiers?.length?a.tiers:[null]).map(r=>{let d=r?.id??null,c=`${a.key}\0${d??""}`,p=r?.price??a.price??0,m=n.get(c),v=r?`${a.label} \xB7 ${r.name}`:a.label;return`<label class="slm-ch-price-row">
580
- <span><b>${h(v)}</b><small>Event price ${h(String(p))}</small></span>
574
+ </div>`,s=>{s.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let n=s.querySelector("#slm-ch-newname")?.value??"";if(!n.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,n.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(i=>{this.showDialogError(i instanceof y&&i.code==="channel_name_taken"?"That name is already used on this event.":"Couldn't rename the channel."),this.host.onError(i)})})})}renderPricingDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=this.host.api.updateChannelPricing;if(!t||!s||!this.caps.manage){this.closeDialog();return}let n=new Map((t.priceOverrides??[]).map(a=>[`${a.categoryKey}\0${a.tierId??""}`,a.price])),i=this.host.categories().flatMap(a=>(a.tiers?.length?a.tiers:[null]).map(r=>{let c=r?.id??null,d=`${a.key}\0${c??""}`,h=r?.price??a.price??0,u=n.get(d),f=r?`${a.label} \xB7 ${r.name}`:a.label;return`<label class="slm-ch-price-row">
575
+ <span><b>${p(f)}</b><small>Event price ${p(String(h))}</small></span>
581
576
  <input class="slm-input" type="number" min="0" max="1000000" step="0.01"
582
- inputmode="decimal" aria-label="Custom price for ${h(v)}"
583
- data-ch-price-category="${h(a.key)}" data-ch-price-tier="${h(d??"")}"
584
- placeholder="${h(String(p))}" value="${m===void 0?"":h(String(m))}"
577
+ inputmode="decimal" aria-label="Custom price for ${p(f)}"
578
+ data-ch-price-category="${p(a.key)}" data-ch-price-tier="${p(c??"")}"
579
+ placeholder="${p(String(h))}" value="${u===void 0?"":p(String(u))}"
585
580
  ${e.busy?"disabled":""} />
586
581
  </label>`})).join("");this.renderScrim(`
587
- <h3 id="slm-ch-dlg-title">Prices for ${h(t.name)}</h3>
582
+ <h3 id="slm-ch-dlg-title">Prices for ${p(t.name)}</h3>
588
583
  <p class="sub">Set only the prices that differ for this audience. Leave a field blank to use the event price.</p>
589
584
  <div class="slm-ch-price-list">${i||'<p class="slm-empty">This event has no priced categories.</p>'}</div>
590
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
585
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
591
586
  <div class="foot">
592
587
  <button type="button" class="quiet" data-ch-close ${e.busy?"disabled":""}>Cancel</button>
593
588
  <button type="button" class="slm-btn" data-ch-price-save ${e.busy||!i?"disabled":""}>
594
589
  ${e.busy?"Saving\u2026":"Save prices"}
595
590
  </button>
596
- </div>`,a=>{a.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let o=[];for(let r of a.querySelectorAll("[data-ch-price-category]")){let d=r.value.trim();if(!d)continue;let c=Number(d);if(!Number.isFinite(c)||c<0||c>1e6){r.focus(),this.showDialogError("Enter a price from 0 to 1,000,000, or leave the field blank.");return}o.push({categoryKey:r.dataset.chPriceCategory,tierId:r.dataset.chPriceTier||null,price:c})}this.saveChannelPricing(t,o)})})}async saveChannelPricing(e,t){let s=this.host.api.updateChannelPricing;if(!(!s||!this.dialog||this.dialog.kind!=="pricing")){this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{await s.call(this.host.api,this.host.eventKey,e.id,t,e.pricingVersion??0),this.closeDialog(),await this.refresh(),this.host.toast(t.length?`Custom prices saved for ${e.name}.`:`${e.name} now uses event prices.`,"ok")}catch(n){if(n instanceof y&&n.code==="channel_pricing_conflict"){await this.refresh({quiet:!0}),this.dialog={kind:"pricing",channelId:e.id,error:"Prices changed in another window. Latest values are shown \u2014 review and save again."},this.renderDialog();return}this.dialog={kind:"pricing",channelId:e.id,error:n instanceof y&&n.serverMessage?n.serverMessage:"Couldn't save these prices. Try again."},this.renderDialog(),this.host.onError(n)}}}async chooseWebsiteIntegration(){this.detailChannelId&&await this.setAccessIntent("server")}async setAccessIntent(e,t={}){let s=this.detailChannelId;if(!s||!this.caps.manage)return!1;try{let n=await this.host.api.setChannelAccessIntent(this.host.eventKey,s,e,t);return await this.refresh(),this.host.toast(this.intentSavedCopy(e,n?.intentSwitch),"ok"),!0}catch(n){return n instanceof y&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:s,intentTo:e,switchBlocked:n.details}),!1):n instanceof y&&n.code==="channel_access_intent_forbids"?(this.host.toast(Y(n.details),"err"),!1):(this.host.toast("Couldn't change how this channel reaches buyers.","err"),this.host.onError(n),!1)}}intentSavedCopy(e,t){let s=e==="server"?"Set to your website or app. The embed code is on the Embed page.":e==="internal"?"Only your own staff can sell this channel now.":e==="hosted_link"?"Set to buyer links. Create one to let buyers in.":"Kept as a protected reserve. No route can sell these seats.";if(!t)return s;let n=t.closedLinks?` ${t.closedLinks.toLocaleString()} buyer link${t.closedLinks===1?"":"s"} closed.`:"",i=t.keptSessions?` ${t.keptSessions.toLocaleString()} buyer${t.keptSessions===1?"":"s"} already in a checkout can still finish.`:"";return`${s}${n}${i}`}async togglePause(e=this.detailChannelId){let t=this.list?.channels.find(n=>n.id===e);if(!t||!this.caps.manage)return;let s=t.state!=="paused";try{await this.host.api.setChannelPaused(this.host.eventKey,t.id,s),await this.refresh(),this.host.toast(s?`${t.name} paused. Existing checkouts can finish; no new buyer access is issued.`:`${t.name} resumed.`,"ok")}catch(n){this.host.toast("Couldn't change that channel.","err"),this.host.onError(n)}}renderArchiveDialog(e){let t=this.list?.channels.find(o=>o.id===e.channelId);if(!t){this.closeDialog();return}let s=e.archiveBlocked??null,n=!s&&t.counts.held>0,i=this.assignableChannels().filter(o=>o.id!==t.id),a=s?`<div class="slm-ch-alert warn" role="alert"><span>\u23F3</span>
591
+ </div>`,a=>{a.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let o=[];for(let r of a.querySelectorAll("[data-ch-price-category]")){let c=r.value.trim();if(!c)continue;let d=Number(c);if(!Number.isFinite(d)||d<0||d>1e6){r.focus(),this.showDialogError("Enter a price from 0 to 1,000,000, or leave the field blank.");return}o.push({categoryKey:r.dataset.chPriceCategory,tierId:r.dataset.chPriceTier||null,price:d})}this.saveChannelPricing(t,o)})})}async saveChannelPricing(e,t){let s=this.host.api.updateChannelPricing;if(!(!s||!this.dialog||this.dialog.kind!=="pricing")){this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{await s.call(this.host.api,this.host.eventKey,e.id,t,e.pricingVersion??0),this.closeDialog(),await this.refresh(),this.host.toast(t.length?`Custom prices saved for ${e.name}.`:`${e.name} now uses event prices.`,"ok")}catch(n){if(n instanceof y&&n.code==="channel_pricing_conflict"){await this.refresh({quiet:!0}),this.dialog={kind:"pricing",channelId:e.id,error:"Prices changed in another window. Latest values are shown \u2014 review and save again."},this.renderDialog();return}this.dialog={kind:"pricing",channelId:e.id,error:n instanceof y&&n.serverMessage?n.serverMessage:"Couldn't save these prices. Try again."},this.renderDialog(),this.host.onError(n)}}}async chooseWebsiteIntegration(){this.detailChannelId&&await this.setAccessIntent("server")}async setAccessIntent(e,t={}){let s=this.detailChannelId;if(!s||!this.caps.manage)return!1;try{let n=await this.host.api.setChannelAccessIntent(this.host.eventKey,s,e,t);return await this.refresh(),this.host.toast(this.intentSavedCopy(e,n?.intentSwitch),"ok"),!0}catch(n){return n instanceof y&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:s,intentTo:e,switchBlocked:n.details}),!1):n instanceof y&&n.code==="channel_access_intent_forbids"?(this.host.toast(Y(n.details),"err"),!1):(this.host.toast("Couldn't change how this channel reaches buyers.","err"),this.host.onError(n),!1)}}intentSavedCopy(e,t){let s=e==="server"?"Set to your website or app. The embed code is on the Embed page.":e==="internal"?"Only your own staff can sell this channel now.":e==="hosted_link"?"Set to buyer links. Create one to let buyers in.":"Kept as a protected reserve. No route can sell these seats.";if(!t)return s;let n=t.closedLinks?` ${t.closedLinks.toLocaleString()} buyer link${t.closedLinks===1?"":"s"} closed.`:"",i=t.keptSessions?` ${t.keptSessions.toLocaleString()} buyer${t.keptSessions===1?"":"s"} already in a checkout can still finish.`:"";return`${s}${n}${i}`}async togglePause(e=this.detailChannelId){let t=this.list?.channels.find(n=>n.id===e);if(!t||!this.caps.manage)return;let s=t.state!=="paused";try{await this.host.api.setChannelPaused(this.host.eventKey,t.id,s),await this.refresh(),this.host.toast(s?`${t.name} paused. Existing checkouts can finish; no new buyer access is issued.`:`${t.name} resumed.`,"ok")}catch(n){this.host.toast("Couldn't change that channel.","err"),this.host.onError(n)}}renderArchiveDialog(e){let t=this.list?.channels.find(o=>o.id===e.channelId);if(!t){this.closeDialog();return}let s=e.archiveBlocked??null,n=!s&&t.counts.held>0,i=this.assignableChannels().filter(o=>o.id!==t.id),a=s?`<div class="slm-ch-alert warn" role="alert"><span>\u23F3</span>
597
592
  <span><b>${(s.heldUnits??s.activeHolds??0).toLocaleString()} seats are in a buyer's checkout right now.</b>
598
- Archive is unavailable while seats are held \u2014 try again ${h(ve(s))}.</span></div>`:n?`<div class="slm-ch-alert warn"><span>\u23F3</span>
593
+ Archive is unavailable while seats are held \u2014 try again ${p(xe(s))}.</span></div>`:n?`<div class="slm-ch-alert warn"><span>\u23F3</span>
599
594
  <span>${t.counts.held.toLocaleString()} seats are in a buyer's checkout right now.
600
595
  Archive is refused while any seat is held \u2014 you can try, and we'll tell you when to come back.</span></div>`:"";this.renderScrim(`
601
- <h3 id="slm-ch-dlg-title">Archive ${h(t.name)}</h3>
596
+ <h3 id="slm-ch-dlg-title">Archive ${p(t.name)}</h3>
602
597
  <p class="sub">The channel closes for good. Its seats move to a destination you choose;
603
598
  sales history keeps its attribution.</p>
604
599
  ${a}
605
600
  <div class="slm-field">
606
601
  <label for="slm-ch-dest">Move the ${t.counts.free.toLocaleString()} remaining free seats to</label>
607
602
  <select class="slm-select" id="slm-ch-dest">
608
- ${i.map(o=>`<option value="${h(o.id)}">${h(o.name)}</option>`).join("")}
603
+ ${i.map(o=>`<option value="${p(o.id)}">${p(o.name)}</option>`).join("")}
609
604
  </select>
610
605
  </div>
611
- <p class="slm-note">${t.counts.booked.toLocaleString()} sold seats keep "${h(t.name)}" on their sale
606
+ <p class="slm-note">${t.counts.booked.toLocaleString()} sold seats keep "${p(t.name)}" on their sale
612
607
  record. If one is cancelled later it returns to the destination above. Any buyer access for this channel
613
608
  stops working.</p>
614
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
609
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
615
610
  <div class="foot">
616
611
  <button type="button" class="quiet" data-ch-close>Cancel</button>
617
612
  <button type="button" class="slm-btn danger" data-ch-archive ${s?"disabled":""}>Archive channel</button>
618
613
  </div>`,o=>{o.querySelector("[data-ch-archive]")?.addEventListener("click",()=>{let r=o.querySelector("#slm-ch-dest")?.value??"";this.archive(t.id,r||null)})})}async archive(e,t){try{await this.host.api.archiveChannel(this.host.eventKey,e,t),this.closeDialog(),this.detailChannelId=null,await this.refresh(),this.host.toast("Channel archived. Its remaining seats moved to the destination you chose.","ok")}catch(s){if(s instanceof y&&s.status===409&&s.code==="channel_archive_blocked_by_holds"){this.dialog={kind:"archive",channelId:e,archiveBlocked:s.details??{}},this.renderDialog();return}this.showDialogError("Couldn't archive that channel. Try again."),this.host.onError(s)}}renderSeatListDialog(){let e=new Set(this.host.selectionLabels()),t=new Map,s=0;for(let i of this.host.seats()){if(s+=1,s>this.seatListLimit)break;let a=this.host.sectionOfLabel(i.label),o=a?.id??"",r=t.get(o)??{label:a?.label??"Other seats",seats:[]};r.seats.push({label:i.label,status:this.host.statusOf(i.label)??"free"}),t.set(o,r)}let n=[...t.entries()].map(([i,a])=>`
619
614
  <div class="slm-ch-seatgroup">
620
- <span>${h(a.label)}</span>
621
- ${i?`<button type="button" data-ch-section="${h(i)}">Select section</button>`:""}
615
+ <span>${p(a.label)}</span>
616
+ ${i?`<button type="button" data-ch-section="${p(i)}">Select section</button>`:""}
622
617
  </div>
623
- ${a.seats.map(o=>{let r=this.allocation.get(o.label)??C,d=this.nameOf(r)??T;return`<button type="button" class="slm-ch-seatitem" role="checkbox"
624
- aria-checked="${e.has(o.label)}" data-ch-seat="${h(o.label)}">
618
+ ${a.seats.map(o=>{let r=this.allocation.get(o.label)??T,c=this.nameOf(r)??A;return`<button type="button" class="slm-ch-seatitem" role="checkbox"
619
+ aria-checked="${e.has(o.label)}" data-ch-seat="${p(o.label)}">
625
620
  <span class="box" aria-hidden="true">\u2713</span>
626
- <span>${h(o.label)}</span>
627
- <span class="meta">${h(d)} \xB7 ${h(o.status)}</span>
621
+ <span>${p(o.label)}</span>
622
+ <span class="meta">${p(c)} \xB7 ${p(o.status)}</span>
628
623
  </button>`}).join("")}`).join("");this.renderScrim(`
629
624
  <h3 id="slm-ch-dlg-title">Seat list</h3>
630
625
  <p class="sub">The same selection as the map, with checkboxes. Space or Enter toggles a seat.</p>
631
626
  <div class="slm-ch-seatlist">${n||'<div class="slm-empty">No seats on this chart.</div>'}</div>
632
627
  ${s>this.seatListLimit?'<div class="foot"><button type="button" class="slm-btn ghost" data-ch-more>Show more seats</button></div>':""}
633
- <div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>`,i=>{i.querySelectorAll("[data-ch-seat]").forEach(a=>{a.addEventListener("click",()=>{let o=a.dataset.chSeat,r=new Set(this.host.selectionLabels());r.has(o)?r.delete(o):r.add(o),this.host.clearSelection(),r.size&&this.host.selectByLabels([...r]),this.renderSeatListDialog()})}),i.querySelectorAll("[data-ch-section]").forEach(a=>{a.addEventListener("click",()=>{this.host.selectSection(a.dataset.chSection),this.renderSeatListDialog()})}),i.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=gt,this.renderSeatListDialog()})})}async reloadLinks(){let e=this.detailChannelId;e&&(this.linksState=this.links.length?this.linksState:"loading",await this.loadLinks(e),this.paintRail())}async reloadAfterLinkChange(e){if(this.detailChannelId===e){await this.refresh({quiet:!0});return}await this.loadLinks(e),this.active&&this.paintRail()}linkById(e){return this.links.find(t=>t.id===e)??null}renderLinkCreateDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}this.renderScrim(`
634
- <h3 id="slm-ch-dlg-title">Create a buyer link for ${h(t.name)}</h3>
628
+ <div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>`,i=>{i.querySelectorAll("[data-ch-seat]").forEach(a=>{a.addEventListener("click",()=>{let o=a.dataset.chSeat,r=new Set(this.host.selectionLabels());r.has(o)?r.delete(o):r.add(o),this.host.clearSelection(),r.size&&this.host.selectByLabels([...r]),this.renderSeatListDialog()})}),i.querySelectorAll("[data-ch-section]").forEach(a=>{a.addEventListener("click",()=>{this.host.selectSection(a.dataset.chSection),this.renderSeatListDialog()})}),i.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=St,this.renderSeatListDialog()})})}async reloadLinks(){let e=this.detailChannelId;e&&(this.linksState=this.links.length?this.linksState:"loading",await this.loadLinks(e),this.paintRail())}async reloadAfterLinkChange(e){if(this.detailChannelId===e){await this.refresh({quiet:!0});return}await this.loadLinks(e),this.active&&this.paintRail()}linkById(e){return this.links.find(t=>t.id===e)??null}renderLinkCreateDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}this.renderScrim(`
629
+ <h3 id="slm-ch-dlg-title">Create a buyer link for ${p(t.name)}</h3>
635
630
  <p class="sub">Anyone who opens the link can buy from this channel's allocation \u2014 and only from it.
636
631
  You'll see the link once, right after you create it.</p>
637
632
  <div class="slm-field">
@@ -653,30 +648,30 @@
653
648
  <div class="slm-field">
654
649
  <label for="slm-ch-lk-redemptions">How many people can use it</label>
655
650
  <input class="slm-input" type="number" id="slm-ch-lk-redemptions" inputmode="numeric"
656
- value="${ee.maxRedemptions}" />
651
+ value="${J.maxRedemptions}" />
657
652
  <p class="slm-note">Each buyer who opens the link uses one.</p>
658
653
  </div>
659
654
  <div class="slm-field">
660
655
  <label for="slm-ch-lk-quantity">Seats per buyer</label>
661
656
  <input class="slm-input" type="number" id="slm-ch-lk-quantity" inputmode="numeric"
662
- value="${ee.maxQuantity}" />
657
+ value="${J.maxQuantity}" />
663
658
  </div>
664
659
  <label class="slm-note" style="display:flex;gap:8px;align-items:center;margin:2px 0 6px">
665
660
  <input type="checkbox" id="slm-ch-lk-public" />
666
661
  Also let this link buy Public sale seats
667
662
  </label>
668
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
663
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
669
664
  <div class="foot">
670
665
  <button type="button" class="quiet" data-ch-close>Cancel</button>
671
666
  <button type="button" class="slm-btn" data-ch-lk-create>Create link</button>
672
- </div>`,s=>{let n=s.querySelector("[data-ch-lk-expiry]"),i=s.querySelector("[data-ch-lk-when-field]"),a=s.querySelector("#slm-ch-lk-when");n.addEventListener("change",()=>{let o=n.value==="custom";i.hidden=!o,o&&!a.value&&(a.value=ht(Date.now()+7*864e5))}),s.querySelector("[data-ch-lk-create]")?.addEventListener("click",()=>{let o=Oe(s,"#slm-ch-lk-redemptions"),r=Oe(s,"#slm-ch-lk-quantity");if(o==null||r==null){this.showDialogError("Those two settings need to be whole numbers.");return}let d;if(n.value==="custom"&&(d=Date.parse(a.value),!Number.isFinite(d))){this.showDialogError("Pick the date and time the link should stop working.");return}this.createLink(t.id,{label:s.querySelector("#slm-ch-lk-label")?.value.trim()||null,includePublic:s.querySelector("#slm-ch-lk-public")?.checked??!1,...d===void 0?{}:{expiresAt:d},maxRedemptions:o,maxQuantity:r})})})}async createLink(e,t){await this.ensureHostedLinkRoute(e,t)&&await this.mintLink(e,t)}async mintLink(e,t){try{let s=await this.host.api.createAccessLink(this.host.eventKey,e,t);this.revealLink(s,{channelId:e}),await this.reloadAfterLinkChange(e)}catch(s){this.showDialogError(q(s instanceof y?s:void 0)),s instanceof y||this.host.onError(s)}}async ensureHostedLinkRoute(e,t){if((this.list?.channels.find(n=>n.id===e)?.access?.intent??"none")==="hosted_link")return!0;try{return await this.host.api.setChannelAccessIntent(this.host.eventKey,e,"hosted_link"),await this.refresh(),!0}catch(n){return n instanceof y&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:e,intentTo:"hosted_link",switchBlocked:n.details,pendingLink:t}),!1):(this.showDialogError(n instanceof y&&n.code==="channel_access_intent_forbids"?Y(n.details):"Couldn't set this channel up for buyer links. Try again."),n instanceof y||this.host.onError(n),!1)}}revealLink(e,t){let s=e.url;this.dialog=null;let n=t.rotated?`<div class="slm-ch-alert warn" role="status"><span>\u26A0</span><span>
673
- <b>The old link has stopped working.</b> ${e.endedSessions?`${e.endedSessions.toLocaleString()} buyer${e.endedSessions===1?"":"s"} lost access immediately.`:"Buyers who already came in can finish; every new visit needs this link."}</span></div>`:"",i=se(e.link).map(a=>`<div class="slm-ch-lkrow"><span class="k">${h(a.k)}</span>
674
- <span class="v">${h(a.v)}</span></div>`).join("");this.renderScrim(`
667
+ </div>`,s=>{let n=s.querySelector("[data-ch-lk-expiry]"),i=s.querySelector("[data-ch-lk-when-field]"),a=s.querySelector("#slm-ch-lk-when");n.addEventListener("change",()=>{let o=n.value==="custom";i.hidden=!o,o&&!a.value&&(a.value=ft(Date.now()+7*864e5))}),s.querySelector("[data-ch-lk-create]")?.addEventListener("click",()=>{let o=je(s,"#slm-ch-lk-redemptions"),r=je(s,"#slm-ch-lk-quantity");if(o==null||r==null){this.showDialogError("Those two settings need to be whole numbers.");return}let c;if(n.value==="custom"&&(c=Date.parse(a.value),!Number.isFinite(c))){this.showDialogError("Pick the date and time the link should stop working.");return}this.createLink(t.id,{label:s.querySelector("#slm-ch-lk-label")?.value.trim()||null,includePublic:s.querySelector("#slm-ch-lk-public")?.checked??!1,...c===void 0?{}:{expiresAt:c},maxRedemptions:o,maxQuantity:r})})})}async createLink(e,t){await this.ensureHostedLinkRoute(e,t)&&await this.mintLink(e,t)}async mintLink(e,t){try{let s=await this.host.api.createAccessLink(this.host.eventKey,e,t);this.revealLink(s,{channelId:e}),await this.reloadAfterLinkChange(e)}catch(s){this.showDialogError(N(s instanceof y?s:void 0)),s instanceof y||this.host.onError(s)}}async ensureHostedLinkRoute(e,t){if((this.list?.channels.find(n=>n.id===e)?.access?.intent??"none")==="hosted_link")return!0;try{return await this.host.api.setChannelAccessIntent(this.host.eventKey,e,"hosted_link"),await this.refresh(),!0}catch(n){return n instanceof y&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:e,intentTo:"hosted_link",switchBlocked:n.details,pendingLink:t}),!1):(this.showDialogError(n instanceof y&&n.code==="channel_access_intent_forbids"?Y(n.details):"Couldn't set this channel up for buyer links. Try again."),n instanceof y||this.host.onError(n),!1)}}revealLink(e,t){let s=e.url;this.dialog=null;let n=t.rotated?`<div class="slm-ch-alert warn" role="status"><span>\u26A0</span><span>
668
+ <b>The old link has stopped working.</b> ${e.endedSessions?`${e.endedSessions.toLocaleString()} buyer${e.endedSessions===1?"":"s"} lost access immediately.`:"Buyers who already came in can finish; every new visit needs this link."}</span></div>`:"",i=te(e.link).map(a=>`<div class="slm-ch-lkrow"><span class="k">${p(a.k)}</span>
669
+ <span class="v">${p(a.v)}</span></div>`).join("");this.renderScrim(`
675
670
  <h3 id="slm-ch-dlg-title">Copy this link now</h3>
676
671
  <p class="sub">This is the only time SeatLayer can show it. We keep just a fingerprint, so it cannot be
677
672
  shown again \u2014 if it is lost, rotate the link for a fresh one.</p>
678
673
  ${n}
679
- <div class="slm-ch-secret" data-ch-lk-url>${h(s)}</div>
674
+ <div class="slm-ch-secret" data-ch-lk-url>${p(s)}</div>
680
675
  <div class="slm-ch-row2" style="margin-top:8px">
681
676
  <button type="button" class="slm-btn" data-ch-lk-copy>Copy link</button>
682
677
  </div>
@@ -687,10 +682,10 @@
687
682
  ${i}
688
683
  <div class="foot">
689
684
  <button type="button" class="slm-btn" data-ch-close data-ch-lk-done>I've copied it</button>
690
- </div>`,a=>{let o=a.querySelector("[data-ch-lk-copy]");o?.addEventListener("click",()=>{let r=()=>{o.textContent="Copied",this.announce("Buyer link copied.")},d=typeof navigator>"u"?null:navigator.clipboard;if(d?.writeText){d.writeText(s).then(r,()=>ze(a));return}ze(a)})}),this.announce("Your buyer link is ready and is shown once.")}renderLinkRotateDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0,n=s?`<div class="slm-ch-alert warn"><span>\u26A0</span>
685
+ </div>`,a=>{let o=a.querySelector("[data-ch-lk-copy]");o?.addEventListener("click",()=>{let r=()=>{o.textContent="Copied",this.announce("Buyer link copied.")},c=typeof navigator>"u"?null:navigator.clipboard;if(c?.writeText){c.writeText(s).then(r,()=>Ne(a));return}Ne(a)})}),this.announce("Your buyer link is ready and is shown once.")}renderLinkRotateDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0,n=s?`<div class="slm-ch-alert warn"><span>\u26A0</span>
691
686
  <span><b>${s.toLocaleString()} buyer${s===1?"":"s"}</b> got in with the current link
692
687
  and still ${s===1?"has":"have"} active access.</span></div>`:"";this.renderScrim(`
693
- <h3 id="slm-ch-dlg-title">Rotate the ${h(t.label||"buyer")} link?</h3>
688
+ <h3 id="slm-ch-dlg-title">Rotate the ${p(t.label||"buyer")} link?</h3>
694
689
  <p class="sub">The current link stops opening immediately and cannot be restored. You will get a new
695
690
  link to copy \u2014 shown once.</p>
696
691
  ${n}
@@ -705,12 +700,12 @@
705
700
  Buyers part-way through choosing seats lose access.</span></span>
706
701
  </label>
707
702
  <p class="slm-note">Choose one \u2014 SeatLayer will not decide this for you.</p>
708
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
703
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
709
704
  <div class="foot">
710
705
  <button type="button" class="quiet" data-ch-close>Cancel</button>
711
706
  <button type="button" class="slm-btn" data-ch-lk-rotate disabled>Rotate and copy new link</button>
712
- </div>`,i=>{let a=i.querySelector("[data-ch-lk-rotate]");i.querySelectorAll("[data-ch-rot]").forEach(o=>{o.addEventListener("change",()=>{a.disabled=!1})}),a.addEventListener("click",()=>{let o=[...i.querySelectorAll("[data-ch-rot]")].find(r=>r.checked);if(!o){this.showDialogError(q({code:"end_active_sessions_required"}));return}this.rotateLink(e.channelId,t.id,o.value==="end")})})}async rotateLink(e,t,s){try{let n=await this.host.api.rotateAccessLink(this.host.eventKey,e,t,s);this.revealLink(n,{channelId:e,rotated:!0}),await this.reloadAfterLinkChange(e)}catch(n){this.showDialogError(q(n instanceof y?n:void 0)),n instanceof y||this.host.onError(n)}}renderLinkRevokeDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0;this.renderScrim(`
713
- <h3 id="slm-ch-dlg-title">Revoke the ${h(t.label||"buyer")} link?</h3>
707
+ </div>`,i=>{let a=i.querySelector("[data-ch-lk-rotate]");i.querySelectorAll("[data-ch-rot]").forEach(o=>{o.addEventListener("change",()=>{a.disabled=!1})}),a.addEventListener("click",()=>{let o=[...i.querySelectorAll("[data-ch-rot]")].find(r=>r.checked);if(!o){this.showDialogError(N({code:"end_active_sessions_required"}));return}this.rotateLink(e.channelId,t.id,o.value==="end")})})}async rotateLink(e,t,s){try{let n=await this.host.api.rotateAccessLink(this.host.eventKey,e,t,s);this.revealLink(n,{channelId:e,rotated:!0}),await this.reloadAfterLinkChange(e)}catch(n){this.showDialogError(N(n instanceof y?n:void 0)),n instanceof y||this.host.onError(n)}}renderLinkRevokeDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0;this.renderScrim(`
708
+ <h3 id="slm-ch-dlg-title">Revoke the ${p(t.label||"buyer")} link?</h3>
714
709
  <p class="sub">It stops opening immediately and cannot be restored \u2014 there is no undo, and no way to
715
710
  bring the same URL back. Seats already bought through it keep their sale.</p>
716
711
  ${s?`<label class="slm-ch-radio">
@@ -719,11 +714,20 @@
719
714
  buyer${s===1?"":"s"} already inside</b><span class="why">Leave this off and they can
720
715
  finish what they started; new visits are refused either way.</span></span>
721
716
  </label>`:""}
722
- <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${h(e.error??"")}</p>
717
+ <p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${p(e.error??"")}</p>
723
718
  <div class="foot">
724
719
  <button type="button" class="quiet" data-ch-close>Cancel</button>
725
720
  <button type="button" class="slm-btn danger" data-ch-lk-revoke>Revoke link</button>
726
- </div>`,n=>{n.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let i=n.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,i)})})}async revokeLink(e,t,s){try{let n=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,s);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(n.endedSessions?`Link revoked. ${n.endedSessions.toLocaleString()} buyer${n.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(n){this.showDialogError(q(n instanceof y?n:void 0)),n instanceof y||this.host.onError(n)}}applySheetClasses(){let e=this.host.root,t=this.host.isCompact();e.classList.toggle("ch-sheet",t&&this.active);for(let s of["collapsed","medium","full"])e.classList.toggle(`detent-${s}`,t&&this.active&&this.detent===s);this.host.setMapInert(t&&this.active&&this.detent==="full")}cycleDetent(){let e=["collapsed","medium","full"];this.detent=e[(e.indexOf(this.detent)+1)%e.length],this.applySheetClasses()}handleBack(){return this.scrimEl?(this.closeDialog(),!0):this.host.isCompact()&&this.detent==="full"?(this.detent="medium",this.applySheetClasses(),!0):!1}}});var es={};qe(es,{ACCESS_LINK_DEFAULTS:()=>ee,ChannelsMode:()=>ne,ManageApi:()=>U,ManageApiError:()=>y,PUBLIC_CHANNEL_ID:()=>C,PUBLIC_CHANNEL_NAME:()=>T,SeatManager:()=>$e,accessIntentDescription:()=>ye,accessIntentLabel:()=>F,accessLine:()=>fe,accessLinkBadge:()=>we,accessLinkErrorCopy:()=>q,accessLinkIsLive:()=>te,accessLinkPolicyLines:()=>se,bucketRows:()=>ge,bucketRowsHtml:()=>W,dropReviewRows:()=>ct,intentForbidsCopy:()=>Y,intentSwitchBlockedCopy:()=>ke,isPublicChannelId:()=>B,markerLetter:()=>z,markerOf:()=>pe,mutationCount:()=>K,needsMoveConfirmation:()=>be,planAssignment:()=>me,retryAfterCopy:()=>ve,selectionSources:()=>ue,stateBadge:()=>xe,suggestMarker:()=>J});module.exports=Tt(es);var L=require("@seatlayer/core");ae();var It=/^[a-zA-Z0-9._-]+$/;function Pt(l){let e;try{e=new URL(l,"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]),n=decodeURIComponent(t[2]);return!s||!It.test(n)?null:{eventKey:s,asset:n}}catch{return null}}function Ht(l){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(l,"https://seatlayer.invalid").pathname)}catch{return!1}}var oe=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=Pt(e);if(!t)return Promise.resolve(Ht(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,n=this.pending.get(s);if(n)return n;let i=this.load(t.eventKey,t.asset).then(a=>{let o=URL.createObjectURL(a);return this.disposed?(URL.revokeObjectURL(o),null):(this.created.add(o),o)}).catch(a=>{throw this.pending.delete(s),a});return this.pending.set(s,i),i}async prepareRendererChart(e){let t=async i=>{if(!i?.url)return;let a=await this.resolve(i.url);if(!a)throw new Error("organizer_event_asset_scope_mismatch");i.url=a},s=async i=>{for(let a of i){if(a.type!=="decorImage")continue;let o=a,r=await this.resolve(o.href);if(!r)throw new Error("organizer_event_asset_scope_mismatch");o.href=r}},n=async i=>{await t(i.backgroundImage),await s(i.objects)};await n(e);for(let i of e.floors??[])await n(i);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 Ue="seatlayer-manager-style",Ke="seatlayer-manager-channels-style",Bt=`
721
+ </div>`,n=>{n.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let i=n.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,i)})})}async revokeLink(e,t,s){try{let n=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,s);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(n.endedSessions?`Link revoked. ${n.endedSessions.toLocaleString()} buyer${n.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(n){this.showDialogError(N(n instanceof y?n:void 0)),n instanceof y||this.host.onError(n)}}applySheetClasses(){let e=this.host.root,t=this.host.isCompact();e.classList.toggle("ch-sheet",t&&this.active);for(let s of["collapsed","medium","full"])e.classList.toggle(`detent-${s}`,t&&this.active&&this.detent===s);this.host.setMapInert(t&&this.active&&this.detent==="full")}cycleDetent(){let e=["collapsed","medium","full"];this.detent=e[(e.indexOf(this.detent)+1)%e.length],this.applySheetClasses()}handleBack(){return this.scrimEl?(this.closeDialog(),!0):this.host.isCompact()&&this.detent==="full"?(this.detent="medium",this.applySheetClasses(),!0):!1}}});var rs={};Ue(rs,{ACCESS_LINK_DEFAULTS:()=>J,ChannelsMode:()=>se,ManageApi:()=>U,ManageApiError:()=>y,PUBLIC_CHANNEL_ID:()=>T,PUBLIC_CHANNEL_NAME:()=>A,SeatManager:()=>Ae,accessIntentDescription:()=>Se,accessIntentLabel:()=>F,accessLine:()=>we,accessLinkBadge:()=>Ce,accessLinkErrorCopy:()=>N,accessLinkIsLive:()=>ee,accessLinkPolicyLines:()=>te,bucketRows:()=>ke,bucketRowsHtml:()=>W,dropReviewRows:()=>gt,intentForbidsCopy:()=>Y,intentSwitchBlockedCopy:()=>Le,isPublicChannelId:()=>B,markerLetter:()=>z,markerOf:()=>ge,mutationCount:()=>K,needsMoveConfirmation:()=>ye,planAssignment:()=>fe,retryAfterCopy:()=>xe,selectionSources:()=>ve,stateBadge:()=>Te,suggestMarker:()=>Q});module.exports=Dt(rs);Ie();var Ke={hold:"Held",release:"Released",expire:"Expired",book:"Booked",unbook:"Cancelled",block:"Blocked",unblock:"Unblocked"},ie=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 n=await this.fetchPage(e?this.next:void 0,this.action);if(this.closed||s!==this.generation)return;if(this.paintCounts(n),t&&this.entries.length&&n.entries[0]?.id!==this.entries[0]?.id&&this.list.scrollTop>24){this.latest.hidden=!1;return}let i=!t||n.entries[0]?.id!==this.entries[0]?.id;e?(this.entries=[...this.entries,...n.entries.filter(a=>!this.entries.some(o=>o.id===a.id))],this.next=n.nextBefore):i&&(this.entries=n.entries,this.next=n.nextBefore),i&&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 n=document.createElement("button");n.className="slm-btn ghost",n.textContent="Retry",n.onclick=()=>{this.load(e)},this.message.append(n)}}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:n})=>{let i=document.createElement("button");return i.type="button",i.textContent=s?`${Ke[s]??s} ${n}`:`${n} changes`,i.setAttribute("aria-pressed",String((this.action??"")===s)),i.onclick=()=>{this.busy||(this.action=s||void 0,this.entries=[],this.next=null,this.list.scrollTop=0,this.latest.hidden=!0,this.load())},i}))}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 n=document.createElement("time");n.dateTime=new Date(t.at).toISOString(),n.textContent=new Date(t.at).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),n.title=new Date(t.at).toString();let i=document.createElement("strong");return i.textContent=Ke[t.action]??t.action,s.append(n,i),s})),this.list.scrollTop=e}};var Ot={held:"HOLD",booked:"BOOK",expired:"EXPIRE",released:"RELEASE",cancelled:"CANCEL",blocked:"BLOCK",unblocked:"ON SALE",available:"FREE"},Ye={held:"Held",booked:"Booked",expired:"Hold expired",released:"Hold released",cancelled:"Booking cancelled",blocked:"Blocked",unblocked:"Back on sale",available:"Available again"},ae=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 n={signal:this.abort.signal},i=()=>{this.paused=!1,this.signature="unrendered",this.list.scrollTop=0,this.render()};this.list.addEventListener("scroll",()=>{this.list.scrollTop>24&&(this.paused=!0)},n),this.list.addEventListener("focusin",()=>{this.paused=!0},n),this.list.addEventListener("toggle",a=>{a.target.open&&(this.paused=!0)},{...n,capture:!0}),this.newer.addEventListener("click",i,n),this.more.addEventListener("click",()=>{this.limit=200,this.signature="unrendered",this.render(!0)},n)}update(e){this.items=e,this.render()}render(e=!1){let t=this.items,s=t.filter(a=>!this.shown.has(a.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 n=t.slice(0,this.limit),i=n.map(a=>`${a.id}:${a.verb}`).join("|");if(i!==this.signature){if(this.signature=i,this.shown=new Set(t.map(a=>a.id)),this.list.replaceChildren(),!n.length){let a=document.createElement("p");a.className="slm-activity-empty",a.textContent=this.items.length?"No activity matches these filters.":"Waiting for activity. Holds, bookings and releases will appear here.",this.list.append(a)}for(let a of n){let o=document.createElement("article");o.className="slm-activity-entry",o.dataset.status=a.status;let r=document.createElement("button");r.type="button",r.className="slm-activity-row";let c=`${Ye[a.verb]??a.verb} \xB7 ${a.count} seat${a.count===1?"":"s"} \xB7 ${a.sectionLabels?.join(", ")||"Event inventory"} \xB7 ${a.labels.join(", ")} \xB7 ${new Date(a.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(a.id));let d=document.createElement("time");d.dateTime=new Date(a.at).toISOString(),d.textContent=new Date(a.at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let h=document.createElement("strong");h.textContent=Ot[a.verb]??a.verb,h.title=Ye[a.verb]??a.verb;let u=document.createElement("span");if(u.className="slm-activity-seats",u.textContent=a.labels.join(", "),r.append(d,h,u),o.append(r),a.count>1){let f=document.createElement("details");f.className="slm-activity-details";let v=document.createElement("summary");v.textContent="\u22EF",v.setAttribute("aria-label",`Show all ${a.count} seats`);let g=document.createElement("p");g.textContent=c,f.append(v,g),o.append(f)}this.list.append(o)}this.more.hidden=t.length<=this.limit}}destroy(){this.abort.abort()}};var oe=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=m=>`<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">${m}</svg>`,n=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"/>'),i=s('<path d="m5 3 14 10-7 1-3 7-4-18Z"/>'),a=s('<circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/>'),o=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">
722
+ <button type="button" data-nav="move" aria-label="Move" aria-pressed="false" title="Drag to move the map; hold Space temporarily">${n}</button>
723
+ <button type="button" data-nav="select" aria-label="Select" aria-pressed="true" title="Drag to select seats">${i}</button>
724
+ <button type="button" data-nav="search" aria-label="Search" title="Search seats, rows or sections" aria-expanded="false">${a}</button>
725
+ <button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${o}</button>
726
+ <button type="button" hidden data-nav="out" aria-label="Zoom out">\u2212</button>
727
+ <button type="button" hidden data-nav="in" aria-label="Zoom in">+</button>
728
+ <span class="slm-navigation-count" role="status" aria-live="polite">0 selected</span>
729
+ <button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${r}</button>
730
+ </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},d=t.querySelector('[data-nav="search"]'),h=t.querySelector(".slm-navigation-search"),u=()=>{h.hidden=!0,this.results.hidden=!0,d.setAttribute("aria-expanded","false"),d.focus()};d.addEventListener("click",()=>{let m=h.hidden;h.hidden=!m,d.setAttribute("aria-expanded",String(m)),m&&this.search.focus()},c);let f=t.querySelector('[data-nav="zoom"]');f.addEventListener("click",()=>{let m=f.getAttribute("aria-expanded")!=="true";f.setAttribute("aria-expanded",String(m));for(let k of["in","out"])t.querySelector(`[data-nav="${k}"]`).hidden=!m},c),this.search.addEventListener("keydown",m=>{m.key==="Escape"&&u()},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 v=t.querySelector('[data-nav="rail"]');v.addEventListener("click",()=>{let m=e.root.classList.toggle("details-hidden");v.setAttribute("aria-expanded",String(!m)),v.setAttribute("aria-label",m?"Show details":"Hide details"),v.title=m?"Show details":"Hide details"},c),this.search.addEventListener("input",()=>this.find(),c),this.search.addEventListener("keydown",m=>{m.key==="Escape"&&(this.results.hidden=!0),m.key==="ArrowDown"&&(m.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",m=>{m.target?.closest('input,textarea,select,button,[contenteditable="true"]')||m.code!=="Space"||m.ctrlKey||m.metaKey||m.altKey||(m.preventDefault(),this.space||(this.space=!0,e.pauseFollow(),e.setMoving(!0)))},c);let g=()=>{this.space&&(this.space=!1,e.setMoving(this.moving))};window.addEventListener("keyup",m=>{m.code==="Space"&&g()},c),window.addEventListener("blur",g,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",m=>{e.root.contains(m.relatedTarget)||g()},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 n=document.createElement("button");n.type="button",n.textContent=`${s.label} \xB7 ${s.detail}`,n.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(n)}t.length||(this.results.textContent="No matching section, row or seat.")}destroy(){this.abort.abort(),this.bar.remove(),this.location.remove()}};var S=require("@seatlayer/core");re();var jt=/^[a-zA-Z0-9._-]+$/;function Nt(l){let e;try{e=new URL(l,"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]),n=decodeURIComponent(t[2]);return!s||!jt.test(n)?null:{eventKey:s,asset:n}}catch{return null}}function _t(l){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(l,"https://seatlayer.invalid").pathname)}catch{return!1}}var ce=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=Nt(e);if(!t)return Promise.resolve(_t(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,n=this.pending.get(s);if(n)return n;let i=this.load(t.eventKey,t.asset).then(a=>{let o=URL.createObjectURL(a);return this.disposed?(URL.revokeObjectURL(o),null):(this.created.add(o),o)}).catch(a=>{throw this.pending.delete(s),a});return this.pending.set(s,i),i}async prepareRendererChart(e){let t=async i=>{if(!i?.url)return;let a=await this.resolve(i.url);if(!a)throw new Error("organizer_event_asset_scope_mismatch");i.url=a},s=async i=>{for(let a of i){if(a.type!=="decorImage")continue;let o=a,r=await this.resolve(o.href);if(!r)throw new Error("organizer_event_asset_scope_mismatch");o.href=r}},n=async i=>{await t(i.backgroundImage),await s(i.objects)};await n(e);for(let i of e.floors??[])await n(i);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 Ze="seatlayer-manager-style",Qe="seatlayer-manager-channels-style",Vt=`
727
731
  /* The floor was 480px, which trapped the cockpit in any host shorter than that:
728
732
  every ancestor here is overflow:hidden, so the bottom of the rail (Create
729
733
  channel, Show archived) was rendered but clipped away by the host and could
@@ -743,6 +747,73 @@
743
747
  .slm button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
744
748
  .slm input{font:inherit}
745
749
 
750
+ .slm .slm-btn:not(.ghost):not(.danger){background:var(--slm-accent);color:var(--slm-accent-ink);border:1px solid var(--slm-accent)}
751
+ /* Navigation remains available without changing the inventory tool. */
752
+ .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}
753
+ .slm-navigation>*{pointer-events:auto}
754
+ .slm .slm-navigation-tools button{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;min-width:34px;padding:0}
755
+ .slm-navigation-tools svg{pointer-events:none;flex:none}
756
+ .slm-navigation-tools{padding:3px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-bg);box-shadow:0 1px 3px #00000012}
757
+ .slm-navigation-tools{display:flex;gap:2px;align-items:center;flex-wrap:wrap}
758
+ .slm-navigation-count{font-size:12px;color:var(--slm-muted);padding:0 6px;white-space:nowrap}
759
+ .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}
760
+ .slm .slm-navigation button[aria-pressed="true"]{background:var(--slm-accent);color:var(--slm-accent-ink)}
761
+ /* Toolbar controls are flat; search result buttons retain their own layout. */
762
+ .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}
763
+ .slm .slm-navigation .slm-navigation-tools button:hover{background:var(--slm-tint);color:var(--slm-text)}
764
+ .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)}
765
+ .slm .slm-navigation .slm-navigation-tools button[data-nav=rail]{margin-left:4px;position:relative}
766
+ .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)}
767
+ .slm .slm-navigation .slm-navigation-tools button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
768
+ .slm-navigation button[hidden]{display:none}
769
+ .slm-navigation-search{position:relative;width:300px;max-width:100%;min-width:0;box-shadow:0 2px 8px #0002}
770
+ .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}
771
+ .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}
772
+ .slm-navigation-results button{display:block;width:100%;text-align:left;margin-bottom:3px}
773
+ .slm.details-hidden .slm-rail{display:none}
774
+ .slm button:focus-visible,.slm input:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
775
+ .slm[data-theme="light"] .slm-scope.read{color:#465169}
776
+ .slm[data-theme="light"] .slm-scope.event,.slm[data-theme="light"] .slm-tablelock,.slm[data-theme="light"] .slm-kpidelta.down{color:#805500!important}
777
+ .slm[data-theme="light"] .slm-barbtn.follow.on,.slm[data-theme="light"] .slm-kpidelta{color:#17663f!important}
778
+
779
+
780
+ .slm [hidden]{display:none!important}
781
+ .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}
782
+ .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)}
783
+ .slm-monitor-head{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:8px}
784
+ .slm-monitor-head h2{font-size:17px;letter-spacing:-.3px}
785
+ .slm-monitor-connection{font-size:12px;color:var(--slm-muted)}
786
+ .slm.live .slm-monitor-connection{color:#168153}
787
+ .slm-monitor-tabs{display:flex;border-bottom:1px solid var(--slm-line);margin-bottom:6px;gap:16px}
788
+ .slm .slm-monitor-tabs button{padding:0 0 7px;font-size:12px;color:var(--slm-muted);border-bottom:2px solid transparent}
789
+ .slm .slm-monitor-tabs button[aria-selected="true"]{color:var(--slm-text);border-color:var(--slm-accent);font-weight:700}
790
+ .slm-activity-filters{display:flex;gap:6px;margin-bottom:6px}
791
+ .slm-activity-filters label{flex:1;min-width:0;font-size:11px;color:var(--slm-muted)}
792
+ .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}
793
+ .slm.monitor-view .slm-railscroll{display:flex;flex-direction:column;overflow:hidden}
794
+ .slm-monitor-head,.slm-monitor-tabs,.slm-activity-filters{flex:none}
795
+ .slm-monitor-activity,.slm-monitor-activity>[data-ref="feed"]{display:flex;flex-direction:column;flex:1;min-height:0}
796
+ .slm [data-monitor-panel="sections"]{overflow:auto;min-height:0}
797
+ .slm-activity-list{overflow:auto;flex:1;min-height:0;scrollbar-gutter:stable}
798
+
799
+ .slm-activity-entry{position:relative;border-bottom:1px solid var(--slm-line);display:flex;align-items:flex-start;min-width:0}
800
+ .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}
801
+ .slm .slm-activity-row:hover{background:var(--slm-surface)}
802
+ .slm-activity-row time{font-size:10px;color:var(--slm-muted);font-variant-numeric:tabular-nums;white-space:nowrap}
803
+ .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}
804
+ .slm-activity-entry[data-status="held"] strong{background:#b780171a;color:#946000}
805
+ .slm-activity-entry[data-status="booked"] strong{background:#1681531a;color:#14764d}
806
+ .slm[data-theme="dark"] .slm-activity-entry[data-status="held"] strong{background:#f2b44020;color:#f2bd59}
807
+ .slm[data-theme="dark"] .slm-activity-entry[data-status="booked"] strong{background:#2dc88d20;color:#6ed9ab}
808
+ .slm-activity-seats{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--slm-text);min-width:0}
809
+ .slm-activity-details{flex:none;font-size:11px}
810
+ .slm-activity-details summary{cursor:pointer;list-style:none;padding:6px 3px;color:var(--slm-muted)}
811
+ .slm-activity-details summary::-webkit-details-marker{display:none}
812
+ .slm-activity-details[open]{padding-bottom:68px}
813
+ .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}
814
+ .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)}
815
+ .slm .slm-new-activity{background:var(--slm-accent);color:var(--slm-accent-ink)}
816
+ .slm-activity-empty{padding:22px 4px;color:var(--slm-muted);font-size:13px;line-height:1.6}
746
817
  /* top bar */
747
818
  /* FOUR columns, because the bar has four children: modes, the tools
748
819
  select, the live badge, and the actions. With three, the actions had no
@@ -791,6 +862,11 @@
791
862
  @keyframes slm-kpi-delta{0%{opacity:0;transform:translateY(5px)}18%,72%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-5px)}}
792
863
  .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}
793
864
  .slm-barbtn:hover{border-color:var(--slm-muted)}
865
+ .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)}
866
+ .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)}
867
+ .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)}
868
+ .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}
869
+ .slm-heat-status{bottom:48px}
794
870
  .slm-barbtn.follow.on{background:rgba(34,160,107,.13);border-color:#22a06b;color:#5bd39b}
795
871
 
796
872
  /* body */
@@ -798,7 +874,7 @@
798
874
  .slm-map{position:relative;flex:1;min-width:0}
799
875
  .slm-map-host{position:absolute;inset:0}
800
876
  .slm-hud{position:absolute;left:12px;bottom:12px;display:flex;gap:8px}
801
- .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
877
+ .slm .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
802
878
  border:1px solid var(--slm-line);color:var(--slm-text)}
803
879
  .slm-zoomhint{position:absolute;left:50%;top:14px;transform:translateX(-50%);padding:6px 13px;border-radius:999px;
804
880
  background:rgba(0,0,0,.55);color:#fff;font-size:12px;font-weight:700;pointer-events:none;opacity:0;
@@ -816,13 +892,13 @@
816
892
  .slm-rail{width:320px;flex:none;border-left:1px solid var(--slm-line);display:flex;flex-direction:column;min-height:0}
817
893
  .slm-railscroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px}
818
894
  .slm-eyebrow{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--slm-muted);font-weight:800;margin-bottom:6px}
819
- .slm-hint{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}
895
+ .slm-hint{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:8px}
820
896
  /* rail header: title + scope badge, then one plain sentence \u2014 every tool opens the same way */
821
897
  .slm-railhead{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:6px}
822
898
  .slm-railhead .slm-eyebrow{margin-bottom:0;font-size:11px;color:var(--slm-text)}
823
899
  .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}
824
- .slm-scope.read{background:rgba(139,148,172,.16);color:#c2c9d8}
825
- .slm-scope.event{background:rgba(244,183,64,.16);color:#f7ca6b}
900
+ .slm-scope.read{background:rgba(139,148,172,.16);color:var(--slm-text)}
901
+ .slm-scope.event{background:rgba(244,183,64,.16);color:var(--slm-text)}
826
902
  .slm-scope.host{background:color-mix(in srgb,var(--slm-accent) 18%,transparent);color:var(--slm-accent)}
827
903
  .slm-step{display:flex;align-items:center;gap:7px}
828
904
  .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}
@@ -850,7 +926,7 @@
850
926
  .slm-empty{font-size:12.5px;color:var(--slm-muted);padding:12px 0}
851
927
 
852
928
  /* block toolbar */
853
- .slm-selbar{display:flex;align-items:baseline;gap:8px;margin-bottom:10px}
929
+ .slm-selbar{display:flex;align-items:baseline;gap:6px;margin-bottom:6px}
854
930
  .slm-selnum{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums}
855
931
  .slm-sellabel{font-size:12px;color:var(--slm-muted);font-weight:600}
856
932
  .slm-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
@@ -888,7 +964,15 @@
888
964
  color:var(--slm-muted);font-size:10.5px}
889
965
  .slm-linkbtn{font-size:11px!important;font-weight:800!important;color:var(--slm-accent)!important;text-align:right}
890
966
  .slm-linkbtn:disabled{opacity:.45;cursor:not-allowed}
891
- .slm-blockedlist{max-height:246px;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
967
+ .slm .slm-blockedsummary .slm-linkbtn{color:var(--slm-text)}
968
+ .slm-block-seatline{display:flex;align-items:center}
969
+ .slm .slm-block-seatline>button:last-child{color:var(--slm-text);font-size:11px;padding:7px;background:transparent;border:0;cursor:pointer}
970
+ .slm-block-group{border-bottom:1px solid var(--slm-line);padding:7px}
971
+ .slm-block-grouphead{display:flex;align-items:center;justify-content:space-between;gap:8px}
972
+ .slm .slm-block-grouphead button{color:var(--slm-text);font-size:11px;text-align:left;padding:4px;background:transparent;border:0;cursor:pointer}
973
+ .slm-block-grouphead small{display:block;color:var(--slm-muted);font-size:10px;margin-top:3px}
974
+ .slm-block-group summary{font-size:11px;color:var(--slm-muted);cursor:pointer;padding:5px}
975
+ .slm-blockedlist{max-height:none;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
892
976
  border-radius:10px;background:var(--slm-surface)}
893
977
  .slm-blockeditem{display:grid!important;grid-template-columns:18px minmax(0,1fr);width:100%;gap:8px;padding:8px 9px!important;
894
978
  border-bottom:1px solid var(--slm-line)!important;text-align:left!important}
@@ -914,8 +998,8 @@
914
998
  .slm-toast.ok{background:#1f7a4d;color:#fff;border-color:#1f7a4d}
915
999
 
916
1000
  /* control-room actions + insights */
917
- .slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:7px}
918
- .slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:#f7ca6b}
1001
+ .slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:5px;flex-wrap:wrap}
1002
+ .slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:var(--slm-text)}
919
1003
  .slm-sectionlist{display:flex;flex-direction:column;gap:8px;margin-top:4px}
920
1004
  .slm-sectionlist + .slm-eyebrow{margin-top:18px}
921
1005
  .slm-sectionrow{width:100%;padding:10px!important;border:1px solid var(--slm-line)!important;border-radius:10px;
@@ -930,6 +1014,21 @@
930
1014
  .slm-health{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}
931
1015
  .slm-healthitem{padding:10px;border:1px solid var(--slm-line);border-radius:10px;background:var(--slm-surface)}
932
1016
  .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}
1017
+ .slm-seat-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
1018
+ .slm-seat-heading h2{font-size:18px;margin:0}
1019
+ .slm-seat-heading [data-seat-status]{font-size:12px;text-transform:capitalize}
1020
+ .slm-seat-history{display:flex;flex-direction:column;min-height:0;flex:1;gap:6px}
1021
+ .slm-history-counts{display:flex;flex-wrap:wrap;gap:4px;margin:5px 0}
1022
+ .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}
1023
+ .slm-history-counts button[aria-pressed=true]{color:var(--slm-text);border-color:var(--slm-accent)}
1024
+ .slm-history-list{min-height:0;overflow:auto;flex:1}
1025
+ .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}
1026
+ .slm-history-row time{color:var(--slm-muted);font-variant-numeric:tabular-nums}
1027
+ .slm-history-row strong{font-size:10px;text-transform:uppercase;border-radius:4px;padding:3px 6px;background:var(--slm-surface);color:var(--slm-text)}
1028
+ .slm-history-row[data-action=hold] strong{color:#a66c00;background:#e9ad2220}
1029
+ .slm-history-row[data-action=book] strong{color:#168251;background:#20976520}
1030
+ .slm[data-theme=dark] .slm-history-row[data-action=hold] strong{color:#f6c65c}
1031
+ .slm[data-theme=dark] .slm-history-row[data-action=book] strong{color:#63d6a0}
933
1032
  .slm-sectionhead{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-top:18px}
934
1033
  .slm-windows{display:flex;gap:3px;padding:2px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-surface)}
935
1034
  .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)}
@@ -944,14 +1043,35 @@
944
1043
  /* Mixed toward the INK rather than toward black: on a light ground a black
945
1044
  mix is the only thing on the surface that reads as dark. */
946
1045
  .slm-availrow.zone{background:color-mix(in srgb,var(--slm-surface) 82%,var(--slm-text))}
947
- .slm-availrow.hidden{opacity:.62}.slm-availrow.closed{opacity:.82}
1046
+ .slm-availrow.hidden,.slm-availrow.closed{opacity:1}
1047
+ .slm-themed-picker{min-width:0;width:100%}
1048
+ .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}
1049
+ .slm-themed-picker summary::-webkit-details-marker{display:none}
1050
+ .slm-themed-picker summary::after{content:'\u2304';flex:none;margin-left:auto;line-height:1;color:var(--slm-muted)}
1051
+ .slm-themed-picker summary[aria-disabled=true]{opacity:.55;cursor:wait}
1052
+ .slm-themed-picker summary:focus-visible,.slm-themed-options button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
1053
+ .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}
1054
+ .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}
1055
+ .slm .slm-themed-options button:hover,.slm .slm-themed-options button[aria-pressed=true]{background:var(--slm-tint-strong)}
1056
+ .slm-themed-options button[aria-pressed=true]::after{content:' \u2713';float:right}
1057
+ .slm-availpicker{margin-top:7px}
1058
+ .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)}
1059
+ .slm-availpicker summary::-webkit-details-marker{display:none}
1060
+ .slm-availpicker summary:focus-visible,.slm-availchoices button:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
1061
+ .slm-availpicker[open] summary{border-color:var(--slm-accent)}
1062
+ .slm-availpicker summary[aria-disabled=true]{opacity:.55;cursor:wait}
1063
+ .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}
1064
+ .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}
1065
+ .slm-availchoices button:hover,.slm-availchoices button[aria-pressed=true]{background:var(--slm-tint-strong)}
1066
+ .slm-availchoices b{display:block;font-size:12px;font-weight:600}
1067
+ .slm-availchoices small{display:block;margin-top:2px;font-size:10px;color:var(--slm-muted)}
948
1068
  .slm-availhead{display:flex;align-items:center;gap:8px}
949
1069
  .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}
950
1070
  .slm-availcaret{flex:none;color:var(--slm-muted);font-size:10px}
951
1071
  .slm-availcount{flex:none;font-size:11px;font-weight:700;color:var(--slm-muted);font-variant-numeric:tabular-nums}
952
1072
  .slm-availbadge{flex:none;font-size:9px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;padding:2px 6px;border-radius:999px}
953
- .slm-availbadge.hidden{background:rgba(139,148,172,.18);color:#c2c9d8}
954
- .slm-availbadge.closed{background:rgba(244,183,64,.16);color:#f7ca6b}
1073
+ .slm-availbadge.hidden{background:rgba(139,148,172,.18);color:var(--slm-text)}
1074
+ .slm-availbadge.closed{background:rgba(244,183,64,.16);color:var(--slm-text)}
955
1075
  .slm-availselwrap{position:relative;flex:none;display:inline-flex}
956
1076
  .slm-availmode{width:auto;max-width:190px;padding:6px 8px;font-size:11.5px;font-weight:700;cursor:pointer}
957
1077
  .slm-availmode.on{border-color:var(--slm-accent);color:var(--slm-text)}
@@ -965,7 +1085,7 @@
965
1085
  .slm-availdot{width:9px;height:9px;border-radius:50%;flex:none;background:#22a06b}.slm-availdot.warn{background:#f4b740}
966
1086
  .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)}
967
1087
  .slm-availstar{flex:none;margin-top:1px;color:#f4b740;font-size:13px;line-height:1}
968
- .slm-availcallout p{font-size:11.5px;line-height:1.55;color:#f4d58a}.slm-availcallout b{color:#ffe4a3;font-weight:800}
1088
+ .slm-availcallout p{font-size:11.5px;line-height:1.55;color:var(--slm-text)}.slm-availcallout b{color:inherit;font-weight:800}
969
1089
  .slm-inspect-card{padding:16px;border:1px solid var(--slm-line);border-radius:12px;background:var(--slm-surface)}
970
1090
  .slm-inspect-label{font-size:24px;font-weight:850;letter-spacing:-.02em;line-height:1.1}
971
1091
  .slm-inspect-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px;margin-top:18px}
@@ -1001,6 +1121,8 @@
1001
1121
 
1002
1122
  .slm.compact .slm-rail{width:100%;border-left:0;border-top:1px solid var(--slm-line);height:44%}
1003
1123
  .slm.compact .slm-body{flex-direction:column}
1124
+ .slm.compact.monitor-view{min-height:760px}
1125
+ .slm.compact.monitor-view .slm-rail{height:55%;min-height:260px}
1004
1126
  .slm.compact .slm-bar{grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:8px}
1005
1127
  .slm.compact .slm-modes{display:none}
1006
1128
  .slm.compact .slm-tools{display:block;width:100%;padding:9px 13px;min-height:44px;border:1px solid var(--slm-line);
@@ -1026,47 +1148,44 @@
1026
1148
  transition:none!important;
1027
1149
  scroll-behavior:auto!important}
1028
1150
  }
1029
- `;function Ye(){if(typeof document>"u"||document.getElementById(Ue))return;let l=document.createElement("style");l.id=Ue,l.textContent=Bt,document.head.appendChild(l)}function We(l){if(typeof document>"u"||document.getElementById(Ke))return;let e=document.createElement("style");e.id=Ke,e.textContent=l,document.head.appendChild(e)}var Qe=require("@seatlayer/core");var Ge=require("@seatlayer/core/core/color");var Ae={light:{background:"#ffffff",surface:"#f6f7fb",text:"#172033",muted:"#667085",line:"rgba(23,32,51,.16)",map:"#e9edf4"},dark:{background:"#0f1522",surface:"#1a2234",text:"#eef1f8",muted:"#a5aec2",line:"rgba(165,174,194,.24)",map:"#0f1522"}};function Dt(){try{return window.matchMedia?.("(prefers-color-scheme: dark)").matches===!0}catch{return!1}}function Me(l){if(l)return l==="auto"?Dt()?"dark":"light":l}function Xe(l){let e;try{e=window.matchMedia?.("(prefers-color-scheme: dark)")}catch{return()=>{}}if(!e)return()=>{};let t=s=>l(s.matches);return typeof e.addEventListener=="function"?e.addEventListener("change",t):e.addListener?.(t),()=>{typeof e.removeEventListener=="function"?e.removeEventListener("change",t):e.removeListener?.(t)}}function Ze(l){return l?l.mode:"open"}function Je(l,e,t){switch(l){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 et(l){return new Date(l-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function tt(l){if(typeof l=="string"){let e=document.querySelector(l);if(!e)throw new Error(`seatmanager: container "${l}" not found`);return e}if(!(l instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return l}function Ee(l){if(!l.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 le(l){return l==="blocked"?"not_for_sale":l}var st=[{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 nt(l,e){let t=l??{},s=e?Ae[e]:null,n=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":n?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":n?"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 it(l){return l?Ae[l].map:null}function Ie(l,e){let t=Math.max(0,Math.round((e-l)/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 Z(l,e){return(0,Qe.formatMoney)(l,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function u(l){return String(l??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}var at=require("@seatlayer/core");function Pe(l){return Object.entries(l).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function re(l){let e=l.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=l.doc?.zones??[],s=new Map,n=[];for(let d of e.sections)if(d.zone&&t.some(c=>c.id===d.zone)){let c=s.get(d.zone)??[];c.push(d),s.set(d.zone,c)}else n.push(d);let i=[],a=0,o=0,r=(d,c,p,m=!1)=>{let v=l.availabilityRules[c.id]??null,g=l.effectiveClosed.has(c.id)||m,b=l.effectiveHidden.has(c.id)||p&&!g;d==="section"&&b&&(a+=1),d==="section"&&g&&(o+=1),i.push({kind:d,id:c.id,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels,rule:v,hidden:b,closed:g,followsZone:d==="section"&&p})};for(let d of t){let c=s.get(d.id);if(!c||!c.length)continue;let p={id:d.id,label:d.label||"Zone",seatCount:c.reduce((g,b)=>g+b.seatCount,0),seatLabels:c.flatMap(g=>g.seatLabels)},m=!!l.availabilityRules[d.id],v=l.availabilityRules[d.id]?.mode==="closed";r("zone",p,!1);for(let g of c)r("section",g,m,v)}for(let d of n)r("section",d,!1);if(e.ungrouped){let d=e.ungrouped;r("section",{id:at.UNGROUPED_ID,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels},!1)}return{rows:i,hiddenSections:a,closedSections:o}}function ot(l,e){let t=Ze(l.rule),s=`slm-availrow${l.kind==="zone"?" zone":""}${l.hidden?" hidden":""}${l.closed?" closed":""}`,n=e?" disabled":"",i=(c,p)=>`<option value="${c}"${t===c?" selected":""}>${p}</option>`,a=l.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<span class="slm-availselwrap">
1030
- <select class="slm-select slm-availmode${t!=="open"?" on":""}" data-avail-id="${u(l.id)}"${n} aria-label="Availability for ${u(l.label)}">
1031
- ${i("open","Open \u2014 on sale")}
1032
- ${i("closed","Closed \u2014 visible, not on sale")}
1033
- ${i("hidden","Hidden \u2014 off the buyer map")}
1034
- ${i("timed","Reveal at a time")}
1035
- ${i("threshold","Auto-reveal at % sold")}
1036
- </select>
1037
- </span>`,o="";if(!l.followsZone&&t==="timed"){let c=l.rule?.revealAt?u(et(l.rule.revealAt)):"";o=`<div class="slm-availdetail">
1038
- <input type="datetime-local" class="slm-input" data-avail-reveal="${u(l.id)}" value="${c}"${n} aria-label="Reveal time for ${u(l.label)}" />
1039
- </div>`}else if(!l.followsZone&&t==="threshold"){let c=l.rule?.thresholdPct??80;o=`<div class="slm-availdetail">
1151
+ `;function Je(){if(typeof document>"u"||document.getElementById(Ze))return;let l=document.createElement("style");l.id=Ze,l.textContent=Vt,document.head.appendChild(l)}function et(l){if(typeof document>"u"||document.getElementById(Qe))return;let e=document.createElement("style");e.id=Qe,e.textContent=l,document.head.appendChild(e)}var nt=require("@seatlayer/core");var tt=require("@seatlayer/core/core/color");var Pe={light:{background:"#ffffff",surface:"#f6f7fb",text:"#172033",muted:"#667085",line:"rgba(23,32,51,.16)",map:"#e9edf4"},dark:{background:"#0f1522",surface:"#1a2234",text:"#eef1f8",muted:"#a5aec2",line:"rgba(165,174,194,.24)",map:"#0f1522"}};function Ut(){try{return window.matchMedia?.("(prefers-color-scheme: dark)").matches===!0}catch{return!1}}function Be(l){if(l)return l==="auto"?Ut()?"dark":"light":l}function st(l){let e;try{e=window.matchMedia?.("(prefers-color-scheme: dark)")}catch{return()=>{}}if(!e)return()=>{};let t=s=>l(s.matches);return typeof e.addEventListener=="function"?e.addEventListener("change",t):e.addListener?.(t),()=>{typeof e.removeEventListener=="function"?e.removeEventListener("change",t):e.removeListener?.(t)}}function it(l){return l?l.mode:"open"}function at(l,e,t){switch(l){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 ot(l){return new Date(l-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function lt(l){if(typeof l=="string"){let e=document.querySelector(l);if(!e)throw new Error(`seatmanager: container "${l}" not found`);return e}if(!(l instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return l}function De(l){if(!l.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 de(l){return l==="blocked"?"not_for_sale":l}var rt=[{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 ct(l,e){let t=l??{},s=e?Pe[e]:null,n=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":n?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":n?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??(n?"#4654c8":"#6e7bff"),"--slm-accent-ink":t.accentInk??"#ffffff","--slm-font":"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif","--slm-radius":"14px"}}function dt(l){return l?Pe[l].map:null}function ht(l,e){let t=Math.max(0,Math.round((e-l)/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 he(l,e){return(0,nt.formatMoney)(l,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function b(l){return String(l??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}var pt=require("@seatlayer/core");function Oe(l){return Object.entries(l).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function pe(l){let e=l.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=l.doc?.zones??[],s=new Map,n=[];for(let c of e.sections)if(c.zone&&t.some(d=>d.id===c.zone)){let d=s.get(c.zone)??[];d.push(c),s.set(c.zone,d)}else n.push(c);let i=[],a=0,o=0,r=(c,d,h,u=!1)=>{let f=l.availabilityRules[d.id]??null,v=l.effectiveClosed.has(d.id)||u,g=l.effectiveHidden.has(d.id)||h&&!v;c==="section"&&g&&(a+=1),c==="section"&&v&&(o+=1),i.push({kind:c,id:d.id,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels,rule:f,hidden:g,closed:v,followsZone:c==="section"&&h})};for(let c of t){let d=s.get(c.id);if(!d||!d.length)continue;let h={id:c.id,label:c.label||"Zone",seatCount:d.reduce((v,g)=>v+g.seatCount,0),seatLabels:d.flatMap(v=>v.seatLabels)},u=!!l.availabilityRules[c.id],f=l.availabilityRules[c.id]?.mode==="closed";r("zone",h,!1);for(let v of d)r("section",v,u,f)}for(let c of n)r("section",c,!1);if(e.ungrouped){let c=e.ungrouped;r("section",{id:pt.UNGROUPED_ID,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels},!1)}return{rows:i,hiddenSections:a,closedSections:o}}function mt(l,e){let t=it(l.rule),s=`slm-availrow${l.kind==="zone"?" zone":""}${l.hidden?" hidden":""}${l.closed?" closed":""}`,n=e?" disabled":"",i=[["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"]],a=l.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
1152
+ <summary aria-label="Availability for ${b(l.label)}" ${e?'aria-disabled="true"':""}>${i.find(d=>d[0]===t)[1]}<span aria-hidden="true">\u2304</span></summary>
1153
+ <div class="slm-availchoices" aria-label="Availability options for ${b(l.label)}">
1154
+ ${i.map(([d,h,u])=>`<button type="button" data-avail-id="${b(l.id)}" data-avail-value="${d}" aria-pressed="${t===d}"${n}><span><b>${h}</b><small>${u}</small></span><span aria-hidden="true">${t===d?"\u2713":""}</span></button>`).join("")}
1155
+ </div>
1156
+ </details>`,o="";if(!l.followsZone&&t==="timed"){let d=l.rule?.revealAt?b(ot(l.rule.revealAt)):"";o=`<div class="slm-availdetail">
1157
+ <input type="datetime-local" class="slm-input" data-avail-reveal="${b(l.id)}" value="${d}"${n} aria-label="Reveal time for ${b(l.label)}" />
1158
+ </div>`}else if(!l.followsZone&&t==="threshold"){let d=l.rule?.thresholdPct??80;o=`<div class="slm-availdetail">
1040
1159
  <span class="slm-availpctlabel">Reveal at</span>
1041
- <input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${u(l.id)}" value="${u(c)}"${n} aria-label="Percent sold to reveal ${u(l.label)}" />
1160
+ <input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${b(l.id)}" value="${b(d)}"${n} aria-label="Percent sold to reveal ${b(l.label)}" />
1042
1161
  <span class="slm-availpctlabel">% sold</span>
1043
- </div>`}let r=l.closed?'<span class="slm-availbadge closed">Closed</span>':l.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",d=l.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${l.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
1162
+ </div>`}let r=l.closed?'<span class="slm-availbadge closed">Closed</span>':l.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",c=l.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${l.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
1044
1163
  <div class="slm-availhead">
1045
- <span class="slm-availlabel">${d}${u(l.label)}</span>
1164
+ <span class="slm-availlabel">${c}${b(l.label)}</span>
1046
1165
  ${r}
1047
1166
  <span class="slm-availcount">${l.seatCount.toLocaleString()}</span>
1048
- ${a}
1049
1167
  </div>
1168
+ ${a}
1050
1169
  ${o}
1051
- </div>`}var Qt="https://api.seatlayer.io",Ce=80,Zt=16,ft=4,yt=[{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."}]}],Jt=Object.fromEntries(yt.flatMap(l=>l.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),$e=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(),n=Jt[s];if(n){if(!this.toolAvailable(n))return;this.setMode(n)}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 n=t?.closest("[data-feed-id]");n?.dataset.feedId&&this.locateActivity(n.dataset.feedId)};this.sectionOptions=[];Ee(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 U(e.apiBase??Qt,e.token),this.organizerAssetUrls=new oe(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=tt(e.container)}assertSelectionOptions(e,t){let s=n=>n===void 0||Number.isInteger(n)&&n>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(){Ye(),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",n=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(),n&&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 n=new Set(t);s={view:n.has("event:channels:view"),manage:n.has("event:channels:view")&&n.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 Promise.resolve().then(()=>(Fe(),vt));if(this.closed||!this.channelCaps.view||(this.channels||(We(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 n=e.get(s.rowId);if(!n||n.type!=="row"&&n.type!=="table")continue;let i=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??L.UNGROUPED_ID,o=t.get(i)??{id:i,label:n.type==="row"?n.segmentedRow?.displayLabel??n.displayLabel??n.label:n.displayLabel??n.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};o.labels.push(s.label),t.set(i,o)}return[...t.values()].sort((s,n)=>s.sectionLabel.localeCompare(n.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(n.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)??L.UNGROUPED_ID;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=Me(this.themeMode);for(let[t,s]of Object.entries(nt(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=Xe(()=>{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=it(Me(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){Ee(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(),n=Math.min(12e4,Math.max(3e4,s*.2)),i=Math.max(0,s-n);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},i)}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(i=>this.status.get(i)==="free");if(!s.length)return;let n=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:n}),this.clearSelection(),this.done("block",s,n?`Blocked ${s.length} \u2014 auto-release ${new Date(n).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"free"),this.toastErr(i instanceof y&&i.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(i)}}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(n=>this.status.get(n)==="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(n){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(n)}}}async setCategory(e,t){let s=this.doc?.categories.find(i=>i.key===e),n=[...new Set(t??this.selectionLabels())].filter(i=>this.labelToSeat.has(i));if(!(!s||!n.length))try{let i=await this.withAuthRetry(()=>this.api.setCategory(this.key,n,e)),a={};for(let o of i.labels){let r=this.labelToSeat.get(o),d=this.labelToId.get(o);r&&(r.categoryKey=e),d&&(a[d]=e)}this.renderer?.setSeatCategories?.(a),this.clearSelection(),this.done("setCategory",i.labels,`Assigned ${i.labels.length.toLocaleString()} object${i.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(i){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(i)}}async setTableBooking(e,t,s={}){let n=[...new Set(e)].filter(Boolean);if(!(!n.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 i=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,n,t,s));await this.reloadEventChart(),this.done("setTableBooking",i.tableIds,`Updated ${i.tableIds.length.toLocaleString()} table${i.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(i){let a=i instanceof y&&i.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?.(i)}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 n=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let i=s.map(({id:a,label:o,seatCount:r,zone:d})=>({id:a,label:o,seatCount:r,...d?{zone:d}:{}}));return n&&this.opts.onFilteredSectionChange?.(i),i}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:n})=>({id:e,label:t,seatCount:s,...n?{zone:n}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),n=this.selectionCap(),i=[...new Set(e)].filter(o=>!s.has(o)).map(o=>this.labelToSeat.get(o)).filter(o=>!!o&&this.canSelectObject(o)),a=Math.max(0,n-s.size);i.length>a&&this.opts.onSelectionLimit?.(n),t=i.slice(0,a).map(o=>o.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 L.SeatmapRenderer(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(n=>n.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(0,L.expandChart)(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of(0,L.gaAreasOf)(e))for(let s of(0,L.gaUnitLabels)(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,n]of this.status.entries()){let i=this.labelToId.get(s);i&&t[le(n)].push(i)}["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 n=[],i=new Map;for(let o of s.changes){let r=["free","held","booked","blocked"].includes(o.status)?o.status:"free",d=this.status.get(o.label)??"free";if(d===r)continue;this.setStatusLabel(o.label,r,d);let c=this.labelToId.get(o.label);c&&(this.renderer?.setStatus([c],le(r)),n.push(c));let p=this.verbFor(d,r),m=`${p}:${r}`,v=i.get(m)??{labels:[],verb:p,status:r};v.labels.push(o.label),i.set(m,v)}for(let o of i.values()){let r=this.pushActivity(o.labels,o.verb,o.status);r&&this.paintSpatialActivity(r)}n.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=i=>["free","held","booked","blocked"].includes(i)?i:"free",n=new Map;if(t!==void 0){let i=s(t);for(let a of this.knownLabels())n.set(a,i)}for(let[i,a]of Object.entries(e))n.set(i,s(a));this.status=n,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 n of e){this.setStatusLabel(n,t);let i=this.labelToId.get(n);i&&s.push(i)}s.length&&this.renderer?.setStatus(s,le(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 n of e){let i=this.labelToSeat.get(n);if(!i)continue;let a=this.sectionByObject.get(i.rowId);a&&a!==L.UNGROUPED_ID&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(n=>this.sectionLabelById.get(n)??n)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let n of e.slice(0,Zt)){let i=this.labelToId.get(n);i&&this.renderer?.flashSeat(i,s)}}paintSpatialActivity(e){let t=e.sectionIds??this.sectionsForLabels(e.labels).ids,s=this.renderer?.getFocusedSection()??null,n=this.followLive&&t.length===1&&(e.status==="held"||e.status==="booked");if(n&&s===t[0]){this.pulseSeatLabels(e.labels,e.status);return}if(n){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 i=this.activityColor(e.status);for(let a of t.slice(0,ft))this.renderer?.flashSection(a,i);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(n=>n.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 n=this.activityColor(t.status);for(let i of s.slice(0,ft))this.renderer?.flashSection(i,n)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],n=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,i=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
1052
- <span class="slm-liveeventcopy">${u(n)} \xB7 ${e.count.toLocaleString()} ${i} ${u(e.verb)}</span>
1053
- <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 n=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(n)?n: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),n=s.bookedValue??s.revenue??{gross:0,bySection:[]},i=(n.bySection??[]).map(r=>{let d=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:d??0,bookedRevenue:d??0}}),a={...n,bySection:i},o={...s,bookedValue:a,revenue:a};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?o={...o,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let r={...o.bookedValue,gross:this.liveGross.value};o={...o,bookedValue:r,revenue:r}}else this.liveGross=null;this.controlRoomSnapshot=o,this.rebaseServerTotals(o),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=o.bookedValue.gross,this.authoritativeCurrency=o.currency,this.currency=o.currency,this.revenueStatus="current",this.recomputeTallies(),this.applyHeatOverlay(),this.paintMonitorInsights(),this.opts.onControlRoom?.(o)}return o}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=o=>t?Math.max(0,t.server[o]+(e[o]-t.client[o])):e[o],n=this.controlRoomSnapshot?.event?.seatTotal,i={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(n)?n:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};i.capacityPct=i.total?Math.round(i.booked/i.total*100):0;let a=i.total-i.blocked;return i.sellThroughPct=a>0?Math.round(i.booked/a*100):0,i}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,n=Date.now()){let i=e[0];if(!i)return null;let a=this.sectionsForLabels(e),o={id:`${i}:${n}:${Math.random().toString(36).slice(2,6)}`,at:n,label:i,labels:[...e],count:e.length,verb:t,status:s,sectionIds:a.ids,sectionLabels:a.labels};return this.feed.unshift(o),this.feed.length>Ce&&(this.feed.length=Ce),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(o),this.opts.onActivity?.(o),o}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 n of e){let i=n.labels[0];if(!i)continue;let a=this.sectionsForLabels(n.labels),o={id:`log:${n.id}`,at:n.at,label:i,labels:[...n.labels],count:n.labels.length,verb:t[n.action]??n.action,status:s[n.action]??"free",sectionIds:a.ids,sectionLabels:a.labels};this.feed.push(o),this.opts.onActivity?.(o)}this.feed.sort((n,i)=>i.at-n.at),this.feed.length>Ce&&(this.feed.length=Ce),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,n=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return n;try{return this.opts.isObjectSelectable(e,n)===!0}catch(i){return this.opts.onError?.(i),!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[n,i]of t)this.lastSelectionLabels.has(n)||this.opts.onObjectSelected?.(i);for(let n of this.lastSelectionLabels)if(!t.has(n)){let i=this.labelToSeat.get(n);i&&this.opts.onObjectDeselected?.(i)}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=`
1170
+ </div>`}var os="https://api.seatlayer.io",Ee=200,Ct=16,Tt=4,Rt=[{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."}]}],ls=Object.fromEntries(Rt.flatMap(l=>l.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),Ae=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(),n=ls[s];if(n){if(!this.toolAvailable(n))return;this.setMode(n)}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 n=t?.closest("[data-feed-id]");n?.dataset.feedId&&this.locateActivity(n.dataset.feedId)};this.sectionOptions=[];De(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 U(e.apiBase??os,e.token),this.organizerAssetUrls=new ce(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=lt(e.container)}assertSelectionOptions(e,t){let s=n=>n===void 0||Number.isInteger(n)&&n>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(){Je(),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",n=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(),n&&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 n=new Set(t);s={view:n.has("event:channels:view"),manage:n.has("event:channels:view")&&n.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 Promise.resolve().then(()=>(_e(),Lt));if(this.closed||!this.channelCaps.view||(this.channels||(et(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 n=e.get(s.rowId);if(!n||n.type!=="row"&&n.type!=="table")continue;let i=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??S.UNGROUPED_ID,o=t.get(i)??{id:i,label:n.type==="row"?n.segmentedRow?.displayLabel??n.displayLabel??n.label:n.displayLabel??n.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};o.labels.push(s.label),t.set(i,o)}return[...t.values()].sort((s,n)=>s.sectionLabel.localeCompare(n.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(n.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)??S.UNGROUPED_ID;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=Be(this.themeMode);for(let[t,s]of Object.entries(ct(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=st(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(i=>i.id),s=e.getCameraPose(),n=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),n&&e.focusSection(n),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=dt(Be(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){De(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(),n=Math.min(12e4,Math.max(3e4,s*.2)),i=Math.max(0,s-n);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},i)}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(i=>this.status.get(i)==="free");if(!s.length)return;let n=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:n}),this.clearSelection(),this.done("block",s,n?`Blocked ${s.length} \u2014 auto-release ${new Date(n).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"free"),this.toastErr(i instanceof y&&i.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(i)}}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(n=>this.status.get(n)==="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(n){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(n)}}}async setCategory(e,t){let s=this.doc?.categories.find(i=>i.key===e),n=[...new Set(t??this.selectionLabels())].filter(i=>this.labelToSeat.has(i));if(!(!s||!n.length))try{let i=await this.withAuthRetry(()=>this.api.setCategory(this.key,n,e)),a={};for(let o of i.labels){let r=this.labelToSeat.get(o),c=this.labelToId.get(o);r&&(r.categoryKey=e),c&&(a[c]=e)}this.renderer?.setSeatCategories?.(a),this.clearSelection(),this.done("setCategory",i.labels,`Assigned ${i.labels.length.toLocaleString()} object${i.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(i){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(i)}}async setTableBooking(e,t,s={}){let n=[...new Set(e)].filter(Boolean);if(!(!n.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 i=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,n,t,s));await this.reloadEventChart(),this.done("setTableBooking",i.tableIds,`Updated ${i.tableIds.length.toLocaleString()} table${i.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(i){let a=i instanceof y&&i.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?.(i)}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 n=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let i=s.map(({id:a,label:o,seatCount:r,zone:c})=>({id:a,label:o,seatCount:r,...c?{zone:c}:{}}));return n&&this.opts.onFilteredSectionChange?.(i),i}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:n})=>({id:e,label:t,seatCount:s,...n?{zone:n}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),n=this.selectionCap(),i=[...new Set(e)].filter(o=>!s.has(o)).map(o=>this.labelToSeat.get(o)).filter(o=>!!o&&this.canSelectObject(o)),a=Math.max(0,n-s.size);i.length>a&&this.opts.onSelectionLimit?.(n),t=i.slice(0,a).map(o=>o.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 S.SeatmapRenderer(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(n=>n.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(0,S.expandChart)(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of(0,S.gaAreasOf)(e))for(let s of(0,S.gaUnitLabels)(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,n]of this.status.entries()){let i=this.labelToId.get(s);i&&t[de(n)].push(i)}["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 n=[],i=new Map;for(let o of s.changes){let r=["free","held","booked","blocked"].includes(o.status)?o.status:"free",c=this.status.get(o.label)??"free";if(c===r)continue;this.setStatusLabel(o.label,r,c);let d=this.labelToId.get(o.label);d&&(this.renderer?.setStatus([d],de(r)),n.push(d));let h=this.verbFor(c,r),u=`${h}:${r}`,f=i.get(u)??{labels:[],verb:h,status:r};f.labels.push(o.label),i.set(u,f)}for(let o of i.values()){let r=this.pushActivity(o.labels,o.verb,o.status);r&&this.paintSpatialActivity(r)}i.size&&this.scheduleMonitorRefresh(),n.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))}applySocketSnapshot(e,t){let s=this.socketSnapshotSeen?this.status:null;if(this.applySnapshot(e,t),this.socketSnapshotSeen=!0,!s)return;let n=new Map;for(let i of new Set([...s.keys(),...this.status.keys()])){let a=s.get(i)??"free",o=this.status.get(i)??"free";if(a===o)continue;let r=this.verbFor(a,o),c=`${r}:${o}`,d=n.get(c)??{labels:[],verb:r,status:o};d.labels.push(i),n.set(c,d)}for(let i of n.values()){let a=this.pushActivity(i.labels,i.verb,i.status);a&&this.paintSpatialActivity(a)}n.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=i=>["free","held","booked","blocked"].includes(i)?i:"free",n=new Map;if(t!==void 0){let i=s(t);for(let a of this.knownLabels())n.set(a,i)}for(let[i,a]of Object.entries(e))n.set(i,s(a));this.status=n,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 n of e){this.setStatusLabel(n,t);let i=this.labelToId.get(n);i&&s.push(i)}s.length&&this.renderer?.setStatus(s,de(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 n of e){let i=this.labelToSeat.get(n);if(!i)continue;let a=this.sectionByObject.get(i.rowId);a&&a!==S.UNGROUPED_ID&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(n=>this.sectionLabelById.get(n)??n)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let n of e.slice(0,Ct)){let i=this.labelToId.get(n);i&&this.renderer?.flashSeat(i,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 i=this.root?.querySelector('[data-ref="followstatus"]');i&&(i.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 i=this.activityColor(e.status);for(let a of t.slice(0,Tt))this.renderer?.flashSection(a,i);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,Ct).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let n=s.map(r=>r.x),i=s.map(r=>r.y),a=Math.min(...n),o=Math.min(...i);this.renderer?.focusRegion({x:a-150,y:o-100,width:Math.max(...n)-a+300,height:Math.max(...i)-o+200})}locateActivity(e){let t=this.feed.find(n=>n.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 n=this.activityColor(t.status);for(let i of s.slice(0,Tt))this.renderer?.flashSection(i,n)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],n=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,i=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
1171
+ <span class="slm-liveeventcopy">${b(n)} \xB7 ${e.count.toLocaleString()} ${i} ${b(e.verb)}</span>
1172
+ <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 n=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(n)?n: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),n=s.bookedValue??s.revenue??{gross:0,bySection:[]},i=(n.bySection??[]).map(r=>{let c=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:c??0,bookedRevenue:c??0}}),a={...n,bySection:i},o={...s,bookedValue:a,revenue:a};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?o={...o,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let d={...o.bookedValue,gross:this.liveGross.value};o={...o,bookedValue:d,revenue:d}}else this.liveGross=null;this.controlRoomSnapshot=o,o.activity&&this.seedFeed(o.activity),this.rebaseServerTotals(o),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=o.bookedValue.gross,this.authoritativeCurrency=o.currency,this.currency=o.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?.(o)}return o}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=o=>t?Math.max(0,t.server[o]+(e[o]-t.client[o])):e[o],n=this.controlRoomSnapshot?.event?.seatTotal,i={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(n)?n:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};i.capacityPct=i.total?Math.round(i.booked/i.total*100):0;let a=i.total-i.blocked;return i.sellThroughPct=a>0?Math.round(i.booked/a*100):0,i}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,n=Date.now()){let i=e[0];if(!i)return null;let a=this.sectionsForLabels(e),o={id:`${i}:${n}:${Math.random().toString(36).slice(2,6)}`,at:n,label:i,labels:[...e],count:e.length,verb:t,status:s,sectionIds:a.ids,sectionLabels:a.labels};return this.controlRoomSnapshot?.activity||this.feed.unshift(o),this.feed.length>Ee&&(this.feed.length=Ee),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(o),this.opts.onActivity?.(o),o}seedFeed(e){this.controlRoomSnapshot?.activity&&(this.feed=this.feed.filter(n=>n.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 n of e){if(this.feed.some(r=>r.id===`log:${n.id}`))continue;let i=n.labels[0];if(!i)continue;let a=this.sectionsForLabels(n.labels),o={id:`log:${n.id}`,at:n.at,label:i,labels:[...n.labels],count:n.labels.length,verb:t[n.action]??n.action,status:s[n.action]??"free",sectionIds:a.ids,sectionLabels:a.labels};this.feed.push(o),this.opts.onActivity?.(o)}this.feed.sort((n,i)=>i.at-n.at),this.feed.length>Ee&&(this.feed.length=Ee),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,n=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return n;try{return this.opts.isObjectSelectable(e,n)===!0}catch(i){return this.opts.onError?.(i),!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[n,i]of t)this.lastSelectionLabels.has(n)||this.opts.onObjectSelected?.(i);for(let n of this.lastSelectionLabels)if(!t.has(n)){let i=this.labelToSeat.get(n);i&&this.opts.onObjectDeselected?.(i)}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=`
1054
1173
  <div class="slm-bar">
1055
1174
  <div class="slm-modes" data-ref="modes" role="tablist" aria-label="Control room tools">
1056
- ${yt.map(s=>`<div class="slm-modegroup" data-group="${s.key}" role="presentation" hidden>
1057
- <span class="slm-modegroup-label" aria-hidden="true">${u(s.label)}</span>
1058
- ${s.tools.map(n=>`<button class="slm-mode" role="tab" data-mode="${n.mode}"
1059
- title="${u(n.title)} (${n.shortcut})" aria-keyshortcuts="${n.shortcut}" hidden>${u(n.label)}</button>`).join("")}
1175
+ ${Rt.map(n=>`<div class="slm-modegroup" data-group="${n.key}" role="presentation" hidden>
1176
+ <span class="slm-modegroup-label" aria-hidden="true">${b(n.label)}</span>
1177
+ ${n.tools.map(i=>`<button class="slm-mode" role="tab" data-mode="${i.mode}"
1178
+ title="${b(i.title)} (${i.shortcut})" aria-keyshortcuts="${i.shortcut}" hidden>${b(i.label)}</button>`).join("")}
1060
1179
  </div>`).join("")}
1061
1180
  </div>
1062
1181
  <select class="slm-tools" data-ref="tools" aria-label="Control room tools"></select>
1063
1182
  <span class="slm-live"><span class="slm-live-dot"></span><span data-ref="livetext">CONNECTING</span></span>
1064
1183
  <div class="slm-bar-actions">
1065
- <button class="slm-barbtn follow" data-ref="follow" aria-pressed="false"
1066
- title="Stay on the current map view unless enabled">Follow live</button>
1067
- <button class="slm-barbtn" data-ref="heat" aria-pressed="false"
1184
+ <button class="slm-barbtn follow" data-ref="follow" aria-label="Follow live" aria-pressed="false"
1185
+ title="Stay on the current map view unless enabled">Auto-follow</button>
1186
+ <button class="slm-barbtn heat" data-ref="heat" aria-pressed="false"
1068
1187
  aria-label="Booking momentum overlay off"
1069
- title="Highlight sections booking fastest in the selected time window">Booking momentum</button>
1188
+ title="Highlight sections booking fastest in the selected time window">Heatmap</button>
1070
1189
  <button class="slm-barbtn" data-ref="fullscreen" title="Full screen (F)" aria-keyshortcuts="F">Full screen</button>
1071
1190
  </div>
1072
1191
  <div class="slm-kpis" data-ref="kpis"></div>
@@ -1076,21 +1195,26 @@
1076
1195
  <div class="slm-map-host" data-ref="maphost"></div>
1077
1196
  <div class="slm-zoomhint" data-ref="zoomhint">Zoom in to marquee-select</div>
1078
1197
  <div class="slm-liveevent" data-ref="liveevent" role="status" aria-live="polite"></div>
1198
+ <div class="slm-heat-status" data-ref="heatstatus" role="status" hidden></div>
1199
+ <div class="slm-follow-status" data-ref="followstatus" role="status" hidden></div>
1079
1200
  <div class="slm-hud"><button class="slm-hud-chip" data-ref="zfit">Zoom to fit</button></div>
1080
1201
  </div>
1081
1202
  <aside class="slm-rail"><div class="slm-railscroll" data-ref="rail"></div></aside>
1082
1203
  </div>
1083
1204
  <div class="slm-toast" data-ref="toast"></div>
1084
- `,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(c=>c.id)),s=this.filterableSections().filter(c=>!t.has(c.id)).map(c=>c.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let n=e.flatMap(c=>c.seatLabels).map(c=>this.labelToSeat.get(c)).filter(c=>!!c&&Number.isFinite(c.x)&&Number.isFinite(c.y));if(!n.length){this.renderer.focusRegion(e[0].id);return}let i=Math.min(...n.map(c=>c.x)),a=Math.min(...n.map(c=>c.y)),o=Math.max(...n.map(c=>c.x)),r=Math.max(...n.map(c=>c.y)),d=Math.max(40,Math.max(o-i,r-a)*.08);this.renderer.focusRegion({x:i-d,y:a-d,width:Math.max(1,o-i)+d*2,height:Math.max(1,r-a)+d*2})}buildSectionOptions(){if(this.doc)try{let e=(0,L.computeSections)(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:L.UNGROUPED_ID,label:e.ungrouped.label}),this.sectionLabelById.set(L.UNGROUPED_ID,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?(0,L.floorsOf)(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let n=[];s.querySelectorAll("[data-mode]").forEach(i=>{let a=i.dataset.mode,o=this.toolAvailable(a);if(i.hidden=!o,!o)return;n.push({mode:a,label:i.textContent??a});let r=a===this.mode;i.classList.toggle("on",r),i.setAttribute("aria-selected",String(r)),i.tabIndex=r?0:-1}),s.hidden=n.length===0,n.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:n})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${u(s.label)}">${s.tools.map(n=>`<option value="${n.mode}"${n.mode===this.mode?" selected":""}>${u(n.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let n=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${u(e)}</p><span class="slm-scope ${t}">${n}</span></div>
1085
- <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(n=>n.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 n=t>0?"+":"\u2212",i=Math.abs(t);return e==="booked-value"?`${n}${Z(i,s)}`:e==="booked-pct"?`${n}${i.toLocaleString()}pt`:`${n}${i.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?Z(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),n=[{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"}],i=!1;this.els.kpis.innerHTML=n.map(a=>{let o=this.lastKpiValues.get(a.key),r=a.raw!=null&&o!=null&&a.raw!==o,d=r?a.raw-o:0;r&&(i=!0,this.activeKpiDeltas.set(a.key,{text:this.formatKpiDelta(a.key,d,e.currency),down:d<0})),a.raw!=null&&this.lastKpiValues.set(a.key,a.raw);let c=this.activeKpiDeltas.get(a.key);return`<div class="slm-kpi${c?" changed":""}" data-kpi="${a.key}" title="${u(a.title)}">
1205
+ `,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let n=e.querySelector(".slm-rail");n&&ne(n)});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=n=>e.querySelector(`[data-ref="${n}"]`);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(n=>n.addEventListener("click",()=>this.setMode(n.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 oe({root:e,map:this.mapHost,setMoving:n=>{this.movingMap=n,this.updateRendererInteraction()},pauseFollow:()=>{this.followLive&&this.setFollowLive(!1)},zoomIn:()=>this.renderer?.zoomIn(),zoomOut:()=>this.renderer?.zoomOut(),targets:n=>this.navigationTargets(n)}),this.navigation.update(this.isBulkSelectMode(),this.mode==="view")}navigationTargets(e){let t=e.toLocaleLowerCase(),s=[];for(let i of this.sectionOptions)if(i.label.toLocaleLowerCase().includes(t)&&s.push({label:i.label,detail:"Section",locate:()=>this.locateSection(i.id)}),s.length>=20)return s;let n=new Map;for(let i of this.labelToSeat.values()){let a=n.get(i.rowId)??{minX:i.x,minY:i.y,maxX:i.x,maxY:i.y};a.minX=Math.min(a.minX,i.x),a.minY=Math.min(a.minY,i.y),a.maxX=Math.max(a.maxX,i.x),a.maxY=Math.max(a.maxY,i.y),n.set(i.rowId,a)}for(let i of this.doc?(0,S.floorsOf)(this.doc).flatMap(a=>a.objects):[]){if(i.type!=="row"||!(i.displayLabel??i.label).toLocaleLowerCase().includes(t))continue;let a=n.get(i.id);if(!a)continue;let{minX:o,minY:r,maxX:c,maxY:d}=a;if(s.push({label:i.displayLabel??i.label,detail:"Row",locate:()=>{let h=this.sectionByObject.get(i.id);h&&this.renderer?.focusSection(h),this.renderer?.focusRegion({x:o-30,y:r-30,width:c-o+60,height:d-r+60},{minScale:1.2,animate:!1})}}),s.length>=20)return s}for(let i of this.labelToSeat.values())if(i.label.toLocaleLowerCase().includes(t)&&(s.push({label:i.label,detail:"Seat",locate:()=>{let a=this.sectionByObject.get(i.rowId);a&&this.renderer?.focusSection(a),this.renderer?.focusRegion({x:i.x-180,y:i.y-120,width:360,height:240},{animate:!1,minScale:1.5}),this.renderer?.flashSeat(i.id,this.activityColor(this.status.get(i.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(d=>d.id)),s=this.filterableSections().filter(d=>!t.has(d.id)).map(d=>d.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let n=e.flatMap(d=>d.seatLabels).map(d=>this.labelToSeat.get(d)).filter(d=>!!d&&Number.isFinite(d.x)&&Number.isFinite(d.y));if(!n.length){this.renderer.focusRegion(e[0].id);return}let i=Math.min(...n.map(d=>d.x)),a=Math.min(...n.map(d=>d.y)),o=Math.max(...n.map(d=>d.x)),r=Math.max(...n.map(d=>d.y)),c=Math.max(40,Math.max(o-i,r-a)*.08);this.renderer.focusRegion({x:i-c,y:a-c,width:Math.max(1,o-i)+c*2,height:Math.max(1,r-a)+c*2})}buildSectionOptions(){if(this.doc)try{let e=(0,S.computeSections)(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:S.UNGROUPED_ID,label:e.ungrouped.label}),this.sectionLabelById.set(S.UNGROUPED_ID,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?(0,S.floorsOf)(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let n=[];s.querySelectorAll("[data-mode]").forEach(i=>{let a=i.dataset.mode,o=this.toolAvailable(a);if(i.hidden=!o,!o)return;n.push({mode:a,label:i.textContent??a});let r=a===this.mode;i.classList.toggle("on",r),i.setAttribute("aria-selected",String(r)),i.tabIndex=r?0:-1}),s.hidden=n.length===0,n.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:n})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${b(s.label)}">${s.tools.map(n=>`<option value="${n.mode}"${n.mode===this.mode?" selected":""}>${b(n.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let n=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${b(e)}</p><span class="slm-scope ${t}">${n}</span></div>
1206
+ <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 i=this.controlRoomSnapshot?.velocity.bySection.some(a=>a.netBooked>0);e.textContent=this.controlRoomSnapshot?i?`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 n=this.controlRoomSnapshot?.velocity.bySection.some(i=>i.netBooked>0);s.textContent=n?"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 n=t>0?"+":"\u2212",i=Math.abs(t);return e==="booked-value"?`${n}${he(i,s)}`:e==="booked-pct"?`${n}${i.toLocaleString()}pt`:`${n}${i.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?he(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),n=[{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"}],i=!1;this.els.kpis.innerHTML=n.map(a=>{let o=this.lastKpiValues.get(a.key),r=a.raw!=null&&o!=null&&a.raw!==o,c=r?a.raw-o:0;r&&(i=!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 d=this.activeKpiDeltas.get(a.key);return`<div class="slm-kpi${d?" changed":""}" data-kpi="${a.key}" title="${b(a.title)}">
1086
1207
  <b>${a.dot?`<span class="dot" style="background:${a.dot}"></span>`:""}${a.n}</b><span>${a.l}</span>
1087
- ${c?`<span class="slm-kpidelta${c.down?" down":""}">${c.text}</span>`:""}
1088
- </div>`}).join(""),i&&(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=`
1089
- ${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.")}
1090
- <div class="slm-health" data-ref="presence"></div>
1091
- <div class="slm-legend" data-ref="legend"></div>
1208
+ ${d?`<span class="slm-kpidelta${d.down?" down":""}">${d.text}</span>`:""}
1209
+ </div>`}).join(""),i&&(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.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=`
1210
+ <div class="slm-monitor-head"><h2>Live activity</h2><span data-ref="presence" class="slm-monitor-connection"></span></div>
1211
+ <div class="slm-monitor-tabs" role="tablist" aria-label="Monitor details">
1212
+ <button role="tab" aria-selected="true" data-monitor-tab="activity">Activity</button>
1213
+ <button role="tab" aria-selected="false" data-monitor-tab="sections">Section inventory</button>
1214
+ </div>
1215
+ <div data-monitor-panel="activity" class="slm-monitor-activity"><div data-ref="feed"></div></div>
1216
+ <div data-monitor-panel="sections" hidden>
1092
1217
  <div class="slm-sectionhead">
1093
- <div><p class="slm-eyebrow">Section inventory</p><p class="slm-note">Configured booked value \xB7 booking momentum</p></div>
1094
1218
  <div class="slm-windows" aria-label="Booking momentum window">
1095
1219
  ${[5,15,30,60].map(e=>`<button class="slm-window" data-window="${e}">${e}m</button>`).join("")}
1096
1220
  </div>
@@ -1100,15 +1224,10 @@
1100
1224
  <p class="slm-momentumcopy" data-ref="momentumcopy"></p>
1101
1225
  </div>
1102
1226
  <div class="slm-sectionlist" data-ref="sections"></div>
1103
- <p class="slm-eyebrow">Activity</p>
1104
- <div class="slm-feed" data-ref="feed"></div>
1105
- `,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 n=this.root?.classList.contains("live"),i=this.lastSyncedAt?Ie(this.lastSyncedAt,Date.now()):"waiting",a=this.presenceCounts();this.els.presence.innerHTML=`
1106
- <div class="slm-healthitem" title="Active map sessions right now"><b>${a?a.shoppingSessions.toLocaleString():"\u2014"}</b><span>Viewing map</span></div>
1107
- <div class="slm-healthitem" title="Sessions currently holding inventory"><b>${a?a.activeHolds.toLocaleString():"\u2014"}</b><span>Active holds</span></div>
1108
- <div class="slm-healthitem"><b>${n?"Healthy":"Reconnecting"}</b><span>Live connection</span></div>
1109
- <div class="slm-healthitem"><b>${i}</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(n=>[n.sectionId,n])),s=[...e.bookedValue.bySection].sort((n,i)=>{let a=t.get(n.sectionId)?.netBooked??0;return(t.get(i.sectionId)?.netBooked??0)-a||i.bookedValue-n.bookedValue});this.els.sections.innerHTML=s.length?s.map(n=>{let i=t.get(n.sectionId),a=i?.netBooked??0,o=`${a>0?"+":""}${a}`,r=i?.trend==="rising"||i?.trend==="cooling"?i.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${u(n.sectionId)}" title="Focus ${u(n.sectionLabel)} on the map">
1110
- <span class="slm-sectiontop"><span>${u(n.sectionLabel)}</span><span>${Z(n.bookedValue,e.currency)}</span></span>
1111
- <span class="slm-sectionmeta"><span>${n.booked.toLocaleString()}/${n.total.toLocaleString()} booked \xB7 ${o} in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${r}">${r}</span><span class="slm-sectionlocate">Locate</span></span>
1227
+ </div>
1228
+ `,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 ae(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 n=this.root?.classList.contains("live"),i=this.lastSyncedAt?ht(this.lastSyncedAt,Date.now()):"waiting";this.els.presence.textContent=n?"\u25CF Live":"Reconnecting",this.els.presence.title=`Last data received: ${i}`}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(n=>[n.sectionId,n])),s=[...e.bookedValue.bySection].sort((n,i)=>{let a=t.get(n.sectionId)?.netBooked??0;return(t.get(i.sectionId)?.netBooked??0)-a||i.bookedValue-n.bookedValue});this.els.sections.innerHTML=s.length?s.map(n=>{let i=t.get(n.sectionId),a=i?.netBooked??0,o=`${a>0?"+":""}${a}`,r=i?.trend==="rising"||i?.trend==="cooling"?i.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${b(n.sectionId)}" title="Focus ${b(n.sectionLabel)} on the map">
1229
+ <span class="slm-sectiontop"><span>${b(n.sectionLabel)}</span><span title="Configured value of currently booked inventory">${he(n.bookedValue,e.currency)}</span></span>
1230
+ <span class="slm-sectionmeta"><span>${n.booked.toLocaleString()}/${n.total.toLocaleString()} booked \xB7 ${o} net in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${r}">${r}</span><span class="slm-sectionlocate">Locate</span></span>
1112
1231
  </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})),n=Math.max(0,...s.map(a=>a.rate)),i={};for(let a of s)i[a.sectionId]=n>0?Math.sqrt(a.rate/n):0;this.renderer?.setSectionHeat(i)}renderSelectRail(){let e=this.doc?.categories??[],t=this.opts.numberOfPlacesToSelect,s=this.selectionCap();this.els.rail.innerHTML=`
1113
1232
  ${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.")}
1114
1233
  <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>
@@ -1119,15 +1238,15 @@
1119
1238
  </div>
1120
1239
  ${e.length?`<p class="slm-eyebrow" style="margin-top:8px">Select by category</p>
1121
1240
  <div class="slm-chipgrid">${e.map(n=>`
1122
- <button class="slm-chip" type="button" data-select-cat="${u(n.key)}" aria-pressed="false">
1123
- <span class="dot" style="background:${u(n.color??"#6e7bff")}"></span>
1124
- <span>${u(n.label??n.key)}</span>
1241
+ <button class="slm-chip" type="button" data-select-cat="${b(n.key)}" aria-pressed="false">
1242
+ <span class="dot" style="background:${b(n.color??"#6e7bff")}"></span>
1243
+ <span>${b(n.label??n.key)}</span>
1125
1244
  <span class="slm-chipcount" data-cat-count>0</span>
1126
1245
  <span class="slm-chipcheck" aria-hidden="true">\u2713</span>
1127
- </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(n=>{n.addEventListener("click",()=>{let i=n.dataset.selectCat,a=[...this.labelToSeat.values()].filter(r=>r.categoryKey===i&&this.canSelectObject(r)),o=new Set(this.selectionLabels());a.length>0&&a.every(r=>o.has(r.label))?this.deselectCategories([i]):this.selectCategories([i])})}),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 n=new Set(e.map(i=>i.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(i=>{let a=i.dataset.selectCat,o=[...this.labelToSeat.values()].filter(p=>p.categoryKey===a&&this.canSelectObject(p)),r=o.filter(p=>n.has(p.label)).length,d=o.length>0&&r===o.length;i.classList.toggle("on",d),i.setAttribute("aria-pressed",String(d));let c=i.querySelector("[data-cat-count]");c&&(c.textContent=r?`${r}/${o.length}`:o.length.toLocaleString()),i.disabled=o.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=`
1246
+ </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(n=>{n.addEventListener("click",()=>{let i=n.dataset.selectCat,a=[...this.labelToSeat.values()].filter(r=>r.categoryKey===i&&this.canSelectObject(r)),o=new Set(this.selectionLabels());a.length>0&&a.every(r=>o.has(r.label))?this.deselectCategories([i]):this.selectCategories([i])})}),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 n=new Set(e.map(i=>i.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(i=>{let a=i.dataset.selectCat,o=[...this.labelToSeat.values()].filter(h=>h.categoryKey===a&&this.canSelectObject(h)),r=o.filter(h=>n.has(h.label)).length,c=o.length>0&&r===o.length;i.classList.toggle("on",c),i.setAttribute("aria-pressed",String(c));let d=i.querySelector("[data-cat-count]");d&&(d.textContent=r?`${r}/${o.length}`:o.length.toLocaleString()),i.disabled=o.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=`
1128
1247
  ${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.")}
1129
- ${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let n=t===this.filteredSectionLabel,i=s.reduce((a,o)=>a+o.seatCount,0);return`<button type="button" class="slm-sectionrow${n?" on":""}" data-filter-section="${u(t)}" aria-pressed="${n}">
1130
- <span class="slm-sectiontop"><span>${u(t)}</span><span>${i.toLocaleString()}</span></span>
1248
+ ${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let n=t===this.filteredSectionLabel,i=s.reduce((a,o)=>a+o.seatCount,0);return`<button type="button" class="slm-sectionrow${n?" on":""}" data-filter-section="${b(t)}" aria-pressed="${n}">
1249
+ <span class="slm-sectiontop"><span>${b(t)}</span><span>${i.toLocaleString()}</span></span>
1131
1250
  <span class="slm-sectionmeta"><span>${s.length===1?"One section":`${s.length.toLocaleString()} matching sections`}</span><span class="slm-sectionlocate">${n?"Filtered":"Filter"}</span></span>
1132
1251
  </button>`}).join("")}</div>
1133
1252
  <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=`
@@ -1135,9 +1254,9 @@
1135
1254
  <p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
1136
1255
  <p class="slm-selecthelp">Click or drag seats on the map, press \u2318A for all, or tick a whole category. A ticked category is selected; tick it again to remove it.</p>
1137
1256
  <div class="slm-chiprow">${e.length?e.map(s=>`
1138
- <button class="slm-chip" type="button" data-pick-category="${u(s.key)}" aria-pressed="false">
1139
- <span class="dot" style="background:${u(s.color??"#6e7bff")}"></span>
1140
- <span>${u(s.label??s.key)}</span>
1257
+ <button class="slm-chip" type="button" data-pick-category="${b(s.key)}" aria-pressed="false">
1258
+ <span class="dot" style="background:${b(s.color??"#6e7bff")}"></span>
1259
+ <span>${b(s.label??s.key)}</span>
1141
1260
  <span class="slm-chipcount" data-cat-count>0</span>
1142
1261
  <span class="slm-chipcheck" aria-hidden="true">\u2713</span>
1143
1262
  </button>`).join(""):'<span class="slm-empty">This chart has no categories.</span>'}</div>
@@ -1152,77 +1271,66 @@
1152
1271
  <p class="slm-eyebrow slm-step" style="margin-top:14px"><span class="slm-stepnum">2</span>Move them to</p>
1153
1272
  <p class="slm-selecthelp" data-ref="categoryhelp">Select seats first \u2014 then pick the category they should sell under.</p>
1154
1273
  <div class="slm-categoryassign">${e.map(s=>`
1155
- <button type="button" class="slm-categoryrow" data-assign-category="${u(s.key)}" disabled>
1156
- <span class="dot" style="background:${u(s.color??"#6e7bff")}"></span>
1157
- <span class="slm-categorycopy"><b>${u(s.label??s.key)}</b><small data-cat-current>0 seats now</small></span>
1274
+ <button type="button" class="slm-categoryrow" data-assign-category="${b(s.key)}" disabled>
1275
+ <span class="dot" style="background:${b(s.color??"#6e7bff")}"></span>
1276
+ <span class="slm-categorycopy"><b>${b(s.label??s.key)}</b><small data-cat-current>0 seats now</small></span>
1158
1277
  <span class="slm-categoryact" data-cat-action>Move here</span>
1159
- </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 n=s.dataset.pickCategory,i=this.categorySeats(n),a=new Set(this.selectionLabels());i.length>0&&i.every(o=>a.has(o.label))?this.deselectCategories([n]):this.selectCategories([n])})}),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 n=a=>this.doc?.categories.find(o=>o.key===a)?.label??a;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([a,o])=>`${o.toLocaleString()} ${n(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 i=new Set(e.map(a=>a.label));this.els.rail?.querySelectorAll("[data-pick-category]").forEach(a=>{let o=a.dataset.pickCategory,r=this.categorySeats(o),d=r.filter(m=>i.has(m.label)).length,c=r.length>0&&d===r.length;a.classList.toggle("on",c),a.classList.toggle("partial",d>0&&!c),a.setAttribute("aria-pressed",String(c));let p=a.querySelector("[data-cat-count]");p&&(p.textContent=d?`${d.toLocaleString()}/${r.length.toLocaleString()}`:r.length.toLocaleString()),a.disabled=r.length===0}),this.els.rail?.querySelectorAll("[data-assign-category]").forEach(a=>{let o=a.dataset.assignCategory,r=[...this.labelToSeat.values()].filter(v=>v.categoryKey===o).length,d=s.get(o)??0,c=t>0&&d===t;a.disabled=t===0||c,a.classList.toggle("current",c);let p=a.querySelector("[data-cat-current]");p&&(p.textContent=`${r.toLocaleString()} ${r===1?"seat":"seats"} now`);let m=a.querySelector("[data-cat-action]");m&&(m.textContent=t===0?"Move here":c?"Already here":`Move ${(t-d).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=`
1278
+ </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 n=s.dataset.pickCategory,i=this.categorySeats(n),a=new Set(this.selectionLabels());i.length>0&&i.every(o=>a.has(o.label))?this.deselectCategories([n]):this.selectCategories([n])})}),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 n=a=>this.doc?.categories.find(o=>o.key===a)?.label??a;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([a,o])=>`${o.toLocaleString()} ${n(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 i=new Set(e.map(a=>a.label));this.els.rail?.querySelectorAll("[data-pick-category]").forEach(a=>{let o=a.dataset.pickCategory,r=this.categorySeats(o),c=r.filter(u=>i.has(u.label)).length,d=r.length>0&&c===r.length;a.classList.toggle("on",d),a.classList.toggle("partial",c>0&&!d),a.setAttribute("aria-pressed",String(d));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 o=a.dataset.assignCategory,r=[...this.labelToSeat.values()].filter(f=>f.categoryKey===o).length,c=s.get(o)??0,d=t>0&&c===t;a.disabled=t===0||d,a.classList.toggle("current",d);let h=a.querySelector("[data-cat-current]");h&&(h.textContent=`${r.toLocaleString()} ${r===1?"seat":"seats"} now`);let u=a.querySelector("[data-cat-action]");u&&(u.textContent=t===0?"Move here":d?"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=`
1160
1279
  ${this.railHeader("Tables","event",t)}
1161
1280
  <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=`
1162
1281
  ${this.railHeader("Tables","event",t)}
1163
- <div class="slm-empty">This chart has no tables. Add tables in the designer and they will appear here.</div>`;return}let s=p=>p.variableOccupancy?"variable":p.bookAsWhole?"whole":"individual",n=p=>{let m=0,v=0,g=0;for(let[f,P]of this.labelToSeat){if(P.rowId!==p.id)continue;let H=this.status.get(f);H==="held"?m++:H==="booked"?v++:H==="blocked"&&g++}let b=[v&&`${v} booked`,m&&`${m} held`,g&&`${g} blocked`].filter(Boolean);return b.length?b.join(" \xB7 "):null},i=e.map(p=>({table:p,current:s(p),locked:n(p)})),a=i.filter(p=>p.current==="individual").length,o=i.filter(p=>p.current==="whole").length,r=i.length-a-o,d=[`${a.toLocaleString()} per chair`,`${o.toLocaleString()} whole table`,r?`${r.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),c=this.tableBookingSaving;this.els.rail.innerHTML=`
1282
+ <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",n=h=>{let u=0,f=0,v=0;for(let[m,k]of this.labelToSeat){if(k.rowId!==h.id)continue;let R=this.status.get(m);R==="held"?u++:R==="booked"?f++:R==="blocked"&&v++}let g=[f&&`${f} booked`,u&&`${u} held`,v&&`${v} blocked`].filter(Boolean);return g.length?g.join(" \xB7 "):null},i=e.map(h=>({table:h,current:s(h),locked:n(h)})),a=i.filter(h=>h.current==="individual").length,o=i.filter(h=>h.current==="whole").length,r=i.length-a-o,c=[`${a.toLocaleString()} per chair`,`${o.toLocaleString()} whole table`,r?`${r.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),d=this.tableBookingSaving;this.els.rail.innerHTML=`
1164
1283
  ${this.railHeader("Tables","event",t)}
1165
- <div class="slm-tablesummary"><b>${i.length.toLocaleString()} ${i.length===1?"table":"tables"}</b><span>${u(d)}</span></div>
1284
+ <div class="slm-tablesummary"><b>${i.length.toLocaleString()} ${i.length===1?"table":"tables"}</b><span>${b(c)}</span></div>
1166
1285
  <p class="slm-eyebrow" style="margin-top:12px">Set every table at once</p>
1167
1286
  <div class="slm-row">
1168
- <button class="slm-btn ghost" data-table-all="individual"${c?" disabled":""} title="Sell every chair on its own">All per chair</button>
1169
- <button class="slm-btn ghost" data-table-all="whole"${c?" disabled":""} title="Sell every table as one booking">All whole table</button>
1287
+ <button class="slm-btn ghost" data-table-all="individual"${d?" disabled":""} title="Sell every chair on its own">All per chair</button>
1288
+ <button class="slm-btn ghost" data-table-all="whole"${d?" disabled":""} title="Sell every table as one booking">All whole table</button>
1170
1289
  </div>
1171
1290
  <p class="slm-eyebrow" style="margin-top:12px">Or one table at a time</p>
1172
- <div class="slm-tablelist">${i.map(({table:p,current:m,locked:v})=>`<div class="slm-tablerow${v?" locked":""}">
1173
- <span class="slm-tablecopy"><b>${u(p.displayLabel??p.label)}</b><small>${p.seatCount.toLocaleString()} chairs${v?` \xB7 <span class="slm-tablelock">Locked: ${u(v)}</span>`:""}</small></span>
1174
- <select class="slm-select" data-table-mode="${u(p.id)}" aria-label="Booking mode for ${u(p.displayLabel??p.label)}"
1175
- ${c||v?"disabled":""} ${v?`title="Release the ${u(v)} chairs before changing how this table sells"`:""}>
1176
- <option value="individual"${m==="individual"?" selected":""}>Per chair</option>
1177
- <option value="whole"${m==="whole"?" selected":""}>Whole table</option>
1178
- ${m==="variable"?'<option value="variable" selected>Flexible group</option>':""}
1291
+ <div class="slm-tablelist">${i.map(({table:h,current:u,locked:f})=>`<div class="slm-tablerow${f?" locked":""}">
1292
+ <span class="slm-tablecopy"><b>${b(h.displayLabel??h.label)}</b><small>${h.seatCount.toLocaleString()} chairs${f?` \xB7 <span class="slm-tablelock">Locked: ${b(f)}</span>`:""}</small></span>
1293
+ <select class="slm-select" data-table-mode="${b(h.id)}" aria-label="Booking mode for ${b(h.displayLabel??h.label)}"
1294
+ ${d||f?"disabled":""} ${f?`title="Release the ${b(f)} chairs before changing how this table sells"`:""}>
1295
+ <option value="individual"${u==="individual"?" selected":""}>Per chair</option>
1296
+ <option value="whole"${u==="whole"?" selected":""}>Whole table</option>
1297
+ ${u==="variable"?'<option value="variable" selected>Flexible group</option>':""}
1179
1298
  </select>
1180
1299
  </div>`).join("")}</div>
1181
- <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(p=>{p.addEventListener("click",()=>{this.setTableBooking(i.filter(m=>!m.locked).map(m=>m.table.id),p.dataset.tableAll)})}),this.els.rail.querySelectorAll("[data-table-mode]").forEach(p=>{p.addEventListener("change",()=>{this.setTableBooking([p.dataset.tableMode],p.value)})})}renderInspectRail(e){let t=e[e.length-1];if(!t){this.els.rail.innerHTML=`
1300
+ <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(i.filter(u=>!u.locked).map(u=>u.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=`
1182
1301
  ${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.")}
1183
- <div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",n={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},i=this.sectionByObject.get(t.rowId)??L.UNGROUPED_ID,a=this.sectionLabelById.get(i)??"Other seats",o=this.doc?.categories.find(m=>m.key===t.categoryKey),r=this.controlRoomSnapshot?.bookedValue.bySection.find(m=>m.sectionId===i),d=this.doc?.objects.find(m=>m.id===t.rowId),c=d?.type==="row"?{label:"Row",value:d.label}:d?.type==="table"?{label:"Table",value:d.label}:t.kind==="booth"?{label:"Type",value:"Booth"}:null,p=t.kind==="booth"?"Booth":"Seat";this.els.rail.innerHTML=`
1184
- ${this.railHeader("Inspect","read",`Live status and section performance for this ${p.toLowerCase()}. Click another seat to switch.`)}
1185
- <div class="slm-inspect-card">
1186
- <div class="slm-inspect-label">${u(t.label)}</div>
1187
- <div class="slm-inspect-grid">
1188
- <div><span>Status</span><b>${n[s]}</b></div>
1189
- <div><span>Section</span><b>${u(a)}</b></div>
1190
- ${c?`<div><span>${c.label}</span><b>${u(c.value)}</b></div>`:""}
1191
- <div><span>Category</span><b>${u(o?.label??t.categoryKey)}</b></div>
1192
- <div><span>Booked in section</span><b>${r?`${r.booked} of ${r.total}`:"\u2014"}</b></div>
1193
- <div><span>Section booked value</span><b>${r&&this.controlRoomSnapshot?Z(r.bookedValue,this.controlRoomSnapshot.currency):"\u2014"}</b></div>
1194
- </div>
1195
- </div>`}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(Pe(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 y&&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(n=>typeof n=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(n=>typeof n=="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}=re(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
1302
+ <div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",n={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},i=this.sectionByObject.get(t.rowId)??S.UNGROUPED_ID,a=this.sectionLabelById.get(i)??"Other seats",o=this.doc?.categories.find(c=>c.key===t.categoryKey);this.els.rail.innerHTML=`
1303
+ <div class="slm-seat-heading"><h2>${b(t.label)}</h2><span data-seat-status>${n[s]}</span></div>
1304
+ <p class="slm-note">${b(a)} \xB7 ${b(o?.label??t.categoryKey)}</p>
1305
+ <div data-ref="seat-history"></div>`;let r=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new ie(r,(c,d)=>this.withAuthRetry(()=>this.api.seatHistory(this.key,t.label,c,d)))}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(Oe(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 y&&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(n=>typeof n=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(n=>typeof n=="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}=pe(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
1196
1306
  ${this.railHeader("Sections","event","Draw sections or zones in the designer to schedule availability per area. This chart has none yet.")}
1197
1307
  <div class="slm-empty">No sections on this chart.</div>`;return}let n=[];t&&n.push(`${t} hidden`),s&&n.push(`${s} closed`);let i=n.length?n.join(" \xB7 "):"All sections open and on sale",a=t>0||s>0;this.els.rail.innerHTML=`
1198
1308
  ${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.")}
1199
- <div class="slm-availlist" data-ref="availlist">${e.map(o=>ot(o,this.availabilitySaving)).join("")}</div>
1309
+ <div class="slm-availlist" data-ref="availlist">${e.map(o=>mt(o,this.availabilitySaving)).join("")}</div>
1200
1310
  <div class="slm-availsummary">
1201
1311
  <span class="slm-availdot${a?" warn":""}"></span>
1202
- <span>${u(i)}</span>
1312
+ <span>${b(i)}</span>
1203
1313
  </div>
1204
1314
  <div class="slm-availcallout">
1205
1315
  <span class="slm-availstar" aria-hidden="true">\u2726</span>
1206
1316
  <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>
1207
- </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=re(this.sectionRowsInput()).rows.find(o=>o.id===e),n=s?.seatLabels??this.availabilityRules[e]?.labels??[],i={...this.availabilityRules},a=Je(t,n,this.availabilityRules[e]);if(a?i[e]=a:delete i[e],s?.kind==="zone"&&this.sectionsBase)for(let o of this.sectionsBase.sections)o.zone===e&&delete i[o.id];this.persistAvailability(i)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let i=re(this.sectionRowsInput()).rows.find(a=>a.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:i}})}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(Pe(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=st.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
1208
- <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 n=s.count>1?` +${s.count-1}`:"",i=s.sectionLabels??[],a=i.length===1?i[0]:i.length>1?`${i.length} sections`:"";return`<button type="button" class="slm-feedrow" data-feed-id="${u(s.id)}" title="Locate this activity on the map">
1209
- <span class="slm-feeddot" style="background:${t[s.status]}"></span>
1210
- <span class="slm-feedtext">${a?`<span class="slm-feedsection">${u(a)}</span>`:""}${s.count===1?"Seat":"Seats"} <b>${u(s.label)}${n}</b> ${u(s.verb)}</span>
1211
- <span class="slm-feedmeta"><span class="slm-feedtime">${Ie(s.at,e)}</span><span class="slm-feedlocate">Locate</span></span>
1212
- </button>`}).join("")}renderBlockRail(){let t=(this.doc?.categories??[]).map(c=>`<button class="slm-chip" type="button" data-cat="${u(c.key)}" aria-pressed="false">
1213
- <span class="dot" style="background:${u(c.color??"#6e7bff")}"></span>
1214
- <span>${u(c.label??c.key)}</span>
1317
+ </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(n=>{n!==t&&(n.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 n=[...t.querySelectorAll("button")],i=n.indexOf(document.activeElement);n[(i+(s.key==="ArrowDown"?1:n.length-1)+n.length)%n.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=pe(this.sectionRowsInput()).rows.find(o=>o.id===e),n=s?.seatLabels??this.availabilityRules[e]?.labels??[],i={...this.availabilityRules},a=at(t,n,this.availabilityRules[e]);if(a?i[e]=a:delete i[e],s?.kind==="zone"&&this.sectionsBase)for(let o of this.sectionsBase.sections)o.zone===e&&delete i[o.id];this.persistAvailability(i)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let i=pe(this.sectionRowsInput()).rows.find(a=>a.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:i}})}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(Oe(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=rt.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
1318
+ <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(d=>`<button class="slm-chip" type="button" data-cat="${b(d.key)}" aria-pressed="false">
1319
+ <span class="dot" style="background:${b(d.color??"#6e7bff")}"></span>
1320
+ <span>${b(d.label??d.key)}</span>
1215
1321
  <span class="slm-chipcount" data-cat-count>0</span>
1216
1322
  <span class="slm-chipcheck" aria-hidden="true">\u2713</span>
1217
1323
  </button>`).join(""),s=this.sectionOptions.length?`<div class="slm-field"><label>Select a whole section</label>
1218
1324
  <select class="slm-select" data-ref="section"><option value="">Choose a section\u2026</option>
1219
- ${this.sectionOptions.map(c=>`<option value="${u(c.id)}">${u(c.label)}</option>`).join("")}</select></div>`:"",n=this.sectionOptions.map(c=>`<option value="${u(c.id)}">${u(c.label)}</option>`).join("");this.els.rail.innerHTML=`
1220
- ${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.")}
1325
+ ${this.sectionOptions.map(d=>`<option value="${b(d.id)}">${b(d.label)}</option>`).join("")}</select></div>`:"",n=this.sectionOptions.map(d=>`<option value="${b(d.id)}">${b(d.label)}</option>`).join("");this.els.rail.innerHTML=`
1326
+ <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>
1327
+ <p class="slm-note">\u25A7 Blocked \xB7 \u25CF Green: booked \xB7 \u25CF Gold: held</p>
1221
1328
  <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>
1222
1329
  <div class="slm-row">
1223
1330
  <button class="slm-btn" data-ref="doblock" disabled>Block</button>
1224
1331
  <button class="slm-btn ghost" data-ref="dounblock" disabled>Put back on sale</button>
1225
1332
  </div>
1333
+ <div data-block-editor ${this.blockBrowse?"hidden":""}>
1226
1334
  <div class="slm-row">
1227
1335
  <button class="slm-btn ghost" data-ref="selall">Select all</button>
1228
1336
  <button class="slm-btn ghost" data-ref="clearsel">Clear</button>
@@ -1236,7 +1344,8 @@
1236
1344
  <input type="datetime-local" class="slm-input" data-ref="release" />
1237
1345
  <p class="slm-note" data-ref="releasenote">Leave empty to block permanently.</p>
1238
1346
  </div>
1239
- <section class="slm-blocked" aria-labelledby="slm-blocked-title">
1347
+ </div>
1348
+ <section ${this.blockBrowse?"":"hidden"} class="slm-blocked" aria-labelledby="slm-blocked-title">
1240
1349
  <div class="slm-blockedhead">
1241
1350
  <p class="slm-eyebrow" id="slm-blocked-title">Blocked inventory</p>
1242
1351
  <span class="slm-blockedtotal"><b data-ref="blockedcount">0</b> out of sale</span>
@@ -1254,12 +1363,9 @@
1254
1363
  </div>
1255
1364
  <div class="slm-blockedlist" data-ref="blockedlist"></div>
1256
1365
  </section>
1257
- <div class="slm-field">
1366
+ <details ${this.blockBrowse?"":"hidden"}><summary>More actions</summary><div class="slm-field">
1258
1367
  <button class="slm-btn ghost" data-ref="markall" style="width:100%" disabled>Put all blocked seats on sale</button>
1259
1368
  <p class="slm-note slm-allnote" data-ref="markallnote">For a full reset only. You will be asked to confirm.</p>
1260
- </div>
1261
- `;let i=c=>this.els.rail.querySelector(`[data-ref="${c}"]`);this.els.selnum=i("selnum"),this.els.doblock=i("doblock"),this.els.dounblock=i("dounblock"),this.els.selmeta=i("selmeta"),this.els.blockedcount=i("blockedcount"),this.els.blockedshowing=i("blockedshowing"),this.els.blockedlist=i("blockedlist"),this.els.selblocked=i("selblocked"),this.els.markall=i("markall"),this.els.markallnote=i("markallnote"),i("doblock").addEventListener("click",()=>{this.block()}),i("dounblock").addEventListener("click",()=>{this.unblock()}),i("selall").addEventListener("click",()=>this.selectAll()),i("clearsel").addEventListener("click",()=>this.clearSelection()),i("markall").addEventListener("click",()=>this.confirmUnblockAll()),this.els.rail.querySelectorAll("[data-cat]").forEach(c=>c.addEventListener("click",()=>this.toggleCategory(c.dataset.cat)));let a=this.els.rail.querySelector('[data-ref="section"]');a?.addEventListener("change",()=>{a.value&&(this.selectSection(a.value),a.value="")});let o=i("blockedsearch"),r=i("blockedsection");o.value=this.blockedQuery,r.value=this.blockedSection,o.addEventListener("input",()=>{this.blockedQuery=o.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),r.addEventListener("change",()=>{this.blockedSection=r.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),i("selblocked").addEventListener("click",()=>{this.toggleLabels(this.filteredBlockedSeats().map(c=>c.label))}),i("blockedlist").addEventListener("click",c=>{let p=c.target,m=p.closest("[data-blocked-label]");m?.dataset.blockedLabel?this.toggleLabels([m.dataset.blockedLabel]):p.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let d=i("release");d.addEventListener("change",()=>{let c=d.value?new Date(d.value).getTime():NaN;this.releaseAt=Number.isFinite(c)&&c>Date.now()?c:null;let p=i("releasenote");p.textContent=this.releaseAt?`New blocks auto-release ${new Date(this.releaseAt).toLocaleString()}.`:d.value?"Pick a time in the future.":"Leave empty to block permanently."}),this.paintSelBar(this.getSelection())}toggleCategory(e){let t=[];for(let[s,n]of this.labelToSeat.entries())n.categoryKey===e&&this.isBlockSelectable(s)&&t.push(s);this.toggleLabels(t)}toggleLabels(e){if(!this.renderer)return;let t=e.filter(i=>this.labelToSeat.has(i)&&this.isBlockSelectable(i));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(i=>s.has(i))){let i=t.map(a=>this.labelToId.get(a)).filter(a=>!!a);this.renderer.deselect(i)}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 n=this.els.doblock,i=this.els.dounblock;n.disabled=t===0,i.disabled=s===0,n.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",i.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 n=s.dataset.cat,i=[];for(let[c,p]of this.labelToSeat.entries())p.categoryKey===n&&this.isBlockSelectable(c)&&i.push(c);let a=i.filter(c=>t.has(c)).length,o=i.length>0&&a===i.length,r=a>0&&!o;s.disabled=i.length===0,s.classList.toggle("on",o),s.classList.toggle("partial",r),s.setAttribute("aria-pressed",o?"true":r?"mixed":"false"),s.setAttribute("title",o?`Remove all ${i.length.toLocaleString()} seats in this category from the selection`:r?`Select the remaining ${(i.length-a).toLocaleString()} seats in this category`:`Select all ${i.length.toLocaleString()} seats in this category`);let d=s.querySelector("[data-cat-count]");d&&(d.textContent=a?`${a.toLocaleString()}/${i.length.toLocaleString()}`:i.length.toLocaleString())})}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,n]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let i=this.sectionByObject.get(n.rowId)??L.UNGROUPED_ID;if(!(this.blockedSection&&i!==this.blockedSection)){if(e){let a=this.doc?.categories.find(p=>p.key===n.categoryKey)?.label??n.categoryKey,o=this.sectionLabelById.get(i)??"Other seats",r=this.doc?.objects.find(p=>p.id===n.rowId),d=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${a} ${o} ${d}`.toLocaleLowerCase().includes(e))continue}t.push(n)}}return t.sort((s,n)=>s.label.localeCompare(n.label,void 0,{numeric:!0,sensitivity:"base"}))}paintBlockedInventory(){if(!this.els.blockedlist)return;let e=[...this.status.entries()].filter(([,c])=>c==="blocked").length,t=this.filteredBlockedSeats(),s=t.slice(0,this.blockedResultLimit),n=new Set(this.selectionLabels()),i=t.filter(c=>n.has(c.label)).length,a=t.length>0&&i===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 o=this.els.selblocked;o.disabled=t.length===0,o.textContent=a?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`,this.els.blockedlist.innerHTML=s.length?s.map(c=>{let p=this.sectionByObject.get(c.rowId)??L.UNGROUPED_ID,m=this.sectionLabelById.get(p)??"Other seats",v=this.doc?.categories.find(b=>b.key===c.categoryKey)?.label??c.categoryKey,g=n.has(c.label);return`<button type="button" class="slm-blockeditem${g?" on":""}" data-blocked-label="${u(c.label)}" aria-pressed="${g}">
1262
- <span class="slm-blockedcheck" aria-hidden="true">\u2713</span>
1263
- <span class="slm-blockedcopy"><span class="slm-blockedlabel">${u(c.label)}</span>
1264
- <span class="slm-blockedmeta">${u(m)} \xB7 ${u(v)}</span></span>
1265
- </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,d=r.dataset.confirm==="true";r.disabled=e===0,r.textContent=d?`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 n=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;n&&this.paintSpatialActivity(n)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(n=>this.opts.onError?.(n)),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>`)}};Fe();Se();ae();0&&(module.exports={ACCESS_LINK_DEFAULTS,ChannelsMode,ManageApi,ManageApiError,PUBLIC_CHANNEL_ID,PUBLIC_CHANNEL_NAME,SeatManager,accessIntentDescription,accessIntentLabel,accessLine,accessLinkBadge,accessLinkErrorCopy,accessLinkIsLive,accessLinkPolicyLines,bucketRows,bucketRowsHtml,dropReviewRows,intentForbidsCopy,intentSwitchBlockedCopy,isPublicChannelId,markerLetter,markerOf,mutationCount,needsMoveConfirmation,planAssignment,retryAfterCopy,selectionSources,stateBadge,suggestMarker});
1369
+ </div></details>
1370
+ `,this.els.rail.querySelectorAll("[data-block-tab]").forEach(d=>d.addEventListener("click",()=>{this.blockBrowse=d.dataset.blockTab==="browse",this.renderBlockRail()}));let i=d=>this.els.rail.querySelector(`[data-ref="${d}"]`);this.els.selnum=i("selnum"),this.els.doblock=i("doblock"),this.els.dounblock=i("dounblock"),this.els.selmeta=i("selmeta"),this.els.blockedcount=i("blockedcount"),this.els.blockedshowing=i("blockedshowing"),this.els.blockedlist=i("blockedlist"),this.els.selblocked=i("selblocked"),this.els.markall=i("markall"),this.els.markallnote=i("markallnote"),i("doblock").addEventListener("click",()=>{this.block()}),i("dounblock").addEventListener("click",()=>{this.unblock()}),i("selall").addEventListener("click",()=>this.selectAll()),i("clearsel").addEventListener("click",()=>this.clearSelection()),i("markall").addEventListener("click",()=>this.confirmUnblockAll()),this.els.rail.querySelectorAll("[data-cat]").forEach(d=>d.addEventListener("click",()=>this.toggleCategory(d.dataset.cat)));let a=this.els.rail.querySelector('[data-ref="section"]');a?.addEventListener("change",()=>{a.value&&(this.selectSection(a.value),a.value="")});let o=i("blockedsearch"),r=i("blockedsection");o.value=this.blockedQuery,r.value=this.blockedSection,o.addEventListener("input",()=>{this.blockedQuery=o.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),r.addEventListener("change",()=>{this.blockedSection=r.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),i("selblocked").addEventListener("click",()=>{this.toggleLabels(this.filteredBlockedSeats().map(d=>d.label))}),i("blockedlist").addEventListener("click",d=>{let h=d.target,u=h.closest("[data-block-seat-find]");if(u?.dataset.blockSeatFind){let m=this.labelToSeat.get(u.dataset.blockSeatFind);m&&(this.setFollowLive(!1),this.focusActivitySeats([m.label],this.sectionByObject.get(m.rowId)??S.UNGROUPED_ID));return}let f=h.closest("[data-block-locate]"),v=h.closest("[data-block-group]");if(f||v){let m=f?.dataset.blockLocate??v?.dataset.blockGroup,k=this.filteredBlockedSeats().filter(R=>R.rowId===m);f&&k.length&&(this.setFollowLive(!1),this.focusActivitySeats(k.map(R=>R.label),this.sectionByObject.get(k[0].rowId)??S.UNGROUPED_ID)),v&&this.toggleLabels(k.map(R=>R.label));return}let g=h.closest("[data-blocked-label]");g?.dataset.blockedLabel?this.toggleLabels([g.dataset.blockedLabel]):h.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let c=i("release");c.addEventListener("change",()=>{let d=c.value?new Date(c.value).getTime():NaN;this.releaseAt=Number.isFinite(d)&&d>Date.now()?d:null;let h=i("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,n]of this.labelToSeat.entries())n.categoryKey===e&&this.isBlockSelectable(s)&&t.push(s);this.toggleLabels(t)}toggleLabels(e){if(!this.renderer)return;let t=e.filter(i=>this.labelToSeat.has(i)&&this.isBlockSelectable(i));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(i=>s.has(i))){let i=t.map(a=>this.labelToId.get(a)).filter(a=>!!a);this.renderer.deselect(i)}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 n=this.els.doblock,i=this.els.dounblock;n.disabled=t===0,i.disabled=s===0,n.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",i.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 n=s.dataset.cat,i=[];for(let[d,h]of this.labelToSeat.entries())h.categoryKey===n&&this.isBlockSelectable(d)&&i.push(d);let a=i.filter(d=>t.has(d)).length,o=i.length>0&&a===i.length,r=a>0&&!o;s.disabled=i.length===0,s.classList.toggle("on",o),s.classList.toggle("partial",r),s.setAttribute("aria-pressed",o?"true":r?"mixed":"false"),s.setAttribute("title",o?`Remove all ${i.length.toLocaleString()} seats in this category from the selection`:r?`Select the remaining ${(i.length-a).toLocaleString()} seats in this category`:`Select all ${i.length.toLocaleString()} seats in this category`);let c=s.querySelector("[data-cat-count]");c&&(c.textContent=a?`${a.toLocaleString()}/${i.length.toLocaleString()}`:i.length.toLocaleString())})}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,n]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let i=this.sectionByObject.get(n.rowId)??S.UNGROUPED_ID;if(!(this.blockedSection&&i!==this.blockedSection)){if(e){let a=this.doc?.categories.find(h=>h.key===n.categoryKey)?.label??n.categoryKey,o=this.sectionLabelById.get(i)??"Other seats",r=this.doc?.objects.find(h=>h.id===n.rowId),c=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${a} ${o} ${c}`.toLocaleLowerCase().includes(e))continue}t.push(n)}}return t.sort((s,n)=>s.label.localeCompare(n.label,void 0,{numeric:!0,sensitivity:"base"}))}paintBlockedInventory(){if(!this.els.blockedlist)return;let e=[...this.status.entries()].filter(([,h])=>h==="blocked").length,t=this.filteredBlockedSeats(),s=t.slice(0,this.blockedResultLimit),n=new Set(this.selectionLabels()),i=t.filter(h=>n.has(h.label)).length,a=t.length>0&&i===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 o=this.els.selblocked;o.disabled=t.length===0,o.textContent=a?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`;let r=new Map;for(let h of t){let u=r.get(h.rowId)??[];u.push(h),r.set(h.rowId,u)}this.els.blockedshowing.textContent=`${t.length.toLocaleString()} seats \xB7 ${r.size} rows`,this.els.blockedlist.innerHTML=[...r.entries()].slice(0,this.blockedResultLimit).map(([h,u])=>{let f=this.sectionByObject.get(h)??S.UNGROUPED_ID,v=this.sectionLabelById.get(f)??"Other seats",g=this.doc?.objects.find(k=>k.id===h),m=g&&"label"in g?g.label:u[0].label;return`<div class="slm-block-group"><div class="slm-block-grouphead"><button type="button" data-block-locate="${b(h)}" title="Show this row and nearby seats on the map"><b>${b(m)}</b><small>${b(v)} \xB7 ${u.length} blocked</small></button><button type="button" data-block-group="${b(h)}">Select row</button></div>
1371
+ <details><summary>Choose seats</summary>${u.map(k=>`<div class="slm-block-seatline"><button type="button" class="slm-blockeditem${n.has(k.label)?" on":""}" data-blocked-label="${b(k.label)}" aria-pressed="${n.has(k.label)}"><span class="slm-blockedcheck" aria-hidden="true">\u2713</span><span>${b(k.label)}</span></button><button type="button" data-block-seat-find="${b(k.label)}" aria-label="Show ${b(k.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,d=c.dataset.confirm==="true";c.disabled=e===0,c.textContent=d?`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 n=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;n&&this.paintSpatialActivity(n)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(n=>this.opts.onError?.(n)),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>`)}};_e();Re();re();0&&(module.exports={ACCESS_LINK_DEFAULTS,ChannelsMode,ManageApi,ManageApiError,PUBLIC_CHANNEL_ID,PUBLIC_CHANNEL_NAME,SeatManager,accessIntentDescription,accessIntentLabel,accessLine,accessLinkBadge,accessLinkErrorCopy,accessLinkIsLive,accessLinkPolicyLines,bucketRows,bucketRowsHtml,dropReviewRows,intentForbidsCopy,intentSwitchBlockedCopy,isPublicChannelId,markerLetter,markerOf,mutationCount,needsMoveConfirmation,planAssignment,retryAfterCopy,selectionSources,stateBadge,suggestMarker});