@seatlayer/js 0.49.0 → 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2756,7 +2756,12 @@ var CSS2 = (
2756
2756
  never inherits (or fights) the host page's own timing. Values mirror
2757
2757
  docs/motion-system-2026-08-01.md \xA72. */
2758
2758
  --slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;
2759
- --slm-mo-out:cubic-bezier(0.2,0.8,0.2,1);--slm-mo-exit:cubic-bezier(0.4,0,1,1)}
2759
+ --slm-mo-out:cubic-bezier(0.2,0.8,0.2,1);--slm-mo-exit:cubic-bezier(0.4,0,1,1);
2760
+ /* Semantic palette tokens, defined here (not resolveTokens) because they are
2761
+ the WIDGET's meanings, not an org's brand: premium gold, environment
2762
+ warning, danger, success. Hosts can still override them with CSS. */
2763
+ --sl-premium:#e8c15a;--sl-premium-deep:#c9a24b;--sl-premium-ink:#1c1608;
2764
+ --sl-warn:#d8a425;--sl-danger:#e5484d;--sl-success:#22a06b}
2760
2765
  .sl-picker *{box-sizing:border-box;margin:0;padding:0}
2761
2766
  .sl-picker button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
2762
2767
 
@@ -2782,21 +2787,41 @@ var CSS2 = (
2782
2787
  .sl-close.on{display:inline-flex}
2783
2788
  .sl-close svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}
2784
2789
 
2785
- /* A page or popup may already own the event heading. In that case only the
2786
- duplicate identity disappears; operational header controls stay available.
2787
- Zero block padding lets an otherwise-empty header collapse completely. */
2788
- .sl-picker[data-event-details-hidden="true"] .sl-head{padding-block:0;border-bottom-width:0}
2789
- .sl-picker[data-event-details-hidden="true"] .sl-logo,
2790
- .sl-picker[data-event-details-hidden="true"] .sl-head-info{display:none!important}
2791
- .sl-picker[data-event-details-hidden="true"] .sl-hold-pill.on,
2792
- .sl-picker[data-event-details-hidden="true"] .sl-closed-pill.on,
2793
- .sl-picker[data-event-details-hidden="true"] .sl-close.on{margin-block:10px}
2790
+ /* A page or popup may already own the event heading \u2014 but "already" is true at
2791
+ load and false thirty seconds later: the buyer scrolls, the sheet opens over
2792
+ the map, fullscreen removes the page, and two-tab comparison shopping is
2793
+ normal ticket behaviour. So identity DEMOTES instead of disappearing: one
2794
+ compact line (thumb + name) that answers "which event is this money for"
2795
+ without competing with the host's own heading. The hold clock keeps a
2796
+ labelled row around it instead of floating in a dark corner. */
2797
+ .sl-picker[data-event-details-hidden="true"] .sl-head{padding-block:7px}
2798
+ .sl-picker[data-event-details-hidden="true"] .sl-logo{width:22px;height:22px;border-radius:6px;font-size:11px}
2799
+ .sl-picker[data-event-details-hidden="true"] .sl-head-name{font-size:12.5px}
2800
+ .sl-picker[data-event-details-hidden="true"] .sl-head-meta{display:none}
2794
2801
 
2795
2802
  /* body */
2796
2803
  .sl-body{display:flex;flex:1;min-height:0}
2797
2804
  .sl-map{position:relative;flex:1;min-width:0}
2798
2805
  .sl-map-host{position:absolute;inset:0}
2799
2806
  .sl-side{width:300px;flex:none;border-left:1px solid var(--sl-line);display:flex;flex-direction:column;min-height:0;overflow:hidden}
2807
+ /* Wide-layout panel collapse: THE CHART IS THE PRODUCT, and a fixed 300px
2808
+ panel holding an empty cart is the map's room spent on nothing. The panel
2809
+ slides to zero (children keep their laid-out width so text doesn't rewrap
2810
+ mid-slide); the "Tickets" pill in the top-right region brings it back, and
2811
+ the first seat landing in the cart reopens it automatically \u2014 a collapsed
2812
+ panel must never hide a checkout. */
2813
+ .sl-picker[data-layout="wide"] .sl-side{transition:width var(--slm-mo-slow) var(--slm-mo-out)}
2814
+ .sl-picker[data-layout="wide"][data-side-collapsed="true"] .sl-side{width:0;min-width:0;border-left-width:0}
2815
+ /* min-width:0 above is load-bearing: the panel is a flex item, and its
2816
+ automatic minimum size (from these 300px-wide children) would otherwise
2817
+ clamp the explicit width:0 straight back to 300 \u2014 verified in-browser. */
2818
+ .sl-picker[data-layout="wide"][data-side-collapsed="true"] .sl-side>*{min-width:300px}
2819
+ .sl-side-toggle{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:36px;padding:0 12px;
2820
+ border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.02em;white-space:nowrap;
2821
+ background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}
2822
+ .sl-side-toggle:hover{border-color:var(--sl-muted)}
2823
+ .sl-side-toggle svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none;stroke-linecap:round;stroke-linejoin:round}
2824
+ .sl-picker[data-layout="narrow"] .sl-side-toggle{display:none}
2800
2825
 
2801
2826
  /* narrow (container < 640px): map-first \u2014 the map claims ~80-85% of the
2802
2827
  container and the side panel becomes a PEEKING bottom sheet (AXS/Ticketmaster
@@ -2879,6 +2904,15 @@ var CSS2 = (
2879
2904
  the buyer explicitly opens the ticket panel. */
2880
2905
  .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-filtersec.has{display:block!important}
2881
2906
  .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-filters.has{display:flex!important}
2907
+ /* The price list is the mobile buyer's ONLY legend \u2014 colour \u2192 ticket type \u2192
2908
+ price \u2192 how many are left. Hiding it in the peek state is right (map-first);
2909
+ never restoring it forced phone buyers to tap dots to learn prices. The OPEN
2910
+ sheet brings it back, exactly like the filters row above. The tray hint comes
2911
+ back with it: the first-time buyer on a phone needs the instruction more than
2912
+ the desktop buyer, not less. */
2913
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-prices-sec{display:flex!important}
2914
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-prices{display:flex!important}
2915
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-tray-hint{display:block!important}
2882
2916
  .sl-cbbtn{width:32px;height:32px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);
2883
2917
  color:var(--sl-text);display:flex;align-items:center;justify-content:center;transition:border-color .15s}
2884
2918
  .sl-cbbtn:hover{border-color:var(--sl-muted)}
@@ -2888,13 +2922,13 @@ var CSS2 = (
2888
2922
  .sl-offer{display:none;margin:12px 14px 2px;padding:12px;border:1px solid color-mix(in srgb,var(--sl-accent) 34%,var(--sl-line));
2889
2923
  border-radius:12px;background:color-mix(in srgb,var(--sl-accent) 8%,var(--sl-surface));color:var(--sl-text)}
2890
2924
  .sl-offer.has{display:block}.sl-offer-main{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
2891
- .sl-offer-copy{min-width:0}.sl-offer-kicker{display:block;font-size:9px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-accent)}
2925
+ .sl-offer-copy{min-width:0}.sl-offer-kicker{display:block;font-size:10px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-accent)}
2892
2926
  .sl-offer-name{display:block;margin-top:2px;font-size:13px;font-weight:800;line-height:1.3}.sl-offer-line{display:block;margin-top:3px;font-size:11px;line-height:1.35;color:var(--sl-muted)}
2893
2927
  .sl-offer-info{position:relative;flex:none}.sl-offer-info>summary{list-style:none;width:25px;height:25px;border:1px solid var(--sl-line);border-radius:999px;
2894
2928
  display:grid;place-items:center;cursor:pointer;font-size:12px;font-weight:850;color:var(--sl-text);background:var(--sl-surface)}
2895
2929
  .sl-offer-info>summary::-webkit-details-marker{display:none}.sl-offer-info[open]>summary{border-color:var(--sl-accent);color:var(--sl-accent)}
2896
2930
  .sl-offer-detail{margin-top:10px;padding-top:9px;border-top:1px solid var(--sl-line);font-size:10.5px;line-height:1.45;color:var(--sl-muted)}
2897
- .sl-sec{padding:14px 14px 4px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}
2931
+ .sl-sec{padding:14px 14px 4px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}
2898
2932
  .sl-prices-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}
2899
2933
  .sl-price-select{min-height:32px;max-width:130px;padding:5px 28px 5px 9px;border:1px solid var(--sl-line);border-radius:9px;
2900
2934
  background:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}
@@ -2904,7 +2938,7 @@ var CSS2 = (
2904
2938
  padding:0 6px;margin:0 -6px;border-radius:8px;cursor:pointer;transition:background .15s}
2905
2939
  .sl-price-row:hover,.sl-price-row:focus-visible{background:color-mix(in srgb,var(--sl-line) 40%,transparent)}
2906
2940
  .sl-price-row.sl-active{background:color-mix(in srgb,var(--sl-accent) 9%,transparent)}
2907
- .sl-price-was{margin-left:auto;color:var(--sl-muted);font-size:10px;text-decoration:line-through}.sl-price-offer{display:block;color:var(--sl-accent);font-size:9px;font-weight:750}
2941
+ .sl-price-was{margin-left:auto;color:var(--sl-muted);font-size:10px;text-decoration:line-through}.sl-price-offer{display:block;color:var(--sl-accent);font-size:10px;font-weight:750}
2908
2942
  .sl-price-row.sl-active .sl-price-label{color:var(--sl-accent)}
2909
2943
  .sl-dot{width:9px;height:9px;border-radius:50%;flex:none}
2910
2944
  .sl-price-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}
@@ -2947,7 +2981,7 @@ var CSS2 = (
2947
2981
  .sl-chip-id .fld{min-width:0}
2948
2982
  .sl-chip-id .fld.sec{flex:1}
2949
2983
  .sl-chip-id .fld.mid{flex:none;text-align:center}
2950
- .sl-chip-eb{display:block;font-size:8px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);margin-bottom:1px}
2984
+ .sl-chip-eb{display:block;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);margin-bottom:1px}
2951
2985
  .sl-chip-id .val{display:block;font-weight:600;font-size:13px;line-height:1.25;white-space:nowrap}
2952
2986
  .sl-chip-id .fld.sec .val{overflow:hidden;text-overflow:ellipsis}
2953
2987
  .sl-chip-sub{display:flex;align-items:center;gap:6px;min-width:0}
@@ -2957,7 +2991,7 @@ var CSS2 = (
2957
2991
  .sl-chip .rm,.sl-chip .view{flex:1;min-height:26px;border-radius:0;display:flex;align-items:center;justify-content:center;
2958
2992
  color:var(--sl-muted);transition:color .15s,background .15s}
2959
2993
  .sl-chip .view{border-top:1px solid var(--sl-line)}
2960
- .sl-chip .rm:hover,.sl-chip .rm:focus-visible{color:#e5484d;background:color-mix(in srgb,#e5484d 9%,transparent)}
2994
+ .sl-chip .rm:hover,.sl-chip .rm:focus-visible{color:var(--sl-danger);background:color-mix(in srgb,var(--sl-danger) 9%,transparent)}
2961
2995
  .sl-chip .view:hover,.sl-chip .view:focus-visible{color:var(--sl-text);background:color-mix(in srgb,var(--sl-accent) 10%,transparent)}
2962
2996
  .sl-chip .rm svg{width:11px;height:11px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round}
2963
2997
  .sl-chip .view svg{width:13px;height:13px;stroke:currentColor;stroke-width:1.8;fill:none}
@@ -2967,7 +3001,7 @@ var CSS2 = (
2967
3001
  .sl-live{display:none;align-items:center;gap:7px;margin:10px 14px 0;padding:7px 9px;flex:none;
2968
3002
  border:1px solid var(--sl-line);border-radius:8px;background:color-mix(in srgb,var(--sl-accent) 4%,var(--sl-surface));
2969
3003
  font-size:11px;color:var(--sl-muted)}
2970
- .sl-live .dot{width:6px;height:6px;border-radius:999px;background:#22a06b;box-shadow:0 0 6px rgba(34,160,107,.75);flex:none}
3004
+ .sl-live .dot{width:6px;height:6px;border-radius:999px;background:var(--sl-success);box-shadow:0 0 6px color-mix(in srgb,var(--sl-success) 75%,transparent);flex:none}
2971
3005
  .sl-live span:last-child{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
2972
3006
  .sl-live.on{display:flex;animation:slNoticeIn .38s cubic-bezier(.2,.8,.2,1) both}
2973
3007
 
@@ -3037,17 +3071,17 @@ var CSS2 = (
3037
3071
  .sl-picker[data-layout="narrow"] .sl-anchor[data-region="top-left"]{max-width:30%}
3038
3072
  .sl-picker[data-layout="narrow"] .sl-anchor[data-region="top-center"]{max-width:44%}
3039
3073
 
3040
- /* TEST MODE is environment context, not an action. A clipped corner ribbon
3041
- keeps it persistent without impersonating a button or competing with Map/3D.
3042
- The top-left interactive region moves below it only on test events. */
3043
- .sl-testbadge{position:absolute;top:17px;left:-38px;z-index:6;width:142px;padding:5px 0;
3044
- transform:rotate(-45deg);text-align:center;pointer-events:none;
3045
- font-size:9.5px;font-weight:850;letter-spacing:.13em;line-height:1.2;text-transform:uppercase;
3046
- white-space:nowrap;background:var(--sl-accent);color:var(--sl-accent-ink);
3047
- box-shadow:0 2px 8px rgba(0,0,0,.28)}
3048
- .sl-picker[data-event-mode="test"] .sl-anchor[data-region="top-left"]{top:96px}
3049
- .sl-picker[data-layout="narrow"] .sl-testbadge{top:14px;left:-35px;width:128px;font-size:8.5px}
3050
- .sl-picker[data-layout="narrow"][data-event-mode="test"] .sl-anchor[data-region="top-left"]{top:88px}
3074
+ /* TEST MODE is environment context, not an action. A small squared chip that
3075
+ flows FIRST in the top-left anchor region: the old rotated corner ribbon sat
3076
+ at a negative offset and was clipped by the widget root's rounded
3077
+ overflow:hidden (its ends cut mid-word), and its accent fill made an
3078
+ environment flag wear the same gold as "buy". Amber warning tone, dashed
3079
+ border \u2014 reads as a tag, never as a control; the a11y chips wrap beside it
3080
+ in the same region, so no displacement hack is needed. */
3081
+ .sl-testbadge{display:inline-flex;align-items:center;padding:5px 10px;border-radius:7px;pointer-events:none;
3082
+ font-size:10px;font-weight:850;letter-spacing:.13em;line-height:1.2;text-transform:uppercase;white-space:nowrap;
3083
+ color:var(--sl-warn);background:color-mix(in srgb,var(--sl-warn) 13%,var(--sl-surface));
3084
+ border:1px dashed color-mix(in srgb,var(--sl-warn) 55%,transparent)}
3051
3085
 
3052
3086
  /* zoom column (flows within the bottom-right region) */
3053
3087
  .sl-zoom{display:flex;flex-direction:column;gap:6px}
@@ -3057,6 +3091,18 @@ var CSS2 = (
3057
3091
  color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}
3058
3092
  .sl-zoom button:hover{border-color:var(--sl-muted)}
3059
3093
  .sl-zoom svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
3094
+ /* Full-screen promotion on phones: the capability existed (native + iOS overlay
3095
+ + framed-host paths) but hid as the 4th unlabelled glyph in a corner stack.
3096
+ On narrow layouts dockLayoutChrome moves the SAME button into the top-right
3097
+ region beside Map|3D and this class dresses it as a labelled pill \u2014 the one
3098
+ accelerator with the highest payoff on a small screen gets words. */
3099
+ .sl-zfs-lbl{display:none}
3100
+ .sl-fs-pill.sl-fs-pill{display:inline-flex;align-items:center;justify-content:center;width:auto;min-height:40px;height:auto;
3101
+ padding:0 13px;gap:6px;border-radius:999px;font-size:11px;font-weight:800;
3102
+ background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}
3103
+ .sl-fs-pill.sl-fs-pill:hover{border-color:var(--sl-muted)}
3104
+ .sl-fs-pill svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
3105
+ .sl-fs-pill .sl-zfs-lbl{display:inline;letter-spacing:.02em;white-space:nowrap}
3060
3106
 
3061
3107
  /* toast + boot states (toast flows in the bottom-center region) */
3062
3108
  .sl-toast{transform:translateY(6px) scale(.98);max-width:100%;
@@ -3067,9 +3113,9 @@ var CSS2 = (
3067
3113
  .sl-toast.has-action{pointer-events:auto;display:flex;align-items:center;gap:12px;padding-right:8px}
3068
3114
  .sl-toast-action{min-height:30px;padding:5px 10px;border-radius:999px;background:var(--sl-accent);color:var(--sl-accent-ink);
3069
3115
  font:inherit;font-weight:800}
3070
- .sl-toast[data-tone="error"]{border-color:#ef4444}
3116
+ .sl-toast[data-tone="error"]{border-color:var(--sl-danger)}
3071
3117
  .sl-toast[data-tone="warning"]{border-color:var(--sl-accent)}
3072
- .sl-toast[data-tone="success"]{border-color:#22c55e}
3118
+ .sl-toast[data-tone="success"]{border-color:var(--sl-success)}
3073
3119
  .sl-toast.on[data-tone="error"]{animation:slToastNudge .32s ease-out}
3074
3120
  .sl-boot{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;
3075
3121
  gap:10px;background:var(--sl-bg);font-size:13px;font-weight:600;color:var(--sl-muted)}
@@ -3165,7 +3211,7 @@ var CSS2 = (
3165
3211
  .sl-confirm-field{min-width:0;padding:12px 11px 10px;border-right:1px solid var(--sl-line)}
3166
3212
  .sl-confirm-field:last-child{border-right:0;text-align:center}
3167
3213
  .sl-confirm-field:nth-child(2){text-align:center}
3168
- .sl-confirm-key{display:block;font-size:8.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}
3214
+ .sl-confirm-key{display:block;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}
3169
3215
  .sl-confirm-value{display:block;margin-top:4px;color:var(--sl-text);font-size:17px;line-height:1.1;font-weight:850;
3170
3216
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
3171
3217
  /* Long venue section names must read in full: smaller type + up to two lines
@@ -3230,7 +3276,7 @@ var CSS2 = (
3230
3276
  .sl-tip-field{min-width:0;padding:6px 9px;border-right:1px solid var(--sl-line)}
3231
3277
  .sl-tip-field:last-child{border-right:0;text-align:center}
3232
3278
  .sl-tip-grid:not(.one) .sl-tip-field:nth-child(2){text-align:center}
3233
- .sl-tip-key{display:block;font-size:7.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}
3279
+ .sl-tip-key{display:block;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);font-weight:800}
3234
3280
  .sl-tip-val{display:block;margin-top:2px;color:var(--sl-text);font-size:13px;line-height:1.1;font-weight:750;
3235
3281
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
3236
3282
  .sl-tip-cat{display:flex;align-items:center;gap:7px;padding:6px 10px;font-size:11px;
@@ -3238,7 +3284,7 @@ var CSS2 = (
3238
3284
  .sl-tip-dot{width:8px;height:8px;border-radius:50%;flex:none}
3239
3285
  .sl-tip-name{color:var(--sl-muted);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
3240
3286
  .sl-tip-amt{margin-left:auto;font-weight:800;color:var(--sl-text);font-variant-numeric:tabular-nums;font-size:12px}
3241
- .sl-tip-status{padding:5px 10px 7px;font-size:8.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;color:var(--sl-muted)}
3287
+ .sl-tip-status{padding:5px 10px 7px;font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;color:var(--sl-muted)}
3242
3288
 
3243
3289
  /* Best available is a first-class shortcut, not an anonymous utility row. */
3244
3290
  .sl-ba{position:relative;flex:none;overflow:hidden;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:7px;
@@ -3254,12 +3300,12 @@ var CSS2 = (
3254
3300
  the confirm popover; deliberately distinct from the accent-toned qty/go. */
3255
3301
  .sl-ba-premium{position:relative;z-index:1;grid-column:1/-1;justify-self:start;display:inline-flex;align-items:center;gap:6px;
3256
3302
  padding:6px 12px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.02em;cursor:pointer;
3257
- color:#c9a24b;background:color-mix(in srgb,#e8c15a 10%,var(--sl-surface));
3258
- border:1px solid color-mix(in srgb,#e8c15a 34%,var(--sl-line));transition:filter .15s,background .15s,color .15s}
3259
- .sl-ba-premium .star{font-size:12px;line-height:1;color:#e8c15a}
3303
+ color:var(--sl-premium-deep);background:color-mix(in srgb,var(--sl-premium) 10%,var(--sl-surface));
3304
+ border:1px solid color-mix(in srgb,var(--sl-premium) 34%,var(--sl-line));transition:filter .15s,background .15s,color .15s}
3305
+ .sl-ba-premium .star{font-size:12px;line-height:1;color:var(--sl-premium)}
3260
3306
  .sl-ba-premium:hover{filter:brightness(1.05)}
3261
- .sl-ba-premium.on{color:#1c1608;background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;
3262
- box-shadow:0 6px 16px color-mix(in srgb,#e8c15a 26%,transparent)}
3307
+ .sl-ba-premium.on{color:var(--sl-premium-ink);background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;
3308
+ box-shadow:0 6px 16px color-mix(in srgb,var(--sl-premium) 26%,transparent)}
3263
3309
  .sl-ba-premium.on .star{color:#5a4410}
3264
3310
  .sl-ba select{background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;
3265
3311
  font:inherit;font-size:11px;padding:7px 8px;min-width:0;width:100%;max-width:none}
@@ -3271,7 +3317,15 @@ var CSS2 = (
3271
3317
  color:var(--sl-accent-ink);font-weight:800;font-size:12px;transition:filter .15s,opacity .15s;display:flex;align-items:center;justify-content:center;gap:6px;
3272
3318
  box-shadow:0 8px 18px color-mix(in srgb,var(--sl-accent) 18%,transparent)}
3273
3319
  .sl-picker .sl-ba-go:hover{filter:brightness(1.06)}
3274
- .sl-picker .sl-ba-go:disabled{opacity:.62;cursor:wait}
3320
+ /* ONE disabled language, shared with the checkout CTA: surface + muted ink +
3321
+ not-allowed. A gold button at 62% still reads as gold, and cursor:wait means
3322
+ "working" \u2014 that pairing made a dead control look live. The wait cursor is
3323
+ reserved for the genuinely in-flight search, which keeps its accent fill
3324
+ via .sl-busy. */
3325
+ .sl-picker .sl-ba-go:disabled{background:var(--sl-surface);color:var(--sl-muted);cursor:not-allowed;
3326
+ filter:none;box-shadow:none}
3327
+ .sl-picker .sl-ba-go.sl-busy:disabled{background:var(--sl-accent);color:var(--sl-accent-ink);opacity:.85;cursor:wait;
3328
+ box-shadow:0 8px 18px color-mix(in srgb,var(--sl-accent) 18%,transparent)}
3275
3329
  .sl-ba-replace{grid-column:1/-1;padding:3px 0 1px}
3276
3330
  .sl-ba-replace b{display:block;font-size:12.5px}
3277
3331
  .sl-ba-replace span{display:block;margin-top:3px;color:var(--sl-muted);font-size:10.5px;line-height:1.35}
@@ -3288,6 +3342,35 @@ var CSS2 = (
3288
3342
  .sl-picker[data-layout="narrow"] .sl-ba-qty button{width:30px;height:30px}
3289
3343
  .sl-picker[data-layout="narrow"] .sl-ba-go{min-height:40px}
3290
3344
 
3345
+ /* Sales-closed is a designed state, not a set of disables: one statement in
3346
+ the tray where the buying flow was, carrying the event's own date so the
3347
+ buyer knows which night the verdict belongs to. Neutral like the header
3348
+ pill \u2014 "unavailable" never wears the accent. */
3349
+ .sl-closed-note{flex:none;display:flex;flex-direction:column;gap:4px;padding:13px;border-radius:13px;
3350
+ border:1px solid var(--sl-line);background:color-mix(in srgb,var(--sl-text) 5%,var(--sl-surface))}
3351
+ .sl-closed-note b{font-size:13px;font-weight:850}
3352
+ .sl-closed-note span{font-size:11.5px;line-height:1.45;color:var(--sl-muted)}
3353
+ .sl-closed-note .when{display:block;margin-top:2px;font-size:11.5px;font-weight:700;color:var(--sl-text)}
3354
+
3355
+ /* 44px HIT FLOOR ON TOUCH. Visual sizes stay exactly as designed \u2014 the target
3356
+ grows through an invisible centred pseudo-element, the same grow-the-target-
3357
+ not-the-ink pattern the hosted event page documents for its footer links.
3358
+ Applied only to controls with clearance around them; tightly stacked pairs
3359
+ (the cart chip's remove/view rail) instead get real height on narrow. */
3360
+ @media (pointer:coarse){
3361
+ .sl-zoom button,.sl-cbbtn,.sl-close,.sl-ga-qty button,.sl-ba-qty button,.sl-price-more,
3362
+ .sl-hold-change,.sl-seccard-x,.sl-fs-pill,.sl-side-toggle{position:relative}
3363
+ .sl-zoom button::after,.sl-cbbtn::after,.sl-close::after,.sl-ga-qty button::after,.sl-ba-qty button::after,
3364
+ .sl-price-more::after,.sl-hold-change::after,.sl-seccard-x::after,.sl-fs-pill::after,.sl-side-toggle::after{
3365
+ content:'';position:absolute;top:50%;left:50%;width:max(100%,44px);height:max(100%,44px);
3366
+ transform:translate(-50%,-50%)}
3367
+ /* The chip rail stacks remove over view in ~53px \u2014 pseudo-targets would
3368
+ overlap and make a destructive tap ambiguous. Give the pair real height. */
3369
+ .sl-picker[data-layout="narrow"] .sl-chip{min-height:64px}
3370
+ .sl-picker[data-layout="narrow"] .sl-chip .rm,
3371
+ .sl-picker[data-layout="narrow"] .sl-chip .view{min-height:32px}
3372
+ }
3373
+
3291
3374
  /* screen-reader live region */
3292
3375
  .sl-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
3293
3376
 
@@ -3657,8 +3740,12 @@ var CSS2 = (
3657
3740
  .sl-picker[data-layout="narrow"] .sl-minimap{display:none}
3658
3741
 
3659
3742
  /* F4 legend reflection: rows + counts for out-of-band categories read muted */
3660
- .sl-price-row.sl-dim{opacity:.4}
3661
- .sl-seccard-mix-item.sl-dim{opacity:.4}
3743
+ /* Out-of-band rows are exactly the rows a buyer reads while deciding whether
3744
+ to widen a filter: whole-row opacity .4 took the label to ~2:1. Dim the
3745
+ SWATCH and soften the numerals; the words stay legible muted ink. */
3746
+ .sl-price-row.sl-dim .sl-dot{opacity:.35}
3747
+ .sl-price-row.sl-dim .sl-price-label,.sl-price-row.sl-dim .sl-price-left,.sl-price-row.sl-dim .sl-price-amt{color:var(--sl-muted)}
3748
+ .sl-seccard-mix-item.sl-dim{opacity:.55}
3662
3749
 
3663
3750
  /* Buyer-journey motion: every animation explains a state transition (selected,
3664
3751
  held, checkout handoff, conflict or booked). No decorative infinite motion
@@ -3784,6 +3871,8 @@ var SeatPicker = class _SeatPicker {
3784
3871
  // state
3785
3872
  this.currency = "USD";
3786
3873
  this.eventTimezone = null;
3874
+ /** The event's formatted date-time (event-zone), reused by the closed-state note. */
3875
+ this.eventWhenText = null;
3787
3876
  this.offerAvailability = null;
3788
3877
  this.hold = null;
3789
3878
  /** Latest server expiry for the open hold (moves on extend). */
@@ -3890,6 +3979,9 @@ var SeatPicker = class _SeatPicker {
3890
3979
  this.fsEscHandler = null;
3891
3980
  /** Host-level event chrome owns the duplicate identity outside full screen. */
3892
3981
  this.eventDetailsHidden = false;
3982
+ /** Wide-layout ticket panel collapsed (map owns the full width). */
3983
+ this.sideCollapsed = false;
3984
+ this.sideToggleEl = null;
3893
3985
  /** True once we've asked the host page to pin us fullscreen (framed, no native). */
3894
3986
  this.framedFs = false;
3895
3987
  /** Last height (px) posted to a host frame; dedupes redundant reports. */
@@ -4199,9 +4291,10 @@ var SeatPicker = class _SeatPicker {
4199
4291
  const active = !!document.fullscreenElement || this.fsFallback || this.framedFs;
4200
4292
  const hideEventDetails = this.eventDetailsHidden && !active;
4201
4293
  this.root?.setAttribute("data-event-details-hidden", String(hideEventDetails));
4202
- this.els.logo?.toggleAttribute("hidden", hideEventDetails);
4203
- this.els.headInfo?.toggleAttribute("hidden", hideEventDetails);
4204
4294
  this.els.zfs?.setAttribute("aria-pressed", String(active));
4295
+ this.els.zfs?.setAttribute("title", active ? "Exit full screen" : "Full screen");
4296
+ const zfsLabel = this.els.zfs?.querySelector(".sl-zfs-lbl");
4297
+ if (zfsLabel) zfsLabel.textContent = active ? "Exit full screen" : "Full screen";
4205
4298
  this.view3dEl?.querySelector(".sl-view3d-fs")?.setAttribute("aria-pressed", String(active));
4206
4299
  }
4207
4300
  /**
@@ -4434,13 +4527,14 @@ var SeatPicker = class _SeatPicker {
4434
4527
  <div class="sl-map">
4435
4528
  <div class="sl-map-host" data-ref="map"></div>
4436
4529
  <div class="sl-zoom" data-ref="zoom">
4437
- <button type="button" aria-label="Zoom in" data-ref="zin">+</button>
4438
- <button type="button" aria-label="Zoom out" data-ref="zout">\u2212</button>
4439
- <button type="button" aria-label="Fit to screen" data-ref="zfit">
4530
+ <button type="button" aria-label="Zoom in" title="Zoom in" data-ref="zin">+</button>
4531
+ <button type="button" aria-label="Zoom out" title="Zoom out" data-ref="zout">\u2212</button>
4532
+ <button type="button" aria-label="Fit to screen" title="Fit to screen" data-ref="zfit">
4440
4533
  <svg viewBox="0 0 24 24"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
4441
4534
  </button>
4442
- <button type="button" aria-label="Full screen" aria-pressed="false" data-ref="zfs">
4535
+ <button type="button" aria-label="Full screen" title="Full screen" aria-pressed="false" data-ref="zfs">
4443
4536
  <svg viewBox="0 0 24 24"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
4537
+ <span class="sl-zfs-lbl" aria-hidden="true">Full screen</span>
4444
4538
  </button>
4445
4539
  </div>
4446
4540
  <div class="sl-boot" data-ref="boot"><span class="sl-boot-spin"></span>Loading seat map\u2026</div>
@@ -4604,17 +4698,18 @@ var SeatPicker = class _SeatPicker {
4604
4698
  badge.className = "sl-testbadge";
4605
4699
  badge.textContent = (0, import_core2.t)("picker.testMode");
4606
4700
  badge.setAttribute("aria-label", (0, import_core2.t)("picker.testMode"));
4607
- this.els.map.appendChild(badge);
4701
+ this.regions["top-left"].appendChild(badge);
4608
4702
  }
4609
4703
  const chartTheme = this.controller.doc?.theme;
4610
4704
  Object.entries(resolveTokens(chartTheme, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));
4611
4705
  this.currency = info.currency ?? this.opts.currency ?? "USD";
4612
4706
  this.eventTimezone = info.timezone ?? null;
4613
- const logoUrl = this.opts.theme?.logoUrl ?? chartTheme?.logoUrl;
4707
+ const logoUrl = this.opts.theme?.logoUrl ?? chartTheme?.logoUrl ?? info.posterUrl ?? null;
4614
4708
  if (logoUrl) this.els.logo.innerHTML = `<img src="${logoUrl}" alt="">`;
4615
4709
  else this.els.logo.textContent = (this.opts.theme?.brandName ?? chartTheme?.brandName ?? info.eventName ?? "?").slice(0, 1).toUpperCase();
4616
4710
  this.els.name.textContent = info.eventName ?? "";
4617
4711
  const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : "";
4712
+ this.eventWhenText = when || null;
4618
4713
  this.els.meta.textContent = [info.venue, when].filter(Boolean).join(" \xB7 ");
4619
4714
  this.buildBadge(chartTheme);
4620
4715
  const present = /* @__PURE__ */ new Set();
@@ -4705,6 +4800,8 @@ var SeatPicker = class _SeatPicker {
4705
4800
  this.buildExtendPrompt();
4706
4801
  this.buildBookedOverlay();
4707
4802
  this.buildSoldoutOverlay();
4803
+ this.buildPanelToggle();
4804
+ if (this.opts.panelCollapsed) this.setPanelCollapsed(true);
4708
4805
  this.dockLayoutChrome();
4709
4806
  await this.restoreRememberedHold();
4710
4807
  if (this.destroyed) return this;
@@ -4751,8 +4848,63 @@ var SeatPicker = class _SeatPicker {
4751
4848
  * re-render the section card in the form the layout wants (docked card/pill
4752
4849
  * on wide, sheet strip on narrow). Runs on every layout flip + once post-render.
4753
4850
  */
4851
+ /**
4852
+ * The wide-layout panel toggle: a labelled pill in the top-right region
4853
+ * beside Map|3D. Collapsing gives the map the panel's 300px; the pill's own
4854
+ * label is the way back ("Tickets"), and syncTray reopens the panel when the
4855
+ * first seat lands so the checkout can never be hidden behind a collapse.
4856
+ */
4857
+ buildPanelToggle() {
4858
+ if (!this.regions["top-right"]) return;
4859
+ const btn = document.createElement("button");
4860
+ btn.type = "button";
4861
+ btn.className = "sl-side-toggle";
4862
+ btn.addEventListener("click", () => this.setPanelCollapsed(!this.sideCollapsed));
4863
+ this.sideToggleEl = btn;
4864
+ this.regions["top-right"].appendChild(btn);
4865
+ this.syncPanelToggle();
4866
+ }
4867
+ syncPanelToggle() {
4868
+ const btn = this.sideToggleEl;
4869
+ if (!btn) return;
4870
+ const collapsed = this.sideCollapsed;
4871
+ btn.setAttribute("aria-expanded", String(!collapsed));
4872
+ btn.setAttribute("aria-label", collapsed ? "Show the ticket panel" : "Hide the ticket panel");
4873
+ btn.innerHTML = collapsed ? '<svg viewBox="0 0 24 24"><path d="M15 6l-6 6 6 6"/></svg><span>Tickets</span>' : '<svg viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></svg><span>Hide panel</span>';
4874
+ }
4875
+ /**
4876
+ * Collapse or reopen the wide-layout ticket panel in place (host-drivable —
4877
+ * a map-first embed can mount collapsed via `panelCollapsed` and reopen on
4878
+ * its own cue). Inert while collapsed so a keyboard buyer cannot tab into a
4879
+ * zero-width panel; narrow layouts ignore the state entirely (the sheet is
4880
+ * already the collapse) but keep it for the next flip back to wide.
4881
+ */
4882
+ setPanelCollapsed(collapsed) {
4883
+ if (this.destroyed) return;
4884
+ this.sideCollapsed = collapsed;
4885
+ this.applyPanelCollapsed();
4886
+ this.scheduleMotion(() => this.controller.zoomToFit(), 340);
4887
+ }
4888
+ /** Idempotent DOM apply, also run on every layout flip (inert must lift on narrow). */
4889
+ applyPanelCollapsed() {
4890
+ const wide = this.root?.dataset.layout !== "narrow";
4891
+ this.root?.setAttribute("data-side-collapsed", String(this.sideCollapsed));
4892
+ this.els.side?.toggleAttribute("inert", this.sideCollapsed && wide);
4893
+ this.syncPanelToggle();
4894
+ }
4754
4895
  dockLayoutChrome() {
4755
4896
  const narrow = this.root?.dataset.layout === "narrow";
4897
+ this.applyPanelCollapsed();
4898
+ const zfs = this.els.zfs;
4899
+ if (zfs) {
4900
+ if (narrow && this.regions["top-right"]) {
4901
+ zfs.classList.add("sl-fs-pill");
4902
+ this.regions["top-right"].appendChild(zfs);
4903
+ } else if (!narrow && this.els.zoom && zfs.parentElement !== this.els.zoom) {
4904
+ zfs.classList.remove("sl-fs-pill");
4905
+ this.els.zoom.appendChild(zfs);
4906
+ }
4907
+ }
4756
4908
  const filters = this.els.filters;
4757
4909
  if (filters) {
4758
4910
  if (this.cbEl) this.els.zoom?.appendChild(this.cbEl);
@@ -4855,6 +5007,9 @@ var SeatPicker = class _SeatPicker {
4855
5007
  text.textContent = this.tf("picker.salesClosedPill", "Sales are closed");
4856
5008
  }
4857
5009
  this.root?.setAttribute("data-sales-closed", String(this.salesClosed));
5010
+ if (this.salesClosed && this.srEl) {
5011
+ this.srEl.textContent = this.tf("picker.salesClosedToast", "Sales are closed for this event.");
5012
+ }
4858
5013
  this.syncCta();
4859
5014
  this.syncTray();
4860
5015
  }
@@ -5700,6 +5855,8 @@ var SeatPicker = class _SeatPicker {
5700
5855
  this.confirmEl = null;
5701
5856
  this.confirmSeat = seat;
5702
5857
  this.root?.setAttribute("data-confirming", "true");
5858
+ this.els.side?.toggleAttribute("inert", true);
5859
+ Object.values(this.regions).forEach((region) => region.toggleAttribute("inert", true));
5703
5860
  this.controller.setSelectionFocus(seat.id);
5704
5861
  if (previousId && previousId !== seat.id) this.controller.deselect([previousId]);
5705
5862
  if (this.tipEl) this.tipEl.style.display = "none";
@@ -5721,7 +5878,6 @@ var SeatPicker = class _SeatPicker {
5721
5878
  const el2 = document.createElement("div");
5722
5879
  el2.className = "sl-confirm";
5723
5880
  el2.setAttribute("role", "dialog");
5724
- el2.setAttribute("aria-modal", "true");
5725
5881
  el2.setAttribute("aria-label", `Confirm seat ${seat.label}`);
5726
5882
  el2.style.setProperty("--sl-cat", cat?.color ?? "#6e7bff");
5727
5883
  el2.innerHTML = `<div class="sl-confirm-grid">` + identityFields + `</div><div class="sl-confirm-cat"><span class="sl-dot" style="background:${cat?.color ?? "#6e7bff"}"></span><span class="sl-confirm-cat-name">${safe(details?.categoryLabel ?? cat?.label ?? seat.categoryKey)}</span>` + (price != null ? `<span class="sl-confirm-price">${this.money(price)}</span>` : "") + `</div><div class="sl-confirm-body">` + this.wheelchairConfirmHtml(details?.wheelchairSpaceType) + this.commercialConfirmHtml(seat.commercial) + (this.seatViewEnabled() && this.buyerView !== "venue3d" ? this.confirmThumbHtml(seat) : "") + (this.buyerView === "venue3d" ? `${this.seatConfidenceConfirmHtml(seat, `${details?.displayLabel ?? seat.displayLabel ?? seat.label} \xB7 ${price == null ? this.tf("picker.priceNotSupplied", "Price not supplied") : this.money(price)}`)}<div class="sl-confirm-inspect-row">${this.view3dCompareConfirmHtml(seat)}${this.see3dConfirmHtml()}</div>` : this.see3dConfirmHtml()) + `<div class="sl-confirm-row"><button type="button" class="sl-confirm-cancel">Cancel</button><button type="button" class="sl-confirm-add"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4 4L19 7"/></svg>Select</button></div></div>`;
@@ -5776,6 +5932,8 @@ var SeatPicker = class _SeatPicker {
5776
5932
  this.confirmEl = null;
5777
5933
  this.confirmSeat = null;
5778
5934
  this.root?.removeAttribute("data-confirming");
5935
+ Object.values(this.regions).forEach((region) => region.toggleAttribute("inert", false));
5936
+ this.applyPanelCollapsed();
5779
5937
  this.controller.setSelectionFocus(null);
5780
5938
  }
5781
5939
  commitConfirm() {
@@ -6214,19 +6372,24 @@ var SeatPicker = class _SeatPicker {
6214
6372
  const heldItems = this.hold?.items ?? [];
6215
6373
  const parts = [];
6216
6374
  const nextTrayKeys = /* @__PURE__ */ new Set();
6217
- if (!seats.length && !heldItems.length && !gaAreas.length) {
6375
+ if (this.salesClosed && !seats.length && !heldItems.length) {
6376
+ const closedWhen = this.eventWhenText ? `<span class="when">${String(this.eventWhenText).replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c])}</span>` : "";
6377
+ parts.push(
6378
+ `<div class="sl-closed-note" role="status"><b>${this.tf("picker.salesClosedPill", "Sales are closed")}</b><span>${this.tf("picker.salesClosedCopy", "Ticket sales for this event have ended.")}${closedWhen}</span></div>`
6379
+ );
6380
+ } else if (!seats.length && !heldItems.length && !gaAreas.length) {
6218
6381
  parts.push(`<div class="sl-tray-hint">Tap a seat on the map, or let us pick the best available for you.</div>`);
6219
6382
  } else if (!seats.length && !heldItems.length) {
6220
6383
  parts.push(`<div class="sl-tray-hint">Tap a seat on the map \u2014 or grab standing tickets below.</div>`);
6221
6384
  }
6222
6385
  const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();
6223
- if (!this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {
6386
+ if (!this.salesClosed && !this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {
6224
6387
  const cats = this.controller.doc?.categories ?? [];
6225
6388
  const zones = this.controller.getBestAvailableZones();
6226
6389
  if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = "";
6227
6390
  parts.push(this.bestAvailableConfirm ? `<div class="sl-ba" role="alert"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>Replace your current choices?</div><div class="sl-ba-replace"><b>We\u2019ll find ${this.baQty} seats together.</b><span>Your manually selected tickets will be removed only after a new group is secured.</span></div><div class="sl-ba-actions"><button type="button" data-ba-cancel>Keep mine</button><button type="button" class="replace" data-ba-replace>Find new seats</button></div></div>` : `<div class="sl-ba"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>Find the best seats together</div><div class="sl-ba-copy"><span class="wide">We\u2019ll choose the closest available group for you.</span><span class="narrow">Closest available group, chosen instantly.</span></div>` + // Premium quick-pick — present only when the chart actually has premium
6228
6391
  // seats (same present-only philosophy as the a11y filter chips).
6229
- (this.controller.hasPremiumSeats() ? `<button type="button" class="sl-ba-premium${this.baPremium ? " on" : ""}" data-ba-premium aria-pressed="${this.baPremium ? "true" : "false"}"><span class="star" aria-hidden="true">\u2605</span>${this.tf("picker.bestSeatsPremium", "Best seats")}</button>` : "") + (cats.length > 1 ? `<select aria-label="Preferred ticket type" data-ba-cat><option value="">Any ticket type</option>` + cats.map((c) => `<option value="${c.key}"${this.baCat === c.key ? " selected" : ""}>${c.label}</option>`).join("") + `</select>` : `<span aria-hidden="true"></span>`) + (zones.length ? `<select aria-label="Preferred venue zone" data-ba-zone><option value="">Any venue zone</option>` + zones.map((zone) => `<option value="${escapeOption(zone.id)}"${this.baZone === zone.id ? " selected" : ""}>${escapeOption(zone.label)}</option>`).join("") + `</select>` : "") + `<div class="sl-ba-qty"><button type="button" data-ba="-1" aria-label="Fewer seats">\u2212</button><span>${this.baQty}</span><button type="button" data-ba="1" aria-label="More seats">+</button></div><button type="button" class="sl-ba-go"${this.bestAvailableBusy ? " disabled" : ""}>` + (this.bestAvailableBusy ? `<span class="sl-ba-spin" aria-hidden="true"></span>Finding the best seats\u2026` : `Find ${this.baQty} best ${this.baQty === 1 ? "seat" : "seats"}`) + `</button></div>`);
6392
+ (this.controller.hasPremiumSeats() ? `<button type="button" class="sl-ba-premium${this.baPremium ? " on" : ""}" data-ba-premium aria-pressed="${this.baPremium ? "true" : "false"}"><span class="star" aria-hidden="true">\u2605</span>${this.tf("picker.bestSeatsPremium", "Best seats")}</button>` : "") + (cats.length > 1 ? `<select aria-label="Preferred ticket type" data-ba-cat><option value="">Any ticket type</option>` + cats.map((c) => `<option value="${c.key}"${this.baCat === c.key ? " selected" : ""}>${c.label}</option>`).join("") + `</select>` : `<span aria-hidden="true"></span>`) + (zones.length ? `<select aria-label="Preferred venue zone" data-ba-zone><option value="">Any venue zone</option>` + zones.map((zone) => `<option value="${escapeOption(zone.id)}"${this.baZone === zone.id ? " selected" : ""}>${escapeOption(zone.label)}</option>`).join("") + `</select>` : "") + `<div class="sl-ba-qty"><button type="button" data-ba="-1" aria-label="Fewer seats">\u2212</button><span>${this.baQty}</span><button type="button" data-ba="1" aria-label="More seats">+</button></div><button type="button" class="sl-ba-go${this.bestAvailableBusy ? " sl-busy" : ""}"${this.bestAvailableBusy ? " disabled" : ""}>` + (this.bestAvailableBusy ? `<span class="sl-ba-spin" aria-hidden="true"></span>Finding the best seats\u2026` : `Find ${this.baQty} best ${this.baQty === 1 ? "seat" : "seats"}`) + `</button></div>`);
6230
6393
  }
6231
6394
  const idGrid = (seatId, label, objectType, quantity = 1, objectId, identity) => {
6232
6395
  const esc = (value) => String(value ?? "\u2014").replace(/[&<>"]/g, (char) => ({
@@ -6436,11 +6599,16 @@ var SeatPicker = class _SeatPicker {
6436
6599
  }
6437
6600
  if (count !== previousCount) this.animateOnce(this.els.count, "sl-value-pop", 380);
6438
6601
  if (total !== previousTotal) this.animateOnce(this.els.total, "sl-value-pop", 380);
6439
- if (previousCount === 0 && count > 0) this.animateOnce(this.els.cta, "sl-ready", 520);
6602
+ if (previousCount === 0 && count > 0) {
6603
+ this.animateOnce(this.els.cta, "sl-ready", 520);
6604
+ if (this.sideCollapsed && this.root?.dataset.layout !== "narrow") this.setPanelCollapsed(false);
6605
+ }
6440
6606
  if (this.els.peek) {
6441
6607
  if (count) {
6442
6608
  const holding = !!this.hold && !pendingCount;
6443
6609
  this.els.peek.innerHTML = `<span>${count} ${count === 1 ? "ticket" : "tickets"} \xB7 ${this.money(total)}</span><button type="button" class="go sl-sheet-go" data-act="${holding ? "checkout" : "open"}">${this.hold ? pendingCount ? "Secure more" : "Continue" : "Review"}</button>`;
6610
+ } else if (this.salesClosed) {
6611
+ this.els.peek.innerHTML = `<span>${this.tf("picker.salesClosedPill", "Sales are closed")}</span>`;
6444
6612
  } else {
6445
6613
  const prices = (this.controller.doc?.categories ?? []).map((c) => this.catPrice(c)).filter((p) => p != null);
6446
6614
  this.els.peek.innerHTML = (prices.length ? `<span>From ${this.money(Math.min(...prices))}</span>` : "<span>Pick your seats</span>") + `<button type="button" class="go sl-sheet-go" data-act="open">\u2726 Best seats</button>`;
@@ -7896,6 +8064,7 @@ var SeatPicker = class _SeatPicker {
7896
8064
  const button = this.els.tray?.querySelector(".sl-ba-go");
7897
8065
  if (button) {
7898
8066
  button.disabled = true;
8067
+ button.classList.add("sl-busy");
7899
8068
  button.innerHTML = '<span class="sl-ba-spin" aria-hidden="true"></span>Finding\u2026';
7900
8069
  }
7901
8070
  try {