@seatlayer/js 0.50.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2659,6 +2659,10 @@ var DEFAULT_MAX_SELECTION2 = 10;
2659
2659
  var EXTEND_PROMPT_MS = 6e4;
2660
2660
  var MAX_3D_SEATS_DEFAULT = 6e4;
2661
2661
  var MAX_3D_SECTION_PILLS = 12;
2662
+ function tfStatic(key, fallback) {
2663
+ const v = (0, import_core2.t)(key);
2664
+ return v === key ? fallback : v;
2665
+ }
2662
2666
  function pointInPolygon(x, y, poly) {
2663
2667
  let inside = false;
2664
2668
  for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
@@ -2833,11 +2837,30 @@ var CSS2 = (
2833
2837
  .sl-picker[data-layout="narrow"] .sl-map{min-height:0;flex:1}
2834
2838
  .sl-picker[data-layout="narrow"] .sl-side{width:100%;border-left:0;border-top:1px solid var(--sl-line);
2835
2839
  flex:none;height:min(72%,480px);overflow:hidden;transition:height .3s cubic-bezier(.2,.8,.2,1);overscroll-behavior:contain}
2836
- .sl-picker[data-layout="narrow"][data-sheet="open"][data-has-selection="false"] .sl-side{height:min(252px,52%)}
2840
+ .sl-picker[data-layout="narrow"][data-sheet="open"][data-has-selection="false"] .sl-side{height:min(380px,64%)}
2841
+ /* With the price list expanded the sheet takes the with-selection height so
2842
+ the tray (cart + best-seats) is never crushed under the fixed-size list. */
2843
+ .sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-side{height:min(480px,74%)}
2837
2844
  .sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-side{height:76px;overflow:hidden}
2838
2845
  .sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-side > :not(.sl-sheet-head){display:none}
2839
- .sl-picker[data-layout="narrow"] .sl-tray{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}
2846
+ .sl-picker[data-layout="narrow"] .sl-tray{flex:1;min-height:96px;overflow-y:auto;overscroll-behavior:contain}
2847
+ .sl-picker[data-layout="narrow"][data-prices-open="true"] .sl-tray{min-height:48px}
2848
+ .sl-picker[data-layout="narrow"] .sl-prices{max-height:150px;overflow-y:auto;overscroll-behavior:contain}
2840
2849
  .sl-picker[data-layout="narrow"] .sl-foot{position:static;background:var(--sl-bg)}
2850
+ /* NARROW FOOT SAYS EVERYTHING ONCE (owner report: with a hold the footer ate
2851
+ ~190px and the ticket list got a sliver). The sheet head already carries
2852
+ "N tickets \xB7 $total" and the header pill already ticks the clock \u2014 so the
2853
+ total row hides, the secured note collapses to one compact line, and the
2854
+ badge tucks in. The tray gets the pixels; a thin scrollbar shows there is
2855
+ more to scroll. */
2856
+ .sl-picker[data-layout="narrow"] .sl-total{display:none}
2857
+ .sl-picker[data-layout="narrow"] .sl-foot{padding:8px 12px 8px}
2858
+ .sl-picker[data-layout="narrow"] .sl-hold-note{margin-bottom:6px;padding:5px 9px}
2859
+ .sl-picker[data-layout="narrow"] .sl-hold-note svg{display:none}
2860
+ .sl-picker[data-layout="narrow"] .sl-hold-note b{display:inline;margin-right:6px;font-size:11px}
2861
+ .sl-picker[data-layout="narrow"] .sl-hold-copy{display:inline;white-space:normal;font-size:10.5px}
2862
+ .sl-picker[data-layout="narrow"] .sl-powered{margin-top:4px;padding:2px 8px;font-size:11px}
2863
+ .sl-picker[data-layout="narrow"] .sl-tray{scrollbar-width:thin}
2841
2864
  .sl-picker[data-layout="narrow"] .sl-foot.empty{display:none}
2842
2865
  .sl-picker[data-layout="narrow"] .sl-sheet-head{order:0}
2843
2866
  .sl-picker[data-layout="narrow"] .sl-seats-sec{display:none}
@@ -2845,6 +2868,7 @@ var CSS2 = (
2845
2868
  .sl-picker[data-layout="narrow"] .sl-filtersec{order:3}
2846
2869
  .sl-picker[data-layout="narrow"] .sl-filters{order:4}
2847
2870
  .sl-picker[data-layout="narrow"] .sl-prices-sec{order:5}
2871
+ .sl-picker[data-layout="narrow"] .sl-prices-hint{order:6}
2848
2872
  .sl-picker[data-layout="narrow"] .sl-pricef{order:6}
2849
2873
  .sl-picker[data-layout="narrow"] .sl-prices{order:7}
2850
2874
  .sl-picker[data-layout="narrow"] .sl-foot{order:8}
@@ -2852,6 +2876,7 @@ var CSS2 = (
2852
2876
  .sl-picker[data-layout="narrow"] .sl-filtersec,
2853
2877
  .sl-picker[data-layout="narrow"] .sl-filters,
2854
2878
  .sl-picker[data-layout="narrow"] .sl-prices-sec,
2879
+ .sl-picker[data-layout="narrow"] .sl-prices-hint,
2855
2880
  .sl-picker[data-layout="narrow"] .sl-prices{display:none!important}
2856
2881
  .sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filtersec,
2857
2882
  .sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filters,
@@ -2869,7 +2894,13 @@ var CSS2 = (
2869
2894
  head is the tap/swipe toggle target (min 44px), so it reads as one control. */
2870
2895
  .sl-sheet-head{display:none;flex-direction:column;justify-content:center;padding:6px 12px 8px;min-height:56px;
2871
2896
  cursor:pointer;touch-action:none;user-select:none;-webkit-user-select:none;flex:none}
2872
- .sl-picker[data-layout="narrow"] .sl-sheet-head{display:flex;min-height:64px;padding:4px 10px 6px}
2897
+ .sl-picker[data-layout="narrow"] .sl-sheet-head{display:flex;min-height:52px;padding:3px 10px 5px}
2898
+ /* OPEN sheet: the head is context, not controls \u2014 the pill it carries at peek
2899
+ ("Best seats"/"Continue") duplicates the card and CTA right below it, and
2900
+ every saved pixel is tray room (owner call 2026-08-14). */
2901
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-head{min-height:42px}
2902
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-bar{min-height:32px}
2903
+ .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-peek .go{display:none}
2873
2904
  .sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-sheet-head{height:100%}
2874
2905
  .sl-sheet-grab{width:36px;height:4px;border-radius:999px;background:var(--sl-muted);opacity:.55;margin:1px auto 5px}
2875
2906
  .sl-sheet-bar{display:flex;align-items:center;gap:8px;min-height:44px}
@@ -2910,9 +2941,19 @@ var CSS2 = (
2910
2941
  sheet brings it back, exactly like the filters row above. The tray hint comes
2911
2942
  back with it: the first-time buyer on a phone needs the instruction more than
2912
2943
  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}
2944
+ .sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices-sec{display:flex!important}
2945
+ /* MOBILE SPACE BELONGS TO THE CART (owner call 2026-08-14): the price list is
2946
+ one tap away behind the "Ticket prices" row, not a permanent tenant. Zone
2947
+ flags and section taps already answer "what does it cost" in context. */
2948
+ .sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices-hint{display:block!important}
2949
+ .sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices{display:flex!important}
2915
2950
  .sl-picker[data-layout="narrow"][data-sheet="open"] .sl-tray-hint{display:block!important}
2951
+ /* The row reads as the toggle it is on narrow: chevron + pointer. */
2952
+ .sl-picker[data-layout="narrow"] .sl-prices-sec{cursor:pointer}
2953
+ .sl-picker[data-layout="narrow"] .sl-prices-sec::after{content:'';width:8px;height:8px;flex:none;margin-left:auto;
2954
+ border-right:2px solid var(--sl-muted);border-bottom:2px solid var(--sl-muted);
2955
+ transform:rotate(45deg);transition:transform .2s cubic-bezier(.2,.8,.2,1)}
2956
+ .sl-picker[data-layout="narrow"][data-prices-open="true"] .sl-prices-sec::after{transform:rotate(-135deg)}
2916
2957
  .sl-cbbtn{width:32px;height:32px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);
2917
2958
  color:var(--sl-text);display:flex;align-items:center;justify-content:center;transition:border-color .15s}
2918
2959
  .sl-cbbtn:hover{border-color:var(--sl-muted)}
@@ -2931,7 +2972,13 @@ var CSS2 = (
2931
2972
  .sl-sec{padding:14px 14px 4px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}
2932
2973
  .sl-prices-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}
2933
2974
  .sl-price-select{min-height:32px;max-width:130px;padding:5px 28px 5px 9px;border:1px solid var(--sl-line);border-radius:9px;
2934
- background:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}
2975
+ background-color:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}
2976
+ /* One sentence that teaches the whole colour code \u2014 a first-time buyer sees
2977
+ "Head Tables \xB7 $165" and coloured dots with nothing connecting them. Gone
2978
+ the moment they have seats (they've learned it) and while sales are closed. */
2979
+ .sl-prices-hint{padding:0 14px 7px;font-size:11px;line-height:1.45;color:var(--sl-muted)}
2980
+ .sl-picker[data-has-selection="true"] .sl-prices-hint,
2981
+ .sl-picker[data-sales-closed="true"] .sl-prices-hint{display:none}
2935
2982
  .sl-prices{display:flex;flex-direction:column;padding:4px 14px 8px;border-bottom:1px solid var(--sl-line)}
2936
2983
  .sl-prices-sec,.sl-prices,.sl-seats-sec{flex:none}
2937
2984
  .sl-price-row{display:flex;align-items:center;gap:7px;min-height:28px;font-size:12px;
@@ -3091,11 +3138,11 @@ var CSS2 = (
3091
3138
  color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}
3092
3139
  .sl-zoom button:hover{border-color:var(--sl-muted)}
3093
3140
  .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. */
3141
+ /* Full-screen promotion: the capability existed (native + iOS overlay +
3142
+ framed-host paths) but hid as the 4th unlabelled glyph in a corner stack \u2014
3143
+ even the owner could not pick it out. dockLayoutChrome docks the SAME
3144
+ button into the top-right region beside Map|3D on EVERY layout and this
3145
+ class dresses it as a labelled pill. */
3099
3146
  .sl-zfs-lbl{display:none}
3100
3147
  .sl-fs-pill.sl-fs-pill{display:inline-flex;align-items:center;justify-content:center;width:auto;min-height:40px;height:auto;
3101
3148
  padding:0 13px;gap:6px;border-radius:999px;font-size:11px;font-weight:800;
@@ -3103,6 +3150,16 @@ var CSS2 = (
3103
3150
  .sl-fs-pill.sl-fs-pill:hover{border-color:var(--sl-muted)}
3104
3151
  .sl-fs-pill svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
3105
3152
  .sl-fs-pill .sl-zfs-lbl{display:inline;letter-spacing:.02em;white-space:nowrap}
3153
+ /* In the header, icons carry it (owner call): square Full screen glyph, and
3154
+ on narrow a price-tag toggle that opens the sheet with the list expanded. */
3155
+ .sl-head .sl-fs-pill{min-height:34px;min-width:34px;width:34px;padding:0;flex:none}
3156
+ .sl-head .sl-fs-pill .sl-zfs-lbl{display:none}
3157
+ .sl-prices-btn{display:none;align-items:center;justify-content:center;width:34px;min-height:34px;flex:none;
3158
+ border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}
3159
+ .sl-prices-btn:hover{border-color:var(--sl-muted)}
3160
+ .sl-prices-btn svg{width:15px;height:15px;stroke:currentColor;stroke-width:1.8;fill:none;stroke-linecap:round;stroke-linejoin:round}
3161
+ .sl-prices-btn[aria-pressed="true"]{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}
3162
+ .sl-picker[data-layout="narrow"] .sl-prices-btn{display:inline-flex}
3106
3163
 
3107
3164
  /* toast + boot states (toast flows in the bottom-center region) */
3108
3165
  .sl-toast{transform:translateY(6px) scale(.98);max-width:100%;
@@ -3230,8 +3287,21 @@ var CSS2 = (
3230
3287
  .sl-confirm-add svg{width:16px;height:16px;stroke:currentColor;stroke-width:2.8;fill:none;stroke-linecap:round;stroke-linejoin:round}
3231
3288
  .sl-confirm-cancel{background:color-mix(in srgb,var(--sl-line) 44%,transparent)!important;border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}
3232
3289
  .sl-confirm-cancel:hover{color:var(--sl-text)}
3233
- .sl-picker[data-layout="narrow"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(342px,calc(100% - 24px));
3290
+ .sl-picker[data-layout="narrow"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(310px,calc(100% - 24px));
3234
3291
  transform:translateX(-50%);animation:slConfirmMobileIn .24s cubic-bezier(.2,.8,.2,1) both}
3292
+ /* Phone-size confirm card (owner call 2026-08-14): same content \u2014 identity,
3293
+ price band, view photo, 3D link \u2014 on a tighter grid. The values stay large
3294
+ enough to double-check against the map; buttons keep tap-size. */
3295
+ .sl-picker[data-layout="narrow"] .sl-confirm-field{padding:9px 9px 8px}
3296
+ .sl-picker[data-layout="narrow"] .sl-confirm-value{font-size:15px}
3297
+ .sl-picker[data-layout="narrow"] .sl-confirm-cat{padding:8px 10px}
3298
+ .sl-picker[data-layout="narrow"] .sl-confirm-cat-name{font-size:12.5px}
3299
+ .sl-picker[data-layout="narrow"] .sl-confirm-price{font-size:15px}
3300
+ .sl-picker[data-layout="narrow"] .sl-confirm-body{padding:9px 10px 10px}
3301
+ .sl-picker[data-layout="narrow"] .sl-confirm-thumbwrap{height:62px;margin-bottom:6px}
3302
+ .sl-picker[data-layout="narrow"] .sl-confirm-3d{margin-top:7px;padding:6px}
3303
+ .sl-picker[data-layout="narrow"] .sl-confirm-row{margin-top:8px}
3304
+ .sl-picker[data-layout="narrow"] .sl-confirm-row button{min-height:42px}
3235
3305
 
3236
3306
  /* Atomic whole/variable-table chooser. Lives inside the widget so the same
3237
3307
  accessible dialog works in inline, modal, desktop and 390px mobile hosts. */
@@ -3307,8 +3377,11 @@ var CSS2 = (
3307
3377
  .sl-ba-premium.on{color:var(--sl-premium-ink);background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;
3308
3378
  box-shadow:0 6px 16px color-mix(in srgb,var(--sl-premium) 26%,transparent)}
3309
3379
  .sl-ba-premium.on .star{color:#5a4410}
3310
- .sl-ba select{background:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;
3311
- font:inherit;font-size:11px;padding:7px 8px;min-width:0;width:100%;max-width:none}
3380
+ .sl-ba select,.sl-price-select{appearance:none;-webkit-appearance:none;
3381
+ background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23949ca9' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
3382
+ background-repeat:no-repeat;background-position:right 10px center}
3383
+ .sl-ba select{background-color:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;
3384
+ font:inherit;font-size:11px;padding:7px 26px 7px 8px;min-width:0;width:100%;max-width:none}
3312
3385
  .sl-ba-qty{display:flex;align-items:center;gap:7px;padding:3px;border:1px solid var(--sl-line);border-radius:9px;background:var(--sl-surface)}
3313
3386
  .sl-ba-qty button{width:25px;height:25px;border-radius:7px;background:color-mix(in srgb,var(--sl-line) 35%,transparent);border:0;
3314
3387
  font-size:14px;font-weight:800;display:flex;align-items:center;justify-content:center}
@@ -3338,9 +3411,23 @@ var CSS2 = (
3338
3411
  .sl-picker[data-layout="narrow"] .sl-ba-copy{display:none}
3339
3412
  .sl-picker[data-layout="narrow"] .sl-ba-copy .wide{display:none}
3340
3413
  .sl-picker[data-layout="narrow"] .sl-ba-copy .narrow{display:inline}
3341
- .sl-picker[data-layout="narrow"] .sl-ba select{min-height:40px}
3414
+ .sl-picker[data-layout="narrow"] .sl-ba{grid-template-columns:auto minmax(0,1fr)}
3415
+ .sl-picker[data-layout="narrow"] .sl-ba select{grid-column:1/-1;min-height:38px}
3342
3416
  .sl-picker[data-layout="narrow"] .sl-ba-qty button{width:30px;height:30px}
3343
- .sl-picker[data-layout="narrow"] .sl-ba-go{min-height:40px}
3417
+ /* Quantity and Go share ONE row: a full-width row holding only "\u2212 2 +" was
3418
+ dead space, and the Find button still gets the lion's share. */
3419
+ .sl-picker[data-layout="narrow"] .sl-ba-qty{grid-column:1}
3420
+ .sl-picker[data-layout="narrow"] .sl-ba-go{grid-column:2;min-height:40px}
3421
+ /* Re-entry to best-available once the cart has seats (the card yields its
3422
+ space to chips, but the accelerator must stay reachable) + the quiet way
3423
+ back out of a reopened card. */
3424
+ .sl-ba-reopen{align-self:flex-start;display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:5px 12px;margin-top:2px;
3425
+ border:1px dashed color-mix(in srgb,var(--sl-accent) 40%,var(--sl-line));border-radius:999px;
3426
+ color:var(--sl-accent);font-size:11.5px;font-weight:750;transition:border-color .15s,background .15s}
3427
+ .sl-ba-reopen:hover,.sl-ba-reopen:focus-visible{background:color-mix(in srgb,var(--sl-accent) 8%,transparent)}
3428
+ .sl-ba-back{grid-column:1/-1;justify-self:start;min-height:30px;padding:3px 0;color:var(--sl-muted);
3429
+ font-size:11px;font-weight:700;text-decoration:underline;text-underline-offset:3px;transition:color .15s}
3430
+ .sl-ba-back:hover,.sl-ba-back:focus-visible{color:var(--sl-text)}
3344
3431
 
3345
3432
  /* Sales-closed is a designed state, not a set of disables: one statement in
3346
3433
  the tray where the buying flow was, carrying the event's own date so the
@@ -3359,9 +3446,9 @@ var CSS2 = (
3359
3446
  (the cart chip's remove/view rail) instead get real height on narrow. */
3360
3447
  @media (pointer:coarse){
3361
3448
  .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}
3449
+ .sl-hold-change,.sl-seccard-x,.sl-fs-pill,.sl-side-toggle,.sl-ba-reopen{position:relative}
3363
3450
  .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{
3451
+ .sl-price-more::after,.sl-hold-change::after,.sl-seccard-x::after,.sl-fs-pill::after,.sl-side-toggle::after,.sl-ba-reopen::after{
3365
3452
  content:'';position:absolute;top:50%;left:50%;width:max(100%,44px);height:max(100%,44px);
3366
3453
  transform:translate(-50%,-50%)}
3367
3454
  /* The chip rail stacks remove over view in ~53px \u2014 pseudo-targets would
@@ -3464,12 +3551,6 @@ var CSS2 = (
3464
3551
  border-radius:999px;font:700 11.5px/1 inherit;color:#eef1f8;background:rgba(12,18,32,.86);
3465
3552
  border:1px solid rgba(150,165,205,.45);backdrop-filter:blur(6px);cursor:pointer}
3466
3553
  .sl-view3d-nav select:focus-visible{outline:2px solid var(--sl-accent);outline-offset:2px}
3467
- .sl-view3d-nav .sl-view3d-locator{display:grid;grid-template-columns:minmax(150px,1.25fr) minmax(110px,.8fr) minmax(105px,.7fr) auto;
3468
- width:min(720px,100%);overflow:visible}
3469
- .sl-view3d-nav.is-seat-focused .sl-view3d-locator{display:none}
3470
- .sl-view3d-locator select{width:100%;min-width:0}
3471
- .sl-picker[data-layout="narrow"] .sl-view3d-nav .sl-view3d-locator{display:flex;width:100%;overflow-x:auto}
3472
- .sl-picker[data-layout="narrow"] .sl-view3d-locator select{flex:0 0 155px}
3473
3554
  /* On phones the library owns the bottom edge for seat/panorama/overview actions.
3474
3555
  Keep venue navigation in a separate top rail so those control families never
3475
3556
  stack over one another. */
@@ -3479,9 +3560,6 @@ var CSS2 = (
3479
3560
  .sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open{left:12px;top:68px;max-width:calc(100% - 24px);padding:8px;
3480
3561
  border:1px solid rgba(150,165,205,.35);border-radius:14px;background:rgba(8,12,22,.9);backdrop-filter:blur(10px)}
3481
3562
  .sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open>div{display:flex}
3482
- .sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator{display:grid;grid-template-columns:1fr 1fr;width:100%;overflow:visible}
3483
- .sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator select{width:100%;min-width:0;flex:auto}
3484
- .sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator button{width:100%}
3485
3563
  /* Seat-eye is a decision state, not another venue-navigation state. Once the
3486
3564
  buyer arrives, clear the floor/area/locator rails and the module's duplicate
3487
3565
  Overview action. The picker-owned Back button becomes the one predictable
@@ -3907,6 +3985,15 @@ var SeatPicker = class _SeatPicker {
3907
3985
  this.baZone = "";
3908
3986
  /** "★ Best seats" premium quick-pick toggle — biases best-available to premium seats. */
3909
3987
  this.baPremium = false;
3988
+ /**
3989
+ * The buyer re-opened the best-seats form with seats already in the cart
3990
+ * ("I picked one, actually find us three together"). The card normally
3991
+ * yields this space to the ticket chips the moment anything is selected —
3992
+ * which removed the accelerator at exactly the moment a one-handed phone
3993
+ * buyer wants it. Cleared when the cart empties, a hold lands, or the
3994
+ * buyer backs out.
3995
+ */
3996
+ this.baReopen = false;
3910
3997
  this.bestAvailableConfirm = false;
3911
3998
  this.releasingHold = false;
3912
3999
  /** Event sales window is closed (read-only load state / live close). */
@@ -3984,6 +4071,7 @@ var SeatPicker = class _SeatPicker {
3984
4071
  /** Wide-layout ticket panel collapsed (map owns the full width). */
3985
4072
  this.sideCollapsed = false;
3986
4073
  this.sideToggleEl = null;
4074
+ this.pricesBtnEl = null;
3987
4075
  /** True once we've asked the host page to pin us fullscreen (framed, no native). */
3988
4076
  this.framedFs = false;
3989
4077
  /** Last height (px) posted to a host frame; dedupes redundant reports. */
@@ -4096,7 +4184,7 @@ var SeatPicker = class _SeatPicker {
4096
4184
  if (this.tableDialog?.physicalSeatIds.includes(seat.id)) this.dismissTableDialog();
4097
4185
  },
4098
4186
  onSelectionLimit: () => {
4099
- this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, "warning");
4187
+ this.toast((0, import_core2.t)("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
4100
4188
  },
4101
4189
  onViewChange: () => {
4102
4190
  this.reanchorConfirm();
@@ -4212,8 +4300,8 @@ var SeatPicker = class _SeatPicker {
4212
4300
  return `<span class="sl-cx-mark" role="img" aria-label="${title}" title="${title}">\u25D0</span>`;
4213
4301
  }
4214
4302
  wheelchairProvisionLabel(type) {
4215
- if (type === "no-seat") return "Empty wheelchair space";
4216
- if (type === "seat-present") return "Accessible physical seat";
4303
+ if (type === "no-seat") return this.tf("picker.emptyWheelchairSpace", "Empty wheelchair space");
4304
+ if (type === "seat-present") return this.tf("picker.accessiblePhysicalSeat", "Accessible physical seat");
4217
4305
  return "";
4218
4306
  }
4219
4307
  wheelchairConfirmHtml(type) {
@@ -4294,9 +4382,9 @@ var SeatPicker = class _SeatPicker {
4294
4382
  const hideEventDetails = this.eventDetailsHidden && !active;
4295
4383
  this.root?.setAttribute("data-event-details-hidden", String(hideEventDetails));
4296
4384
  this.els.zfs?.setAttribute("aria-pressed", String(active));
4297
- this.els.zfs?.setAttribute("title", active ? "Exit full screen" : "Full screen");
4385
+ this.els.zfs?.setAttribute("title", active ? this.tf("picker.exitFullScreen", "Exit full screen") : this.tf("picker.fullScreen", "Full screen"));
4298
4386
  const zfsLabel = this.els.zfs?.querySelector(".sl-zfs-lbl");
4299
- if (zfsLabel) zfsLabel.textContent = active ? "Exit full screen" : "Full screen";
4387
+ if (zfsLabel) zfsLabel.textContent = active ? this.tf("picker.exitFullScreen", "Exit full screen") : this.tf("picker.fullScreen", "Full screen");
4300
4388
  this.view3dEl?.querySelector(".sl-view3d-fs")?.setAttribute("aria-pressed", String(active));
4301
4389
  }
4302
4390
  /**
@@ -4361,7 +4449,7 @@ var SeatPicker = class _SeatPicker {
4361
4449
  frame.className = "sl-modal-frame";
4362
4450
  frame.setAttribute("role", "dialog");
4363
4451
  frame.setAttribute("aria-modal", "true");
4364
- frame.setAttribute("aria-label", "Seat selection");
4452
+ frame.setAttribute("aria-label", tfStatic("picker.seatSelection", "Seat selection"));
4365
4453
  frame.tabIndex = -1;
4366
4454
  scrim.appendChild(frame);
4367
4455
  document.body.appendChild(scrim);
@@ -4521,7 +4609,7 @@ var SeatPicker = class _SeatPicker {
4521
4609
  <svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
4522
4610
  <span data-ref="closedPillText"></span>
4523
4611
  </span>
4524
- <button type="button" class="sl-close" data-ref="close" aria-label="Close">
4612
+ <button type="button" class="sl-close" data-ref="close" aria-label="${this.tf("picker.close", "Close")}">
4525
4613
  <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
4526
4614
  </button>
4527
4615
  </div>
@@ -4529,17 +4617,17 @@ var SeatPicker = class _SeatPicker {
4529
4617
  <div class="sl-map">
4530
4618
  <div class="sl-map-host" data-ref="map"></div>
4531
4619
  <div class="sl-zoom" data-ref="zoom">
4532
- <button type="button" aria-label="Zoom in" title="Zoom in" data-ref="zin">+</button>
4533
- <button type="button" aria-label="Zoom out" title="Zoom out" data-ref="zout">\u2212</button>
4534
- <button type="button" aria-label="Fit to screen" title="Fit to screen" data-ref="zfit">
4620
+ <button type="button" aria-label="${this.tf("picker.zoomIn", "Zoom in")}" title="${this.tf("picker.zoomIn", "Zoom in")}" data-ref="zin">+</button>
4621
+ <button type="button" aria-label="${this.tf("picker.zoomOut", "Zoom out")}" title="${this.tf("picker.zoomOut", "Zoom out")}" data-ref="zout">\u2212</button>
4622
+ <button type="button" aria-label="${this.tf("picker.fitToScreen", "Fit to screen")}" title="${this.tf("picker.fitToScreen", "Fit to screen")}" data-ref="zfit">
4535
4623
  <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>
4536
4624
  </button>
4537
- <button type="button" aria-label="Full screen" title="Full screen" aria-pressed="false" data-ref="zfs">
4625
+ <button type="button" aria-label="${this.tf("picker.fullScreen", "Full screen")}" title="${this.tf("picker.fullScreen", "Full screen")}" aria-pressed="false" data-ref="zfs">
4538
4626
  <svg viewBox="0 0 24 24"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
4539
- <span class="sl-zfs-lbl" aria-hidden="true">Full screen</span>
4627
+ <span class="sl-zfs-lbl" aria-hidden="true">${this.tf("picker.fullScreen", "Full screen")}</span>
4540
4628
  </button>
4541
4629
  </div>
4542
- <div class="sl-boot" data-ref="boot"><span class="sl-boot-spin"></span>Loading seat map\u2026</div>
4630
+ <div class="sl-boot" data-ref="boot"><span class="sl-boot-spin"></span>${this.tf("picker.loadingSeatMap", "Loading seat map\u2026")}</div>
4543
4631
  <div class="sl-toast" data-ref="toast" role="status" aria-live="polite"></div>
4544
4632
  </div>
4545
4633
  <div class="sl-side" data-ref="side">
@@ -4547,24 +4635,25 @@ var SeatPicker = class _SeatPicker {
4547
4635
  <div class="sl-sheet-grab"></div>
4548
4636
  <div class="sl-sheet-bar">
4549
4637
  <div class="sl-sheet-peek" data-ref="peek"></div>
4550
- <button type="button" class="sl-sheet-toggle" data-ref="sheetToggle" aria-label="Open ticket panel" aria-expanded="false">
4638
+ <button type="button" class="sl-sheet-toggle" data-ref="sheetToggle" aria-label="${this.tf("picker.openTicketPanel", "Open ticket panel")}" aria-expanded="false">
4551
4639
  <svg viewBox="0 0 24 24"><path d="M6 15l6-6 6 6"/></svg>
4552
4640
  </button>
4553
4641
  </div>
4554
4642
  </div>
4555
- <div class="sl-sec sl-filtersec" data-ref="filtersSec">Filters</div>
4643
+ <div class="sl-sec sl-filtersec" data-ref="filtersSec">${this.tf("picker.filters", "Filters")}</div>
4556
4644
  <div class="sl-filters" data-ref="filters"></div>
4557
4645
  <div class="sl-offer" data-ref="offer" role="status" aria-live="polite"></div>
4558
- <div class="sl-sec sl-prices-sec" data-ref="pricesSec"><span>Ticket prices</span></div>
4646
+ <div class="sl-sec sl-prices-sec" data-ref="pricesSec"><span>${this.tf("picker.ticketPrices", "Ticket prices")}</span></div>
4647
+ <div class="sl-prices-hint" data-ref="pricesHint"></div>
4559
4648
  <div class="sl-prices" data-ref="prices"></div>
4560
- <div class="sl-live" data-ref="live" role="status" aria-live="polite"><span class="dot" aria-hidden="true"></span><span data-ref="liveText">Live availability \u2014 seats update in real time</span></div>
4561
- <div class="sl-sec sl-seats-sec"><span>Your seats</span><span class="sl-seat-summary" data-ref="seatSummary"></span></div>
4649
+ <div class="sl-live" data-ref="live" role="status" aria-live="polite"><span class="dot" aria-hidden="true"></span><span data-ref="liveText">${this.tf("picker.liveAvailability", "Live availability \u2014 seats update in real time")}</span></div>
4650
+ <div class="sl-sec sl-seats-sec"><span>${this.tf("picker.yourSeats", "Your seats")}</span><span class="sl-seat-summary" data-ref="seatSummary"></span></div>
4562
4651
  <div class="sl-tray" data-ref="tray"></div>
4563
4652
  <div class="sl-foot" data-ref="foot">
4564
4653
  <div class="sl-hold-note" data-ref="holdNote" role="status" aria-live="polite">
4565
4654
  <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
4566
- <span><b data-ref="holdTitle">Seats secured</b><span class="sl-hold-copy" data-ref="holdCopy">You won\u2019t be charged yet.</span></span>
4567
- <button type="button" class="sl-hold-change" data-ref="holdChange" aria-label="Release held tickets and choose different seats">Change</button>
4655
+ <span><b data-ref="holdTitle">${this.tf("picker.seatsSecured", "Seats secured")}</b><span class="sl-hold-copy" data-ref="holdCopy">${this.tf("picker.notChargedYet", "You won\u2019t be charged yet.")}</span></span>
4656
+ <button type="button" class="sl-hold-change" data-ref="holdChange" aria-label="${this.tf("picker.releaseHeldTickets", "Release held tickets and choose different seats")}">${this.tf("picker.change", "Change")}</button>
4568
4657
  </div>
4569
4658
  <div class="sl-total"><span data-ref="count"></span><b data-ref="total"></b></div>
4570
4659
  <button type="button" class="sl-cta" data-ref="cta" disabled></button>
@@ -4615,7 +4704,7 @@ var SeatPicker = class _SeatPicker {
4615
4704
  const setSheet = (open) => {
4616
4705
  root.dataset.sheet = open ? "open" : "peek";
4617
4706
  toggle?.setAttribute("aria-expanded", String(open));
4618
- toggle?.setAttribute("aria-label", open ? "Collapse ticket panel" : "Open ticket panel");
4707
+ toggle?.setAttribute("aria-label", open ? this.tf("picker.collapseTicketPanel", "Collapse ticket panel") : this.tf("picker.openTicketPanel", "Open ticket panel"));
4619
4708
  };
4620
4709
  setSheet(root.dataset.sheet === "open");
4621
4710
  toggle?.addEventListener("click", (e) => {
@@ -4661,6 +4750,39 @@ var SeatPicker = class _SeatPicker {
4661
4750
  head.releasePointerCapture?.(e.pointerId);
4662
4751
  });
4663
4752
  }
4753
+ const togglePrices = () => {
4754
+ if (this.root?.dataset.layout !== "narrow") return;
4755
+ const open = this.root.getAttribute("data-prices-open") === "true";
4756
+ this.root.setAttribute("data-prices-open", String(!open));
4757
+ this.els.pricesSec?.setAttribute("aria-expanded", String(!open));
4758
+ this.pricesBtnEl?.setAttribute("aria-pressed", String(!open));
4759
+ if (!open && this.root.dataset.sheet !== "open") {
4760
+ this.root.dataset.sheet = "open";
4761
+ const sheetToggle = this.els.sheetToggle;
4762
+ sheetToggle?.setAttribute("aria-expanded", "true");
4763
+ sheetToggle?.setAttribute("aria-label", "Collapse ticket panel");
4764
+ }
4765
+ };
4766
+ this.els.pricesSec?.addEventListener("click", (e) => {
4767
+ if (e.target.closest("select,button")) return;
4768
+ togglePrices();
4769
+ });
4770
+ this.els.pricesSec?.addEventListener("keydown", (e) => {
4771
+ if (e.key !== "Enter" && e.key !== " ") return;
4772
+ if (e.target.closest("select,button")) return;
4773
+ e.preventDefault();
4774
+ togglePrices();
4775
+ });
4776
+ const pricesBtn = document.createElement("button");
4777
+ pricesBtn.type = "button";
4778
+ pricesBtn.className = "sl-prices-btn";
4779
+ pricesBtn.setAttribute("aria-label", this.tf("picker.ticketPrices", "Ticket prices"));
4780
+ pricesBtn.setAttribute("title", this.tf("picker.ticketPrices", "Ticket prices"));
4781
+ pricesBtn.setAttribute("aria-pressed", "false");
4782
+ pricesBtn.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.6 13.4 13.4 20.6a2 2 0 0 1-2.8 0L3 13V5a2 2 0 0 1 2-2h8l7.6 7.6a2 2 0 0 1 0 2.8z"/><circle cx="7.5" cy="7.5" r="1.3"/></svg>';
4783
+ pricesBtn.addEventListener("click", () => togglePrices());
4784
+ this.els.headInfo?.parentElement?.insertBefore(pricesBtn, this.els.hold ?? null);
4785
+ this.pricesBtnEl = pricesBtn;
4664
4786
  this.tipEl = document.createElement("div");
4665
4787
  this.tipEl.setAttribute("role", "tooltip");
4666
4788
  this.tipEl.className = "sl-tip";
@@ -4678,7 +4800,7 @@ var SeatPicker = class _SeatPicker {
4678
4800
  const info = await this.controller.render(canvasHost);
4679
4801
  if (this.destroyed) return this;
4680
4802
  if (!info) {
4681
- this.els.boot.innerHTML = '<div class="sl-boot-title">The seat map didn\u2019t load</div><div>Check your connection and try again.</div><button type="button" class="sl-boot-retry">Try again</button>';
4803
+ this.els.boot.innerHTML = `<div class="sl-boot-title">${this.tf("picker.mapDidNotLoad", "The seat map didn\u2019t load")}</div><div>${this.tf("picker.checkConnection", "Check your connection and try again.")}</div><button type="button" class="sl-boot-retry">${this.tf("picker.accessRetry", "Try again")}</button>`;
4682
4804
  this.els.boot.querySelector("button").addEventListener("click", () => {
4683
4805
  const container = this.opts.container;
4684
4806
  const opts = this.opts;
@@ -4713,6 +4835,12 @@ var SeatPicker = class _SeatPicker {
4713
4835
  const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : "";
4714
4836
  this.eventWhenText = when || null;
4715
4837
  this.els.meta.textContent = [info.venue, when].filter(Boolean).join(" \xB7 ");
4838
+ if (this.els.pricesHint) {
4839
+ this.els.pricesHint.textContent = this.tf(
4840
+ "picker.priceHint",
4841
+ "Colours on the map are ticket types \u2014 tap one below to show just those seats."
4842
+ );
4843
+ }
4716
4844
  this.buildBadge(chartTheme);
4717
4845
  const present = /* @__PURE__ */ new Set();
4718
4846
  let hasLimitedView = false;
@@ -4739,7 +4867,7 @@ var SeatPicker = class _SeatPicker {
4739
4867
  const mk = (key, label) => `<button type="button" class="sl-chip-f${key === "all" ? " on" : ""}" data-a11y="1" data-f="${key}">${label}</button>`;
4740
4868
  chips.insertAdjacentHTML(
4741
4869
  "beforeend",
4742
- mk("all", "All seats") + import_core2.ACCESSIBILITY_TYPES.filter(({ key }) => present.has(key)).map(({ key, short, icon }) => mk(key, `${icon} ${short}`)).join("")
4870
+ mk("all", this.tf("picker.allSeats", "All seats")) + import_core2.ACCESSIBILITY_TYPES.filter(({ key }) => present.has(key)).map(({ key, short, icon }) => mk(key, `${icon} ${short}`)).join("")
4743
4871
  );
4744
4872
  const active = /* @__PURE__ */ new Set();
4745
4873
  const syncChips = () => {
@@ -4785,7 +4913,7 @@ var SeatPicker = class _SeatPicker {
4785
4913
  cb.type = "button";
4786
4914
  cb.className = "sl-cbbtn";
4787
4915
  this.cbEl = cb;
4788
- cb.setAttribute("aria-label", "Toggle colorblind-friendly colors");
4916
+ cb.setAttribute("aria-label", this.tf("picker.toggleColorblindColors", "Toggle colorblind-friendly colors"));
4789
4917
  cb.setAttribute("aria-pressed", String(this.cbSafe));
4790
4918
  cb.innerHTML = '<svg viewBox="0 0 24 24"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg>';
4791
4919
  this.els.zfit.parentElement.appendChild(cb);
@@ -4871,8 +4999,8 @@ var SeatPicker = class _SeatPicker {
4871
4999
  if (!btn) return;
4872
5000
  const collapsed = this.sideCollapsed;
4873
5001
  btn.setAttribute("aria-expanded", String(!collapsed));
4874
- btn.setAttribute("aria-label", collapsed ? "Show the ticket panel" : "Hide the ticket panel");
4875
- 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>';
5002
+ btn.setAttribute("aria-label", collapsed ? this.tf("picker.showTicketPanel", "Show the ticket panel") : this.tf("picker.hideTicketPanel", "Hide the ticket panel"));
5003
+ btn.innerHTML = collapsed ? `<svg viewBox="0 0 24 24"><path d="M15 6l-6 6 6 6"/></svg><span>${this.tf("picker.tickets", "Tickets")}</span>` : `<svg viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></svg><span>${this.tf("picker.hidePanel", "Hide panel")}</span>`;
4876
5004
  }
4877
5005
  /**
4878
5006
  * Collapse or reopen the wide-layout ticket panel in place (host-drivable —
@@ -4898,13 +5026,24 @@ var SeatPicker = class _SeatPicker {
4898
5026
  const narrow = this.root?.dataset.layout === "narrow";
4899
5027
  this.applyPanelCollapsed();
4900
5028
  const zfs = this.els.zfs;
4901
- if (zfs) {
4902
- if (narrow && this.regions["top-right"]) {
4903
- zfs.classList.add("sl-fs-pill");
4904
- this.regions["top-right"].appendChild(zfs);
4905
- } else if (!narrow && this.els.zoom && zfs.parentElement !== this.els.zoom) {
4906
- zfs.classList.remove("sl-fs-pill");
4907
- this.els.zoom.appendChild(zfs);
5029
+ const head = this.els.headInfo?.parentElement;
5030
+ if (zfs && head && zfs.parentElement !== head) {
5031
+ zfs.classList.add("sl-fs-pill");
5032
+ head.insertBefore(zfs, this.els.hold ?? null);
5033
+ }
5034
+ const pricesSec = this.els.pricesSec;
5035
+ if (pricesSec) {
5036
+ if (narrow) {
5037
+ pricesSec.setAttribute("role", "button");
5038
+ pricesSec.tabIndex = 0;
5039
+ pricesSec.setAttribute(
5040
+ "aria-expanded",
5041
+ String(this.root?.getAttribute("data-prices-open") === "true")
5042
+ );
5043
+ } else {
5044
+ pricesSec.removeAttribute("role");
5045
+ pricesSec.removeAttribute("aria-expanded");
5046
+ pricesSec.tabIndex = -1;
4908
5047
  }
4909
5048
  }
4910
5049
  const filters = this.els.filters;
@@ -4931,7 +5070,7 @@ var SeatPicker = class _SeatPicker {
4931
5070
  this.extendEl = el2;
4932
5071
  this.els.extendTxt = el2.querySelector('[data-ref="extendTxt"]');
4933
5072
  this.els.extendBtn = el2.querySelector('[data-ref="extendBtn"]');
4934
- this.els.extendBtn.textContent = "Add time";
5073
+ this.els.extendBtn.textContent = this.tf("picker.addTime", "Add time");
4935
5074
  this.els.extendBtn.addEventListener("click", () => void this.handleExtend());
4936
5075
  }
4937
5076
  /** Success overlay + onBooked fire when the held seats settle to booked. */
@@ -4940,7 +5079,7 @@ var SeatPicker = class _SeatPicker {
4940
5079
  el2.className = "sl-booked";
4941
5080
  el2.setAttribute("role", "status");
4942
5081
  el2.setAttribute("aria-live", "polite");
4943
- el2.innerHTML = `<div class="sl-booked-badge"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></div><div class="sl-booked-title">You're all set</div><div class="sl-booked-sub" data-ref="bookedSub"></div>`;
5082
+ el2.innerHTML = `<div class="sl-booked-badge"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></div><div class="sl-booked-title">${this.tf("picker.allSetTitle", "You're all set")}</div><div class="sl-booked-sub" data-ref="bookedSub"></div>`;
4944
5083
  this.root.appendChild(el2);
4945
5084
  this.bookedEl = el2;
4946
5085
  this.els.bookedSub = el2.querySelector('[data-ref="bookedSub"]');
@@ -4951,8 +5090,7 @@ var SeatPicker = class _SeatPicker {
4951
5090
  * host `messages` override (which makes `t()` return the override, not the key).
4952
5091
  */
4953
5092
  tf(key, fallback) {
4954
- const v = (0, import_core2.t)(key);
4955
- return v === key ? fallback : v;
5093
+ return tfStatic(key, fallback);
4956
5094
  }
4957
5095
  /** Sold-out overlay — an informational state with no unavailable action. */
4958
5096
  buildSoldoutOverlay() {
@@ -5137,7 +5275,7 @@ var SeatPicker = class _SeatPicker {
5137
5275
  }
5138
5276
  canAddTicket() {
5139
5277
  if (this.totalTicketCount() < this.maxTickets) return true;
5140
- this.toast(`You can select up to ${this.maxTickets} tickets for this order.`, "warning");
5278
+ this.toast((0, import_core2.t)("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
5141
5279
  return false;
5142
5280
  }
5143
5281
  pendingGATotal(gaAreas) {
@@ -5160,21 +5298,21 @@ var SeatPicker = class _SeatPicker {
5160
5298
  }
5161
5299
  if (this.confirmSeat || this.tableDialog && !this.tableDialogHeld) {
5162
5300
  cta.disabled = true;
5163
- cta.textContent = this.tableDialog ? "Confirm your table" : "Confirm or cancel this seat";
5301
+ cta.textContent = this.tableDialog ? this.tf("picker.confirmYourTable", "Confirm your table") : this.tf("picker.confirmOrCancelSeat", "Confirm or cancel this seat");
5164
5302
  return;
5165
5303
  }
5166
5304
  if (this.ctaPhase === "holding") {
5167
5305
  cta.disabled = true;
5168
- cta.innerHTML = '<span class="sl-cta-spin" aria-hidden="true"></span>Securing seats\u2026';
5306
+ cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}`;
5169
5307
  return;
5170
5308
  }
5171
5309
  if (this.ctaPhase === "checkout") {
5172
5310
  cta.disabled = true;
5173
- cta.innerHTML = '<span class="sl-cta-spin" aria-hidden="true"></span>Opening secure checkout\u2026';
5311
+ cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.openingCheckout", "Opening secure checkout\u2026")}`;
5174
5312
  return;
5175
5313
  }
5176
5314
  cta.disabled = count === 0;
5177
- cta.textContent = this.hold ? pending ? `Secure ${pending} more & checkout` : "Continue to checkout" : count ? "Hold seats & checkout" : "Select seats";
5315
+ cta.textContent = this.hold ? pending ? (0, import_core2.t)("picker.secureMoreAndCheckout", { count: pending }) : this.tf("picker.continueToCheckout", "Continue to checkout") : count ? this.tf("picker.holdSeatsAndCheckout", "Hold seats & checkout") : this.tf("picker.selectSeats", "Select seats");
5178
5316
  }
5179
5317
  setCtaPhase(phase) {
5180
5318
  this.ctaPhase = phase;
@@ -5235,7 +5373,7 @@ var SeatPicker = class _SeatPicker {
5235
5373
  this.syncTray();
5236
5374
  this.emitHoldChange();
5237
5375
  this.opts.onHoldRestored?.(restored, restored.seats ?? [], this.buildHandoff(restored));
5238
- if (automatic) this.toast("Your held tickets have been restored.", "success");
5376
+ if (automatic) this.toast(this.tf("picker.heldTicketsRestored", "Your held tickets have been restored."), "success");
5239
5377
  return restored;
5240
5378
  } catch (error) {
5241
5379
  const status = error?.status;
@@ -5453,8 +5591,8 @@ var SeatPicker = class _SeatPicker {
5453
5591
  if (bands.length < 2) return;
5454
5592
  const select = document.createElement("select");
5455
5593
  select.className = "sl-price-select";
5456
- select.setAttribute("aria-label", "Filter and focus seats by price");
5457
- select.innerHTML = `<option value="all">All prices</option>` + bands.map((band) => `<option value="${band.id}">${band.label}</option>`).join("");
5594
+ select.setAttribute("aria-label", this.tf("picker.filterAndFocusByPrice", "Filter and focus seats by price"));
5595
+ select.innerHTML = `<option value="all">${this.tf("picker.allPrices", "All prices")}</option>` + bands.map((band) => `<option value="${band.id}">${band.label}</option>`).join("");
5458
5596
  this.els.pricesSec.appendChild(select);
5459
5597
  select.addEventListener("change", () => {
5460
5598
  const band = bands.find((candidate) => candidate.id === select.value);
@@ -5481,8 +5619,8 @@ var SeatPicker = class _SeatPicker {
5481
5619
  const projection = document.createElement("div");
5482
5620
  projection.className = "sl-projection";
5483
5621
  projection.setAttribute("role", "group");
5484
- projection.setAttribute("aria-label", "Venue view");
5485
- projection.innerHTML = '<button type="button" data-view="map" aria-pressed="true" title="Flat 2D map">Map</button><button type="button" data-view="venue3d" aria-pressed="false" title="Interactive 3D venue view">3D</button>';
5622
+ projection.setAttribute("aria-label", this.tf("picker.venueView", "Venue view"));
5623
+ projection.innerHTML = `<button type="button" data-view="map" aria-pressed="true" title="${this.tf("picker.flat2dMap", "Flat 2D map")}">${this.tf("picker.map", "Map")}</button><button type="button" data-view="venue3d" aria-pressed="false" title="${this.tf("picker.interactive3dVenueView", "Interactive 3D venue view")}">3D</button>`;
5486
5624
  projection.querySelectorAll("button").forEach((button) => {
5487
5625
  button.addEventListener("click", () => {
5488
5626
  this.setBuyerView(button.dataset.view);
@@ -5605,6 +5743,10 @@ var SeatPicker = class _SeatPicker {
5605
5743
  renderSectionCard(summary) {
5606
5744
  if (!this.els.map) return;
5607
5745
  this.secCardEl?.remove();
5746
+ if (this.root?.dataset.layout === "narrow" && (this.hold || this.committedSelection().length || this.pendingGACount())) {
5747
+ this.lastSection = null;
5748
+ return;
5749
+ }
5608
5750
  const paid = summary.categories.length ? summary.categories.map((c) => this.paidPrice(c.key, null, c.price)) : [summary.priceMin, summary.priceMax];
5609
5751
  const paidMin = Math.min(...paid);
5610
5752
  const paidMax = Math.max(...paid);
@@ -5705,13 +5847,13 @@ var SeatPicker = class _SeatPicker {
5705
5847
  }
5706
5848
  const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);
5707
5849
  const status = this.controller.getStatus(seat.id) ?? "free";
5708
- const statusText = status === "free" ? "available" : status === "held" ? "on hold" : "taken";
5850
+ const statusText = status === "free" ? this.tf("picker.statusAvailable", "available") : status === "held" ? this.tf("picker.statusOnHold", "on hold") : this.tf("picker.statusTaken2", "taken");
5709
5851
  const price = cat ? this.catPrice(cat) : void 0;
5710
5852
  const table = this.controller.tableSelection(seat.id);
5711
5853
  const details = table ?? this.controller.seatDetails(seat.id);
5712
5854
  const typeWord = this.rowTypeWord(details);
5713
5855
  const buyerName = details?.rowLabel ?? details?.displayLabel ?? seat.displayLabel ?? seat.label;
5714
- const identity = table ? `${typeWord} ${buyerName}, ${table.bookingMode === "variable" ? `${table.minOccupancy} to ${table.maxOccupancy} guests` : `${table.capacity} guests`}` : details?.objectType === "booth" ? `${typeWord} ${buyerName}` : details?.objectType === "table" ? `${typeWord} ${buyerName}, seat ${details.seatNumber ?? seat.label}` : `Seat ${details?.displayLabel ?? seat.displayLabel ?? seat.label}`;
5856
+ const identity = table ? `${typeWord} ${buyerName}, ${table.bookingMode === "variable" ? (0, import_core2.t)("picker.minToMaxGuests", { min: table.minOccupancy, max: table.maxOccupancy }) : (0, import_core2.t)("picker.capacityGuests", { count: table.capacity })}` : details?.objectType === "booth" ? `${typeWord} ${buyerName}` : details?.objectType === "table" ? `${typeWord} ${buyerName}, ${(0, import_core2.t)("picker.seatNumberLower", { label: details.seatNumber ?? seat.label })}` : (0, import_core2.t)("picker.seatLabel", { label: details?.displayLabel ?? seat.displayLabel ?? seat.label });
5715
5857
  this.srEl.textContent = `${identity}, ${cat?.label ?? seat.categoryKey}${price != null ? `, ${this.money(price)}` : ""}, ${statusText}`;
5716
5858
  }
5717
5859
  // ---- atomic table confirmation / guest quantity ---------------------------
@@ -5732,7 +5874,7 @@ var SeatPicker = class _SeatPicker {
5732
5874
  const typeWord = this.rowTypeWord(table);
5733
5875
  const el2 = document.createElement("div");
5734
5876
  el2.className = "sl-table-scrim";
5735
- el2.innerHTML = `<section class="sl-table-dialog" role="dialog" aria-modal="true" aria-labelledby="sl-table-title" aria-describedby="sl-table-copy"><div class="sl-table-head"><div class="sl-table-eyebrow">${esc(variable ? `Flexible party \xB7 ${typeWord}` : `Whole ${typeWord}`)}</div><h2 class="sl-table-title" id="sl-table-title">${esc(table.displayLabel ?? table.label)}</h2><p class="sl-table-copy" id="sl-table-copy">${variable ? `Choose how many guests will sit together. This table is held exclusively for your party.` : `All ${table.capacity} places are booked together as one exclusive table.`}</p></div><div class="sl-table-body"><div class="sl-table-summary"><span>${esc(cat?.label ?? table.categoryKey)}</span><b data-table-unit>${this.money(this.paidPrice(table.categoryKey, table.tierId ?? null, table.price))} per guest</b><span class="muted">Table capacity</span><span>${table.capacity} guests</span><span class="muted">Total</span><b data-table-total></b></div>` + (variable ? `<label class="sl-table-qtylabel" id="sl-table-qty-label">Number of guests</label><div class="sl-table-stepper" role="group" aria-labelledby="sl-table-qty-label"><button type="button" data-table-step="-1" aria-label="Fewer guests">\u2212</button><output aria-live="polite" data-table-qty>${table.quantity}</output><button type="button" data-table-step="1" aria-label="More guests">+</button></div><div class="sl-table-range">Choose ${table.minOccupancy}\u2013${table.maxOccupancy} guests</div>` : `<input type="hidden" data-table-qty value="${table.capacity}">`) + `<div class="sl-table-actions"><button type="button" class="sl-table-cancel">Cancel</button><button type="button" class="sl-table-confirm">${held ? "Update table" : variable ? "Select table" : "Select whole table"}</button></div></div></section>`;
5877
+ el2.innerHTML = `<section class="sl-table-dialog" role="dialog" aria-modal="true" aria-labelledby="sl-table-title" aria-describedby="sl-table-copy"><div class="sl-table-head"><div class="sl-table-eyebrow">${esc(variable ? (0, import_core2.t)("picker.flexiblePartyTypeWord", { typeWord }) : (0, import_core2.t)("picker.wholeTypeWord", { typeWord }))}</div><h2 class="sl-table-title" id="sl-table-title">${esc(table.displayLabel ?? table.label)}</h2><p class="sl-table-copy" id="sl-table-copy">${variable ? this.tf("picker.chooseGuestsCopy", "Choose how many guests will sit together. This table is held exclusively for your party.") : (0, import_core2.t)("picker.allPlacesBookedTogether", { count: table.capacity })}</p></div><div class="sl-table-body"><div class="sl-table-summary"><span>${esc(cat?.label ?? table.categoryKey)}</span><b data-table-unit>${(0, import_core2.t)("picker.perGuestPrice", { price: this.money(this.paidPrice(table.categoryKey, table.tierId ?? null, table.price)) })}</b><span class="muted">${this.tf("picker.tableCapacity", "Table capacity")}</span><span>${(0, import_core2.t)("picker.guestsCount", { count: table.capacity })}</span><span class="muted">${this.tf("picker.total", "Total")}</span><b data-table-total></b></div>` + (variable ? `<label class="sl-table-qtylabel" id="sl-table-qty-label">${this.tf("picker.numberOfGuests", "Number of guests")}</label><div class="sl-table-stepper" role="group" aria-labelledby="sl-table-qty-label"><button type="button" data-table-step="-1" aria-label="${this.tf("picker.fewerGuests", "Fewer guests")}">\u2212</button><output aria-live="polite" data-table-qty>${table.quantity}</output><button type="button" data-table-step="1" aria-label="${this.tf("picker.moreGuests", "More guests")}">+</button></div><div class="sl-table-range">${(0, import_core2.t)("picker.chooseMinMaxGuests", { min: table.minOccupancy, max: table.maxOccupancy })}</div>` : `<input type="hidden" data-table-qty value="${table.capacity}">`) + `<div class="sl-table-actions"><button type="button" class="sl-table-cancel">${(0, import_core2.t)("common.cancel")}</button><button type="button" class="sl-table-confirm">${held ? this.tf("picker.updateTable", "Update table") : variable ? this.tf("picker.selectTable", "Select table") : this.tf("picker.selectWholeTable", "Select whole table")}</button></div></div></section>`;
5736
5878
  this.root.appendChild(el2);
5737
5879
  this.tableDialogEl = el2;
5738
5880
  this.renderTableDialogState();
@@ -5791,17 +5933,17 @@ var SeatPicker = class _SeatPicker {
5791
5933
  const button = this.tableDialogEl?.querySelector(".sl-table-confirm");
5792
5934
  if (button) {
5793
5935
  button.disabled = true;
5794
- button.textContent = held ? "Updating\u2026" : "Selecting\u2026";
5936
+ button.textContent = held ? this.tf("picker.updatingEllipsis", "Updating\u2026") : this.tf("picker.selectingEllipsis", "Selecting\u2026");
5795
5937
  }
5796
5938
  if (held) {
5797
5939
  try {
5798
5940
  const updated = await this.controller.replaceTableQuantity(table.label, table.quantity, this.opts.holdTtlMs);
5799
5941
  if (!updated) {
5800
- this.toast("That guest count could not be secured. Your current table hold is unchanged.", "warning");
5942
+ this.toast(this.tf("picker.guestCountCouldNotBeSecured", "That guest count could not be secured. Your current table hold is unchanged."), "warning");
5801
5943
  this.renderTableDialogState();
5802
5944
  if (button) {
5803
5945
  button.disabled = false;
5804
- button.textContent = "Update table";
5946
+ button.textContent = this.tf("picker.updateTable", "Update table");
5805
5947
  }
5806
5948
  return;
5807
5949
  }
@@ -5815,13 +5957,13 @@ var SeatPicker = class _SeatPicker {
5815
5957
  this.dismissTableDialog();
5816
5958
  this.syncTray();
5817
5959
  this.emitHoldChange();
5818
- this.toast(`${table.label} updated for ${table.quantity} guests.`, "success");
5960
+ this.toast((0, import_core2.t)("picker.tableUpdatedForGuests", { label: table.label, count: table.quantity }), "success");
5819
5961
  } catch (error) {
5820
5962
  this.opts.onError?.(error);
5821
- this.toast("That guest count is no longer available. Your current hold is unchanged.", "error");
5963
+ this.toast(this.tf("picker.guestCountNoLongerAvailable", "That guest count is no longer available. Your current hold is unchanged."), "error");
5822
5964
  if (button) {
5823
5965
  button.disabled = false;
5824
- button.textContent = "Update table";
5966
+ button.textContent = this.tf("picker.updateTable", "Update table");
5825
5967
  }
5826
5968
  }
5827
5969
  return;
@@ -5829,7 +5971,7 @@ var SeatPicker = class _SeatPicker {
5829
5971
  if (!this.controller.setTableQuantity(table.label, table.quantity)) {
5830
5972
  if (button) {
5831
5973
  button.disabled = false;
5832
- button.textContent = table.bookingMode === "variable" ? "Select table" : "Select whole table";
5974
+ button.textContent = table.bookingMode === "variable" ? this.tf("picker.selectTable", "Select table") : this.tf("picker.selectWholeTable", "Select whole table");
5833
5975
  }
5834
5976
  return;
5835
5977
  }
@@ -5875,16 +6017,16 @@ var SeatPicker = class _SeatPicker {
5875
6017
  '"': "&quot;"
5876
6018
  })[char]);
5877
6019
  const identityFields = [
5878
- details?.sectionLabel ? `<div class="sl-confirm-field"><span class="sl-confirm-key">Section</span><span class="sl-confirm-value">${safe(details.sectionLabel)}</span></div>` : "",
6020
+ details?.sectionLabel ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${this.tf("picker.section", "Section")}</span><span class="sl-confirm-value">${safe(details.sectionLabel)}</span></div>` : "",
5879
6021
  details?.rowLabel || details?.objectType === "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${safe(this.rowTypeWord(details))}</span><span class="sl-confirm-value">${safe(this.rowShort(details) ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>` : "",
5880
- details?.objectType !== "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key">Seat</span><span class="sl-confirm-value">${safe(details?.seatNumber ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>` : ""
6022
+ details?.objectType !== "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-confirm-value">${safe(details?.seatNumber ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>` : ""
5881
6023
  ].filter(Boolean).join("");
5882
6024
  const el2 = document.createElement("div");
5883
6025
  el2.className = "sl-confirm";
5884
6026
  el2.setAttribute("role", "dialog");
5885
- el2.setAttribute("aria-label", `Confirm seat ${seat.label}`);
6027
+ el2.setAttribute("aria-label", (0, import_core2.t)("picker.confirmSeatLabel", { label: seat.label }));
5886
6028
  el2.style.setProperty("--sl-cat", cat?.color ?? "#6e7bff");
5887
- 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>`;
6029
+ 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">${(0, import_core2.t)("common.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>${this.tf("picker.select", "Select")}</button></div></div>`;
5888
6030
  this.els.map.appendChild(el2);
5889
6031
  this.confirmEl = el2;
5890
6032
  const thumb = el2.querySelector(".sl-confirm-thumb");
@@ -6037,7 +6179,7 @@ var SeatPicker = class _SeatPicker {
6037
6179
  el2.className = "sl-view";
6038
6180
  el2.setAttribute("role", "dialog");
6039
6181
  el2.setAttribute("aria-label", (0, import_core2.t)("picker.viewFromSeat", { label: seat.label }));
6040
- el2.innerHTML = `<div class="sl-view-head"><span class="sl-view-title">${(0, import_core2.t)("picker.viewFromSeat", { label: seat.label })}</span><span class="sl-view-cap">${caption}</span><button type="button" class="sl-view-x" aria-label="Close"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="sl-view-pano"><span class="sl-view-badge">${real ? (0, import_core2.t)("picker.real360") : (0, import_core2.t)("picker.preview")}</span><span class="sl-view-hint">Drag to look around \xB7 scroll to zoom</span></div>`;
6182
+ el2.innerHTML = `<div class="sl-view-head"><span class="sl-view-title">${(0, import_core2.t)("picker.viewFromSeat", { label: seat.label })}</span><span class="sl-view-cap">${caption}</span><button type="button" class="sl-view-x" aria-label="${this.tf("picker.close", "Close")}"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="sl-view-pano"><span class="sl-view-badge">${real ? (0, import_core2.t)("picker.real360") : (0, import_core2.t)("picker.preview")}</span><span class="sl-view-hint">${this.tf("picker.dragToLookAround", "Drag to look around \xB7 scroll to zoom")}</span></div>`;
6041
6183
  this.root.appendChild(el2);
6042
6184
  this.viewEl = el2;
6043
6185
  const pano = el2.querySelector(".sl-view-pano");
@@ -6233,27 +6375,27 @@ var SeatPicker = class _SeatPicker {
6233
6375
  copy.className = "sl-offer-copy";
6234
6376
  const kicker = document.createElement("span");
6235
6377
  kicker.className = "sl-offer-kicker";
6236
- kicker.textContent = active ? "Current ticket offer" : "Upcoming ticket offer";
6378
+ kicker.textContent = active ? this.tf("picker.currentTicketOffer", "Current ticket offer") : this.tf("picker.upcomingTicketOffer", "Upcoming ticket offer");
6237
6379
  const name = document.createElement("strong");
6238
6380
  name.className = "sl-offer-name";
6239
- name.textContent = offer.name || (active ? "Current offer" : "Scheduled offer");
6381
+ name.textContent = offer.name || (active ? this.tf("picker.currentOffer", "Current offer") : this.tf("picker.scheduledOffer", "Scheduled offer"));
6240
6382
  const line = document.createElement("span");
6241
6383
  line.className = "sl-offer-line";
6242
6384
  const facts = [];
6243
6385
  if (active && availability.fromPrice != null) facts.push(this.money(availability.fromPrice / 100));
6244
- if (active && offer.remaining != null) facts.push(`${offer.remaining} available`);
6245
- if (active && offer.endsAt != null) facts.push(`until ${formatWhen(offer.endsAt, this.eventTimezone, this.opts.locale)}`);
6246
- if (upcoming?.startsAt != null) facts.push(`starts ${formatWhen(upcoming.startsAt, this.eventTimezone, this.opts.locale)}`);
6386
+ if (active && offer.remaining != null) facts.push((0, import_core2.t)("picker.offerRemainingAvailable", { count: offer.remaining }));
6387
+ if (active && offer.endsAt != null) facts.push((0, import_core2.t)("picker.offerUntil", { time: formatWhen(offer.endsAt, this.eventTimezone, this.opts.locale) }));
6388
+ if (upcoming?.startsAt != null) facts.push((0, import_core2.t)("picker.offerStarts", { time: formatWhen(upcoming.startsAt, this.eventTimezone, this.opts.locale) }));
6247
6389
  line.textContent = facts.join(" \xB7 ");
6248
6390
  copy.append(kicker, name, line);
6249
6391
  const info = document.createElement("details");
6250
6392
  info.className = "sl-offer-info";
6251
6393
  const summary = document.createElement("summary");
6252
- summary.setAttribute("aria-label", `How the ${name.textContent} offer works`);
6394
+ summary.setAttribute("aria-label", (0, import_core2.t)("picker.howOfferWorks", { name: name.textContent ?? "" }));
6253
6395
  summary.textContent = "i";
6254
6396
  const detail = document.createElement("div");
6255
6397
  detail.className = "sl-offer-detail";
6256
- detail.textContent = active ? `This price applies automatically to eligible seats. Tickets in active carts temporarily reduce the available quantity; released or expired holds return it. When the offer ends, the next matching offer or normal ticket price takes over.` : `Tickets are available at their normal price now. This scheduled offer will apply automatically to eligible seats when it starts.`;
6398
+ detail.textContent = active ? this.tf("picker.offerDetailActive", "This price applies automatically to eligible seats. Tickets in active carts temporarily reduce the available quantity; released or expired holds return it. When the offer ends, the next matching offer or normal ticket price takes over.") : this.tf("picker.offerDetailUpcoming", "Tickets are available at their normal price now. This scheduled offer will apply automatically to eligible seats when it starts.");
6257
6399
  info.append(summary, detail);
6258
6400
  main.append(copy, info);
6259
6401
  host.replaceChildren(main);
@@ -6289,8 +6431,8 @@ var SeatPicker = class _SeatPicker {
6289
6431
  const previous = offer?.previousPrice != null && offer.previousPrice > offer.price ? offer.previousPrice : null;
6290
6432
  const active = this.focusedCatKey === c.key;
6291
6433
  const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);
6292
- return `<div class="sl-price-row${dim ? " sl-dim" : ""}${active ? " sl-active" : ""}" data-cat="${escapeOption(c.key)}" role="button" tabindex="0" aria-pressed="${active}" title="${escapeOption(active ? "Show all seats" : `Show ${c.label} seats on the map`)}"><span class="sl-dot" style="background:${escapeOption(c.color)}"></span><span class="sl-price-label">${escapeOption(c.label)}` + (offer?.offerName ? `<small class="sl-price-offer">${escapeOption(offer.offerName)}</small>` : "") + `</span><span class="sl-price-left">${left[c.key] ?? 0} left</span>` + (previous != null ? `<span class="sl-price-was">${escapeOption(this.money(previous))}</span>` : "") + (price != null ? `<span class="sl-price-amt">${this.money(price)}</span>` : "") + `</div>`;
6293
- }).join("") + (overflow > 1 ? `<button type="button" class="sl-price-more" aria-expanded="${!collapsed}">` + (collapsed ? `Show all ${doc.categories.length} ticket types` : "Show fewer") + `</button>` : "") + `<div class="sl-status-key" aria-label="Seat status legend"><span class="sl-status-item"><i class="sl-status-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></i>Temporarily held</span><span class="sl-status-item"><i class="sl-status-icon sold" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M7 17L17 7"/></svg></i>Sold</span></div>`;
6434
+ return `<div class="sl-price-row${dim ? " sl-dim" : ""}${active ? " sl-active" : ""}" data-cat="${escapeOption(c.key)}" role="button" tabindex="0" aria-pressed="${active}" title="${escapeOption(active ? this.tf("picker.showAllSeats", "Show all seats") : (0, import_core2.t)("picker.showLabelSeatsOnMap", { label: c.label }))}"><span class="sl-dot" style="background:${escapeOption(c.color)}"></span><span class="sl-price-label">${escapeOption(c.label)}` + (offer?.offerName ? `<small class="sl-price-offer">${escapeOption(offer.offerName)}</small>` : "") + `</span><span class="sl-price-left">${(0, import_core2.tCount)("picker.leftCount", left[c.key] ?? 0)}</span>` + (previous != null ? `<span class="sl-price-was">${escapeOption(this.money(previous))}</span>` : "") + (price != null ? `<span class="sl-price-amt">${this.money(price)}</span>` : "") + `</div>`;
6435
+ }).join("") + (overflow > 1 ? `<button type="button" class="sl-price-more" aria-expanded="${!collapsed}">` + (collapsed ? (0, import_core2.t)("picker.showAllTicketTypes", { count: doc.categories.length }) : this.tf("picker.showFewer", "Show fewer")) + `</button>` : "") + `<div class="sl-status-key" aria-label="${this.tf("picker.seatStatusLegend", "Seat status legend")}"><span class="sl-status-item"><i class="sl-status-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></i>${this.tf("picker.temporarilyHeld", "Temporarily held")}</span><span class="sl-status-item"><i class="sl-status-icon sold" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M7 17L17 7"/></svg></i>${this.tf("picker.sold", "Sold")}</span></div>`;
6294
6436
  this.els.prices.querySelectorAll(".sl-price-row").forEach((row) => {
6295
6437
  row.addEventListener("mouseenter", () => this.controller.getRenderer()?.setCategoryHighlight?.(row.dataset.cat ?? null));
6296
6438
  row.addEventListener("mouseleave", () => this.controller.getRenderer()?.setCategoryHighlight?.(null));
@@ -6348,7 +6490,7 @@ var SeatPicker = class _SeatPicker {
6348
6490
  const now = left[cat.key] ?? 0;
6349
6491
  if (before === void 0 || now >= before) continue;
6350
6492
  const taken = before - now;
6351
- textEl.textContent = `${taken} seat${taken === 1 ? "" : "s"} just taken in ${cat.label} \xB7 ${now} left`;
6493
+ textEl.textContent = (0, import_core2.tCount)("picker.seatsJustTakenInCategory", taken, { label: cat.label, left: now });
6352
6494
  this.els.live?.classList.remove("on");
6353
6495
  void this.els.live?.offsetWidth;
6354
6496
  this.els.live?.classList.add("on");
@@ -6366,12 +6508,17 @@ var SeatPicker = class _SeatPicker {
6366
6508
  const gone = this.controller.getSelection().filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? "free") !== "free");
6367
6509
  if (!gone.length) return;
6368
6510
  this.controller.deselect(gone.map((s) => s.id));
6369
- this.toast(`Seat ${gone[0].label} was just taken by another buyer.`, "error");
6511
+ this.toast((0, import_core2.t)("picker.seatJustTakenByAnother", { label: gone[0].label }), "error");
6370
6512
  }
6371
6513
  syncTray() {
6372
6514
  if (!this.els.tray) return;
6373
6515
  this.updateSelectionCapacity();
6374
6516
  const seats = this.committedSelection();
6517
+ if (this.root?.dataset.layout === "narrow" && this.secCardEl && (this.hold || seats.length || this.pendingGACount())) {
6518
+ this.secCardEl.remove();
6519
+ this.secCardEl = null;
6520
+ this.lastSection = null;
6521
+ }
6375
6522
  const gaAreas = this.controller.getGAAreas();
6376
6523
  const heldItems = this.hold?.items ?? [];
6377
6524
  const parts = [];
@@ -6382,18 +6529,22 @@ var SeatPicker = class _SeatPicker {
6382
6529
  `<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>`
6383
6530
  );
6384
6531
  } else if (!seats.length && !heldItems.length && !gaAreas.length) {
6385
- parts.push(`<div class="sl-tray-hint">Tap a seat on the map, or let us pick the best available for you.</div>`);
6532
+ parts.push(`<div class="sl-tray-hint">${this.tf("picker.trayHintTapOrBest", "Tap a seat on the map, or let us pick the best available for you.")}</div>`);
6386
6533
  } else if (!seats.length && !heldItems.length) {
6387
- parts.push(`<div class="sl-tray-hint">Tap a seat on the map \u2014 or grab standing tickets below.</div>`);
6534
+ parts.push(`<div class="sl-tray-hint">${this.tf("picker.trayHintTapOrStanding", "Tap a seat on the map \u2014 or grab standing tickets below.")}</div>`);
6388
6535
  }
6389
6536
  const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();
6390
- if (!this.salesClosed && !this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {
6537
+ if (noPicks) this.baReopen = false;
6538
+ if (!this.salesClosed && !this.hold && (noPicks || this.baReopen || this.bestAvailableBusy || this.bestAvailableConfirm)) {
6391
6539
  const cats = this.controller.doc?.categories ?? [];
6392
6540
  const zones = this.controller.getBestAvailableZones();
6393
6541
  if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = "";
6394
- 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
6542
+ parts.push(this.bestAvailableConfirm ? `<div class="sl-ba" role="alert"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>${this.tf("picker.replaceCurrentChoices", "Replace your current choices?")}</div><div class="sl-ba-replace"><b>${(0, import_core2.t)("picker.willFindSeatsTogether", { count: this.baQty })}</b><span>${this.tf("picker.manualTicketsRemovedNote", "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>${this.tf("picker.keepMine", "Keep mine")}</button><button type="button" class="replace" data-ba-replace>${this.tf("picker.findNewSeats", "Find new seats")}</button></div></div>` : `<div class="sl-ba"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>${this.tf("picker.findBestSeatsTogether", "Find the best seats together")}</div><div class="sl-ba-copy"><span class="wide">${this.tf("picker.willChooseClosestGroup", "We\u2019ll choose the closest available group for you.")}</span><span class="narrow">${this.tf("picker.closestGroupChosenInstantly", "Closest available group, chosen instantly.")}</span></div>` + // Premium quick-pick — present only when the chart actually has premium
6395
6543
  // seats (same present-only philosophy as the a11y filter chips).
6396
- (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>`);
6544
+ (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="${this.tf("picker.preferredTicketType", "Preferred ticket type")}" data-ba-cat><option value="">${this.tf("picker.anyTicketType", "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="${this.tf("picker.preferredVenueZone", "Preferred venue zone")}" data-ba-zone><option value="">${this.tf("picker.anyVenueZone", "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="${this.tf("picker.fewerSeats", "Fewer seats")}">\u2212</button><span>${this.baQty}</span><button type="button" data-ba="1" aria-label="${this.tf("picker.moreSeats", "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>${this.tf("picker.findingBestSeats", "Finding the best seats\u2026")}` : (0, import_core2.tCount)("picker.findBestSeatsCount", this.baQty)) + `</button>` + // Reopened over an existing selection: the buyer needs the way back
6545
+ // stated as plainly as the way forward (Go routes through the
6546
+ // "Replace your current choices?" confirm, so nothing is lost yet).
6547
+ (this.baReopen ? `<button type="button" class="sl-ba-back" data-ba-close>${this.tf("picker.keepMyPicks", "Keep my picks")}</button>` : "") + `</div>`);
6397
6548
  }
6398
6549
  const idGrid = (seatId, label, objectType, quantity = 1, objectId, identity) => {
6399
6550
  const esc = (value) => String(value ?? "\u2014").replace(/[&<>"]/g, (char) => ({
@@ -6405,21 +6556,21 @@ var SeatPicker = class _SeatPicker {
6405
6556
  const d = seatId ? this.controller.seatDetails(seatId) : null;
6406
6557
  const area = objectType === "ga" ? gaAreas.find((candidate) => candidate.id === objectId) : void 0;
6407
6558
  const effectiveType = objectType === "ga" ? "ga" : d?.objectType ?? objectType;
6408
- const typeWord = identity?.displayType?.trim() || d?.displayType?.trim() || area?.displayType?.trim() || (effectiveType === "table" ? "Table" : effectiveType === "booth" ? "Booth" : effectiveType === "ga" ? "General admission" : "Row");
6559
+ const typeWord = identity?.displayType?.trim() || d?.displayType?.trim() || area?.displayType?.trim() || (effectiveType === "table" ? this.tf("picker.table", "Table") : effectiveType === "booth" ? this.tf("picker.booth", "Booth") : effectiveType === "ga" ? this.tf("picker.generalAdmission", "General admission") : this.tf("picker.row", "Row"));
6409
6560
  const buyerName = identity?.rowLabel ?? identity?.displayLabel ?? d?.rowLabel ?? d?.displayLabel ?? area?.displayLabel ?? area?.label ?? label;
6410
6561
  if (effectiveType === "table" && identity?.bookingMode) {
6411
- return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span><span class="fld mid"><span class="sl-chip-eb">Guests</span><span class="val">${quantity}</span></span></div>`;
6562
+ return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span><span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.guests", "Guests")}</span><span class="val">${quantity}</span></span></div>`;
6412
6563
  }
6413
6564
  if (effectiveType === "ga") {
6414
- return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span>` + (quantity > 1 ? `<span class="fld mid"><span class="sl-chip-eb">Tickets</span><span class="val">${quantity}</span></span>` : "") + `</div>`;
6565
+ return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span>` + (quantity > 1 ? `<span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.tickets", "Tickets")}</span><span class="val">${quantity}</span></span>` : "") + `</div>`;
6415
6566
  }
6416
6567
  if (effectiveType === "booth") {
6417
- return `<div class="sl-chip-id">` + (d?.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">Section</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span></div>`;
6568
+ return `<div class="sl-chip-id">` + (d?.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.section", "Section")}</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span></div>`;
6418
6569
  }
6419
6570
  if (!d?.sectionLabel && !d?.rowLabel && !d?.seatNumber) {
6420
- return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">Seat</span><span class="val">${esc(buyerName)}</span></span></div>`;
6571
+ return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.seat", "Seat")}</span><span class="val">${esc(buyerName)}</span></span></div>`;
6421
6572
  }
6422
- return `<div class="sl-chip-id">` + (d.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">Section</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + (d.rowLabel ? `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(this.rowShort(d))}</span></span>` : "") + (d.seatNumber ? `<span class="fld mid"><span class="sl-chip-eb">Seat</span><span class="val">${esc(d.seatNumber)}</span></span>` : "") + `</div>`;
6573
+ return `<div class="sl-chip-id">` + (d.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.section", "Section")}</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + (d.rowLabel ? `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(this.rowShort(d))}</span></span>` : "") + (d.seatNumber ? `<span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.seat", "Seat")}</span><span class="val">${esc(d.seatNumber)}</span></span>` : "") + `</div>`;
6423
6574
  };
6424
6575
  const iconRail = (rmAria, viewLabel) => `<div class="sl-chip-rail"><button type="button" class="rm" aria-label="${rmAria}"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>` + (viewLabel ? `<button type="button" class="view" data-view-label="${viewLabel}" aria-label="${(0, import_core2.t)("picker.viewFromSeat", { label: viewLabel })}"><svg viewBox="0 0 24 24"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg></button>` : "") + `</div>`;
6425
6576
  for (const item of heldItems) {
@@ -6431,7 +6582,7 @@ var SeatPicker = class _SeatPicker {
6431
6582
  const table = item.objectType === "table" ? this.controller.tableSelection(item.label) : null;
6432
6583
  const canView2 = this.seatViewEnabled() && !!heldSeat && item.objectType !== "table";
6433
6584
  parts.push(
6434
- `<div class="sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-held="${encodeURIComponent(item.label)}"${heldSeat ? ` data-locate="${heldSeat.id}"` : ""}><div class="sl-chip-main">` + idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? void 0) + `<div class="sl-chip-sub"><span class="sl-ticket-state held" aria-label="Held for you" title="Held for you"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></span><span class="cat">${cat?.label ?? item.categoryKey}${tierName ? ` \xB7 ${tierName}` : ""}</span>` + (table?.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(item.label)}">${item.quantity ?? 1} guests \xB7 Edit</button>` : "") + this.wheelchairChipMarker(heldSeat?.wheelchairSpaceType) + this.commercialChipMarker(heldSeat?.commercial) + `<span class="amt">${this.money(this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1))}</span></div></div>` + iconRail(`Remove held ticket ${item.label}`, canView2 ? item.label : null) + `</div>`
6585
+ `<div class="sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-held="${encodeURIComponent(item.label)}"${heldSeat ? ` data-locate="${heldSeat.id}"` : ""}><div class="sl-chip-main">` + idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? void 0) + `<div class="sl-chip-sub"><span class="sl-ticket-state held" aria-label="${this.tf("picker.heldForYou", "Held for you")}" title="${this.tf("picker.heldForYou", "Held for you")}"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></span><span class="cat">${cat?.label ?? item.categoryKey}${tierName ? ` \xB7 ${tierName}` : ""}</span>` + (table?.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(item.label)}">${(0, import_core2.t)("picker.guestsCountEdit", { count: item.quantity ?? 1 })}</button>` : "") + this.wheelchairChipMarker(heldSeat?.wheelchairSpaceType) + this.commercialChipMarker(heldSeat?.commercial) + `<span class="amt">${this.money(this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1))}</span></div></div>` + iconRail((0, import_core2.t)("picker.removeHeldTicketLabel", { label: item.label }), canView2 ? item.label : null) + `</div>`
6435
6586
  );
6436
6587
  }
6437
6588
  const heldLabels = new Set(heldItems.map((item) => item.label));
@@ -6442,13 +6593,18 @@ var SeatPicker = class _SeatPicker {
6442
6593
  const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);
6443
6594
  const tierSelect = s.tiers && s.tiers.length ? `<select class="tier" data-tier="${s.id}" aria-label="${(0, import_core2.t)("picker.ticketTierFor", { label: s.label })}">` + s.tiers.map((ti) => `<option value="${ti.id}"${ti.id === s.tierId ? " selected" : ""}>${ti.name} \xB7 ${this.money(this.paidPrice(s.categoryKey, ti.id, ti.price))}</option>`).join("") + `</select>` : "";
6444
6595
  parts.push(
6445
- `<div class="sl-chip${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-seat="${s.id}" data-locate="${s.id}"><div class="sl-chip-main">` + idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) + `<div class="sl-chip-sub"><span class="sl-ticket-state" aria-label="Selected" title="Selected"><svg viewBox="0 0 24 24"><path d="M5 12l4 4L19 6"/></svg></span><span class="cat">${cat?.label ?? s.categoryKey}</span>` + (s.objectType === "table" && s.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(s.label)}">${s.quantity ?? 1} guests \xB7 Edit</button>` : "") + `${this.wheelchairChipMarker(s.wheelchairSpaceType)}${this.commercialChipMarker(s.commercial)}${tierSelect}<span class="amt">${this.money(this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1))}</span></div></div>` + iconRail(`Remove ${s.label}`, canView && s.objectType !== "table" ? s.label : null) + `</div>`
6596
+ `<div class="sl-chip${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-seat="${s.id}" data-locate="${s.id}"><div class="sl-chip-main">` + idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) + `<div class="sl-chip-sub"><span class="sl-ticket-state" aria-label="${this.tf("picker.selected", "Selected")}" title="${this.tf("picker.selected", "Selected")}"><svg viewBox="0 0 24 24"><path d="M5 12l4 4L19 6"/></svg></span><span class="cat">${cat?.label ?? s.categoryKey}</span>` + (s.objectType === "table" && s.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(s.label)}">${(0, import_core2.t)("picker.guestsCountEdit", { count: s.quantity ?? 1 })}</button>` : "") + `${this.wheelchairChipMarker(s.wheelchairSpaceType)}${this.commercialChipMarker(s.commercial)}${tierSelect}<span class="amt">${this.money(this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1))}</span></div></div>` + iconRail((0, import_core2.t)("picker.removeSeatLabel", { label: s.label }), canView && s.objectType !== "table" ? s.label : null) + `</div>`
6446
6597
  );
6447
6598
  }
6448
6599
  for (const area of gaAreas) {
6449
6600
  const qty = this.gaQty.get(area.id) ?? 0;
6450
6601
  parts.push(
6451
- `<div class="sl-ga" data-ga="${area.id}"><div class="sl-ga-info"><div class="sl-ga-name">${area.displayLabel ?? area.label}</div><div class="sl-ga-sub">${area.displayType ?? "General admission"} \xB7 ${this.money(this.paidPrice(area.categoryKey, null, area.price))} \xB7 ${area.available} left</div></div><div class="sl-ga-qty"><button type="button" data-d="-1" aria-label="Fewer">\u2212</button><span>${qty}</span><button type="button" data-d="1" aria-label="More">+</button></div></div>`
6602
+ `<div class="sl-ga" data-ga="${area.id}"><div class="sl-ga-info"><div class="sl-ga-name">${area.displayLabel ?? area.label}</div><div class="sl-ga-sub">${area.displayType ?? this.tf("picker.generalAdmission", "General admission")} \xB7 ${this.money(this.paidPrice(area.categoryKey, null, area.price))} \xB7 ${(0, import_core2.tCount)("picker.leftCount", area.available)}</div></div><div class="sl-ga-qty"><button type="button" data-d="-1" aria-label="${this.tf("picker.fewer", "Fewer")}">\u2212</button><span>${qty}</span><button type="button" data-d="1" aria-label="${this.tf("picker.more", "More")}">+</button></div></div>`
6603
+ );
6604
+ }
6605
+ if (!this.salesClosed && !this.hold && !noPicks && !this.baReopen && !this.bestAvailableBusy && !this.bestAvailableConfirm) {
6606
+ parts.push(
6607
+ `<button type="button" class="sl-ba-reopen" data-ba-reopen><span aria-hidden="true">\u2726</span>${this.tf("picker.findTogetherInstead", "Find seats together instead")}</button>`
6452
6608
  );
6453
6609
  }
6454
6610
  this.els.tray.innerHTML = parts.join("");
@@ -6483,6 +6639,16 @@ var SeatPicker = class _SeatPicker {
6483
6639
  this.syncTray();
6484
6640
  this.els.tray.querySelector(".sl-ba-go")?.focus();
6485
6641
  });
6642
+ this.els.tray.querySelector("[data-ba-reopen]")?.addEventListener("click", () => {
6643
+ this.baReopen = true;
6644
+ this.syncTray();
6645
+ this.els.tray.querySelector(".sl-ba-go")?.focus();
6646
+ });
6647
+ this.els.tray.querySelector("[data-ba-close]")?.addEventListener("click", () => {
6648
+ this.baReopen = false;
6649
+ this.syncTray();
6650
+ this.els.tray.querySelector("[data-ba-reopen]")?.focus();
6651
+ });
6486
6652
  this.els.tray.querySelector("[data-ba-replace]")?.addEventListener("click", () => {
6487
6653
  this.bestAvailableConfirm = false;
6488
6654
  void this.bestAvailable(this.baQty, this.baCat || void 0, { preferPremium: this.baPremium, zoneId: this.baZone || void 0 });
@@ -6495,15 +6661,15 @@ var SeatPicker = class _SeatPicker {
6495
6661
  return;
6496
6662
  }
6497
6663
  const id = chip.dataset.seat;
6498
- const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? "Seat";
6664
+ const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? this.tf("picker.seat", "Seat");
6499
6665
  const remove = () => {
6500
6666
  this.controller.deselect([id]);
6501
- this.toast(`${label} removed.`, "neutral", {
6502
- label: "Undo",
6667
+ this.toast((0, import_core2.t)("picker.labelRemoved", { label }), "neutral", {
6668
+ label: this.tf("picker.undo", "Undo"),
6503
6669
  onClick: () => {
6504
6670
  const restored = this.controller.select([id]);
6505
6671
  this.toast(
6506
- restored.length ? `${label} restored.` : `${label} is no longer available.`,
6672
+ restored.length ? (0, import_core2.t)("picker.labelRestored", { label }) : (0, import_core2.t)("picker.labelNoLongerAvailable", { label }),
6507
6673
  restored.length ? "success" : "warning"
6508
6674
  );
6509
6675
  }
@@ -6575,31 +6741,31 @@ var SeatPicker = class _SeatPicker {
6575
6741
  const pendingCount = this.pendingSelectionCount();
6576
6742
  const previousCount = this.lastTrayCount;
6577
6743
  const previousTotal = this.lastTrayTotal;
6578
- this.els.count.textContent = count ? `${count} ${count === 1 ? "ticket" : "tickets"}` : "No seats selected";
6744
+ this.els.count.textContent = count ? (0, import_core2.tCount)("picker.ticketsCount", count) : this.tf("picker.noSeatsSelected", "No seats selected");
6579
6745
  this.els.total.textContent = count ? this.money(total) : "";
6580
6746
  this.root?.setAttribute("data-has-selection", String(count > 0));
6581
6747
  this.root?.setAttribute(
6582
6748
  "data-ba-active",
6583
- String(this.bestAvailableConfirm || this.bestAvailableBusy)
6749
+ String(this.bestAvailableConfirm || this.bestAvailableBusy || this.baReopen)
6584
6750
  );
6585
6751
  this.els.foot?.classList.toggle("empty", count === 0);
6586
6752
  if (this.els.seatSummary) {
6587
- this.els.seatSummary.textContent = count ? `${count} selected` : "";
6753
+ this.els.seatSummary.textContent = count ? (0, import_core2.tCount)("picker.seatsSelectedCount", count) : "";
6588
6754
  }
6589
6755
  this.syncCta(count, pendingCount);
6590
6756
  if (this.hold) {
6591
6757
  const securedCount = heldCount || this.hold.seats?.length || 0;
6592
6758
  if (this.els.holdTitle) {
6593
- this.els.holdTitle.textContent = `${securedCount} secured`;
6759
+ this.els.holdTitle.textContent = (0, import_core2.t)("picker.securedCount", { count: securedCount });
6594
6760
  }
6595
6761
  if (this.els.holdCopy) {
6596
6762
  this.holdCopyPending = pendingCount > 0;
6597
- this.els.holdCopy.textContent = pendingCount ? `${pendingCount} more selected` : this.holdReassuranceText();
6763
+ this.els.holdCopy.textContent = pendingCount ? (0, import_core2.t)("picker.moreSelectedCount", { count: pendingCount }) : this.holdReassuranceText();
6598
6764
  }
6599
6765
  const change = this.els.holdChange;
6600
6766
  if (change) {
6601
6767
  change.disabled = this.releasingHold;
6602
- change.textContent = this.releasingHold ? "Releasing\u2026" : "Change";
6768
+ change.textContent = this.releasingHold ? this.tf("picker.releasingEllipsis", "Releasing\u2026") : this.tf("picker.change", "Change");
6603
6769
  }
6604
6770
  }
6605
6771
  if (count !== previousCount) this.animateOnce(this.els.count, "sl-value-pop", 380);
@@ -6624,21 +6790,21 @@ var SeatPicker = class _SeatPicker {
6624
6790
  renderPeek(count, total, pendingCount) {
6625
6791
  if (!this.els.peek) return;
6626
6792
  if (count && this.ctaPhase === "holding") {
6627
- this.els.peek.innerHTML = `<span>Securing your seats\u2026</span>`;
6793
+ this.els.peek.innerHTML = `<span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}</span>`;
6628
6794
  return;
6629
6795
  }
6630
6796
  if (count && this.ctaPhase === "checkout") {
6631
- this.els.peek.innerHTML = `<span>\u2713 ${count} ${count === 1 ? "ticket" : "tickets"} secured \xB7 ${this.money(total)} \u2014 you won\u2019t be charged yet</span>`;
6797
+ this.els.peek.innerHTML = `<span>${(0, import_core2.t)("picker.peekSecured", { count, total: this.money(total) })}</span>`;
6632
6798
  return;
6633
6799
  }
6634
6800
  if (count) {
6635
- const holding = !!this.hold && !pendingCount;
6636
- 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>`;
6801
+ const toCheckout = !!this.hold;
6802
+ this.els.peek.innerHTML = `<span>${(0, import_core2.tCount)("picker.peekTicketsTotal", count, { total: this.money(total) })}</span><button type="button" class="go sl-sheet-go" data-act="${toCheckout ? "checkout" : "open"}">${this.hold ? pendingCount ? this.tf("picker.secureMore", "Secure more") : this.tf("picker.continue", "Continue") : this.tf("picker.review", "Review")}</button>`;
6637
6803
  } else if (this.salesClosed) {
6638
6804
  this.els.peek.innerHTML = `<span>${this.tf("picker.salesClosedPill", "Sales are closed")}</span>`;
6639
6805
  } else {
6640
6806
  const prices = (this.controller.doc?.categories ?? []).map((c) => this.catPrice(c)).filter((p) => p != null);
6641
- 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>`;
6807
+ this.els.peek.innerHTML = (prices.length ? `<span>${(0, import_core2.t)("picker.peekFromPrice", { price: this.money(Math.min(...prices)) })}</span>` : `<span>${this.tf("picker.pickYourSeats", "Pick your seats")}</span>`) + `<button type="button" class="go sl-sheet-go" data-act="open">${this.tf("picker.bestSeatsStar", "\u2726 Best seats")}</button>`;
6642
6808
  }
6643
6809
  }
6644
6810
  async removeHeldLabel(label, chip) {
@@ -6651,7 +6817,7 @@ var SeatPicker = class _SeatPicker {
6651
6817
  const preserveAcrossNavigation = this.handedOff;
6652
6818
  const released = await this.controller.releaseLabels([label]);
6653
6819
  if (!released) {
6654
- this.toast(`Couldn't remove ${label}. Your hold is unchanged.`, "error");
6820
+ this.toast((0, import_core2.t)("picker.couldNotRemoveLabel", { label }), "error");
6655
6821
  return false;
6656
6822
  }
6657
6823
  const remaining = this.controller.currentHold();
@@ -6667,7 +6833,7 @@ var SeatPicker = class _SeatPicker {
6667
6833
  }
6668
6834
  this.syncTray();
6669
6835
  this.emitHoldChange();
6670
- this.toast(`${label} removed from your hold.`, "success");
6836
+ this.toast((0, import_core2.t)("picker.labelRemovedFromHold", { label }), "success");
6671
6837
  return true;
6672
6838
  } finally {
6673
6839
  this.releasingLabels.delete(label);
@@ -6681,23 +6847,23 @@ var SeatPicker = class _SeatPicker {
6681
6847
  const button = this.els.holdChange;
6682
6848
  if (button) {
6683
6849
  button.disabled = true;
6684
- button.textContent = "Releasing\u2026";
6850
+ button.textContent = this.tf("picker.releasingEllipsis", "Releasing\u2026");
6685
6851
  }
6686
6852
  try {
6687
6853
  await this.release();
6688
- if (!this.hold) this.toast("Held tickets released. Choose your new seats.", "success");
6854
+ if (!this.hold) this.toast(this.tf("picker.heldTicketsReleased", "Held tickets released. Choose your new seats."), "success");
6689
6855
  } finally {
6690
6856
  this.releasingHold = false;
6691
6857
  if (button?.isConnected) {
6692
6858
  button.disabled = false;
6693
- button.textContent = "Change";
6859
+ button.textContent = this.tf("picker.change", "Change");
6694
6860
  }
6695
6861
  }
6696
6862
  }
6697
6863
  async handleCta() {
6698
6864
  if (this.salesClosed) return;
6699
6865
  if (this.totalTicketCount() > this.maxTickets) {
6700
- this.toast(`Remove tickets until your order has ${this.maxTickets} or fewer.`, "warning");
6866
+ this.toast((0, import_core2.t)("picker.removeTicketsUntilOrFewer", { count: this.maxTickets }), "warning");
6701
6867
  return;
6702
6868
  }
6703
6869
  const committed = this.committedSelection();
@@ -6723,7 +6889,7 @@ var SeatPicker = class _SeatPicker {
6723
6889
  hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;
6724
6890
  }
6725
6891
  if (!hold) {
6726
- this.toast("One or more seats were just taken. Please pick again.", "error");
6892
+ this.toast(this.tf("picker.seatsJustTaken", "One or more seats were just taken. Please pick again."), "error");
6727
6893
  this.setCtaPhase("idle");
6728
6894
  this.syncTray();
6729
6895
  return;
@@ -6740,7 +6906,7 @@ var SeatPicker = class _SeatPicker {
6740
6906
  const problem = err;
6741
6907
  const labels = (problem.conflicts ?? []).map((conflict) => conflict.label).filter(Boolean).slice(0, 3);
6742
6908
  if (problem.reason === "event_closed") this.setSalesClosed(true);
6743
- const message = problem.reason === "event_closed" ? "Seat sales have closed for this event." : labels.length ? `${labels.join(", ")} ${labels.length === 1 ? "is" : "are"} no longer available. Choose another ${labels.length === 1 ? "seat" : "group"}.` : "One or more seats were just taken. Please pick again.";
6909
+ const message = problem.reason === "event_closed" ? this.tf("picker.seatSalesClosedForEvent", "Seat sales have closed for this event.") : labels.length ? labels.length === 1 ? (0, import_core2.t)("picker.labelsNoLongerAvailable.one", { labels: labels.join(", ") }) : (0, import_core2.t)("picker.labelsNoLongerAvailable.other", { labels: labels.join(", ") }) : this.tf("picker.seatsJustTaken", "One or more seats were just taken. Please pick again.");
6744
6910
  this.toast(message, "error");
6745
6911
  this.setCtaPhase("idle");
6746
6912
  } finally {
@@ -6754,14 +6920,14 @@ var SeatPicker = class _SeatPicker {
6754
6920
  const ms = Math.max(0, this.holdExpiresAt - Date.now());
6755
6921
  const m = Math.floor(ms / 6e4);
6756
6922
  const s = String(Math.floor(ms % 6e4 / 1e3)).padStart(2, "0");
6757
- return `Yours for ${m}:${s} \u2014 you won\u2019t be charged yet.`;
6923
+ return (0, import_core2.t)("picker.holdReassurance", { time: `${m}:${s}` });
6758
6924
  }
6759
6925
  startHoldTimer(expiresAt) {
6760
6926
  this.stopHoldTimer();
6761
6927
  this.holdExpiresAt = expiresAt;
6762
6928
  if (this.hold) this.rememberHold(this.hold);
6763
6929
  const pill = this.els.hold;
6764
- pill.innerHTML = '<span class="sl-hold-dot" aria-hidden="true"></span><span>Held</span><span class="sl-hold-time" data-ref="holdTime"></span>';
6930
+ pill.innerHTML = `<span class="sl-hold-dot" aria-hidden="true"></span><span>${this.tf("picker.held", "Held")}</span><span class="sl-hold-time" data-ref="holdTime"></span>`;
6765
6931
  const time = pill.querySelector('[data-ref="holdTime"]');
6766
6932
  this.els.holdNote?.classList.add("on");
6767
6933
  const tick = () => {
@@ -6794,7 +6960,7 @@ var SeatPicker = class _SeatPicker {
6794
6960
  const totalSecs = Math.ceil(ms / 1e3);
6795
6961
  const m = Math.floor(totalSecs / 60);
6796
6962
  const s = String(totalSecs % 60).padStart(2, "0");
6797
- this.els.extendTxt.innerHTML = `Your seats are held for <b>${m}:${s}</b>. Need more time?`;
6963
+ this.els.extendTxt.innerHTML = (0, import_core2.t)("picker.seatsHeldForNeedMoreTime", { time: `${m}:${s}` });
6798
6964
  this.extendEl.classList.add("on");
6799
6965
  } else {
6800
6966
  this.extendEl.classList.remove("on");
@@ -6804,7 +6970,7 @@ var SeatPicker = class _SeatPicker {
6804
6970
  const btn = this.els.extendBtn;
6805
6971
  btn.disabled = true;
6806
6972
  const prev = btn.textContent;
6807
- btn.textContent = "Adding\u2026";
6973
+ btn.textContent = this.tf("picker.addingEllipsis", "Adding\u2026");
6808
6974
  try {
6809
6975
  const h = await this.controller.extendHold(this.opts.holdTtlMs);
6810
6976
  if (h) {
@@ -6813,13 +6979,13 @@ var SeatPicker = class _SeatPicker {
6813
6979
  this.extendEl?.classList.remove("on");
6814
6980
  this.rememberHold(this.hold);
6815
6981
  this.emitHoldChange();
6816
- this.toast("More time added \u2014 your seats are still held.", "success");
6982
+ this.toast(this.tf("picker.moreTimeAdded", "More time added \u2014 your seats are still held."), "success");
6817
6983
  } else {
6818
- this.toast("Couldn't add more time \u2014 please head to checkout now.", "warning");
6984
+ this.toast(this.tf("picker.couldNotAddMoreTime", "Couldn't add more time \u2014 please head to checkout now."), "warning");
6819
6985
  }
6820
6986
  } catch (err) {
6821
6987
  this.opts.onError?.(err);
6822
- this.toast("Couldn't add more time \u2014 please head to checkout now.", "warning");
6988
+ this.toast(this.tf("picker.couldNotAddMoreTime", "Couldn't add more time \u2014 please head to checkout now."), "warning");
6823
6989
  } finally {
6824
6990
  btn.disabled = false;
6825
6991
  btn.textContent = prev;
@@ -6846,7 +7012,7 @@ var SeatPicker = class _SeatPicker {
6846
7012
  this.forgetHold();
6847
7013
  const n = handoff.lineItems.reduce((sum, i) => sum + i.quantity, 0);
6848
7014
  if (this.els.bookedSub) {
6849
- this.els.bookedSub.innerHTML = `<span class="sl-booked-seats">${n} ${n === 1 ? "ticket" : "tickets"}</span> confirmed. A confirmation is on its way.`;
7015
+ this.els.bookedSub.innerHTML = `<span class="sl-booked-seats">${(0, import_core2.tCount)("picker.ticketsCount", n)}</span> ${this.tf("picker.confirmedAndOnWay", "confirmed. A confirmation is on its way.")}`;
6850
7016
  }
6851
7017
  this.bookedEl?.classList.add("on");
6852
7018
  this.opts.onBooked?.(handoff);
@@ -6928,7 +7094,7 @@ var SeatPicker = class _SeatPicker {
6928
7094
  ({ mountCheckout: mountCheckout2 } = await loadHostedCheckout());
6929
7095
  } catch (err) {
6930
7096
  this.opts.onError?.(err);
6931
- this.toast("Checkout could not be opened. Your seats are still held \u2014 please try again.", "error");
7097
+ this.toast(this.tf("picker.checkoutCouldNotBeOpened", "Checkout could not be opened. Your seats are still held \u2014 please try again."), "error");
6932
7098
  this.setCtaPhase("idle");
6933
7099
  return;
6934
7100
  }
@@ -7043,9 +7209,9 @@ var SeatPicker = class _SeatPicker {
7043
7209
  rowTypeWord(details) {
7044
7210
  const authored = details?.displayType?.trim() || details?.rowType?.trim();
7045
7211
  if (authored) return authored;
7046
- if (details?.objectType === "table") return "Table";
7047
- if (details?.objectType === "booth") return "Booth";
7048
- return "Row";
7212
+ if (details?.objectType === "table") return this.tf("picker.table", "Table");
7213
+ if (details?.objectType === "booth") return this.tf("picker.booth", "Booth");
7214
+ return this.tf("picker.row", "Row");
7049
7215
  }
7050
7216
  rowShort(details) {
7051
7217
  const row = details?.rowLabel;
@@ -7068,7 +7234,7 @@ var SeatPicker = class _SeatPicker {
7068
7234
  const isGroupedTable = details.objectType === "table" && !!details.bookingMode;
7069
7235
  const isBooth = details.objectType === "booth";
7070
7236
  const hasLoc = details.sectionLabel || details.rowLabel || details.seatNumber;
7071
- const grid = isGroupedTable ? `<div class="sl-tip-grid"><div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div><div class="sl-tip-field"><span class="sl-tip-key">Guests</span><span class="sl-tip-val">${details.bookingMode === "variable" ? `${details.minOccupancy}\u2013${details.maxOccupancy}` : details.capacity}</span></div></div>` : isBooth ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">Section</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div></div>` : hasLoc ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">Section</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + (details.rowLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(this.rowShort(details))}</span></div>` : "") + (details.seatNumber ? `<div class="sl-tip-field"><span class="sl-tip-key">Seat</span><span class="sl-tip-val">${esc(details.seatNumber)}</span></div>` : "") + `</div>` : `<div class="sl-tip-grid one"><div class="sl-tip-field"><span class="sl-tip-key">Seat</span><span class="sl-tip-val">${esc(details.displayLabel ?? details.label)}</span></div></div>`;
7237
+ const grid = isGroupedTable ? `<div class="sl-tip-grid"><div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div><div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.guests", "Guests")}</span><span class="sl-tip-val">${details.bookingMode === "variable" ? `${details.minOccupancy}\u2013${details.maxOccupancy}` : details.capacity}</span></div></div>` : isBooth ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.section", "Section")}</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div></div>` : hasLoc ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.section", "Section")}</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + (details.rowLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(this.rowShort(details))}</span></div>` : "") + (details.seatNumber ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-tip-val">${esc(details.seatNumber)}</span></div>` : "") + `</div>` : `<div class="sl-tip-grid one"><div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-tip-val">${esc(details.displayLabel ?? details.label)}</span></div></div>`;
7072
7238
  const statusLine = details.status === "free" ? "" : `<div class="sl-tip-status">${details.status === "held" ? (0, import_core2.t)("map.statusHeld") : (0, import_core2.t)("map.statusTaken")}</div>`;
7073
7239
  const limited = this.limitedViewLabel(details.commercial);
7074
7240
  const cxLine = limited ? `<div class="sl-tip-cx"><span class="g" aria-hidden="true">\u25D0</span>${esc(limited)}</div>` : "";
@@ -7359,7 +7525,7 @@ var SeatPicker = class _SeatPicker {
7359
7525
  const identity = details?.displayLabel ?? seat.displayLabel ?? seat.label;
7360
7526
  const section = details?.sectionLabel;
7361
7527
  const row = this.rowShort(details);
7362
- const location2 = [section, row ? `Row ${row}` : null, identity].filter(Boolean).join(" \xB7 ");
7528
+ const location2 = [section, row ? (0, import_core2.t)("picker.rowLabel", { label: row }) : null, identity].filter(Boolean).join(" \xB7 ");
7363
7529
  const copy = status === "held" ? {
7364
7530
  title: this.tf("picker.temporarilyHeld", "Temporarily held"),
7365
7531
  message: this.tf("picker.heldSeatExplanation", "Another buyer is holding this seat. It may become available again.")
@@ -7455,7 +7621,7 @@ var SeatPicker = class _SeatPicker {
7455
7621
  chip = document.createElement("div");
7456
7622
  chip.className = "sl-view3d-compare-saved";
7457
7623
  chip.setAttribute("role", "group");
7458
- chip.setAttribute("aria-label", "Saved seat comparison");
7624
+ chip.setAttribute("aria-label", this.tf("picker.savedSeatComparison", "Saved seat comparison"));
7459
7625
  const main2 = document.createElement("button");
7460
7626
  main2.type = "button";
7461
7627
  main2.className = "main";
@@ -7467,7 +7633,7 @@ var SeatPicker = class _SeatPicker {
7467
7633
  clear.type = "button";
7468
7634
  clear.className = "clear";
7469
7635
  clear.textContent = "\xD7";
7470
- clear.setAttribute("aria-label", "Clear saved seat comparison");
7636
+ clear.setAttribute("aria-label", this.tf("picker.clearSavedSeatComparison", "Clear saved seat comparison"));
7471
7637
  clear.addEventListener("click", () => this.clearView3dComparison());
7472
7638
  chip.append(main2, clear);
7473
7639
  overlay.appendChild(chip);
@@ -7476,8 +7642,8 @@ var SeatPicker = class _SeatPicker {
7476
7642
  const count = this.view3dCompareSeatIds.length;
7477
7643
  const main = chip.querySelector(".main");
7478
7644
  if (main) {
7479
- main.textContent = count > 1 ? `Compare ${count}` : "1 seat saved";
7480
- main.setAttribute("aria-label", count > 1 ? `Open comparison of ${count} seats` : "One seat saved; choose another to compare");
7645
+ main.textContent = count > 1 ? (0, import_core2.t)("picker.compareCount", { count }) : this.tf("picker.oneSeatSaved", "1 seat saved");
7646
+ main.setAttribute("aria-label", count > 1 ? (0, import_core2.t)("picker.openComparisonOfSeats", { count }) : this.tf("picker.oneSeatSavedChooseAnother", "One seat saved; choose another to compare"));
7481
7647
  }
7482
7648
  }
7483
7649
  view3dComparisonSnapshot(seatId) {
@@ -7754,8 +7920,7 @@ var SeatPicker = class _SeatPicker {
7754
7920
  const wantFloors = floors.length > 1;
7755
7921
  const wantZones = zones.length > 1;
7756
7922
  const wantSections = sections.length > 1;
7757
- const wantLocator = allSections.length > 0 && handle.rows().length > 0;
7758
- if (!wantFloors && !wantZones && !wantSections && !wantLocator) return;
7923
+ if (!wantFloors && !wantZones && !wantSections) return;
7759
7924
  const nav = document.createElement("div");
7760
7925
  nav.className = "sl-view3d-nav";
7761
7926
  const finderToggle = document.createElement("button");
@@ -7765,7 +7930,7 @@ var SeatPicker = class _SeatPicker {
7765
7930
  const setFinderOpen = (open) => {
7766
7931
  nav.classList.toggle("is-open", open);
7767
7932
  finderToggle.setAttribute("aria-expanded", String(open));
7768
- finderToggle.textContent = open ? "Close seat finder" : "Find a seat";
7933
+ finderToggle.textContent = open ? this.tf("picker.closeVenueNav", "Close") : wantFloors && (wantZones || wantSections) ? this.tf("picker.levelsAndAreas", "Levels & areas") : wantFloors ? this.tf("picker.levels", "Levels") : this.tf("picker.areas", "Areas");
7769
7934
  };
7770
7935
  finderToggle.addEventListener("click", () => setFinderOpen(!nav.classList.contains("is-open")));
7771
7936
  nav.addEventListener("keydown", (event) => {
@@ -7802,7 +7967,7 @@ var SeatPicker = class _SeatPicker {
7802
7967
  row.appendChild(b);
7803
7968
  };
7804
7969
  add(this.tf("picker.allLevels", "All levels"), null);
7805
- for (const f of floors) add(f.label || `Level ${f.index + 1}`, f.index);
7970
+ for (const f of floors) add(f.label || (0, import_core2.t)("picker.levelNumber", { number: f.index + 1 }), f.index);
7806
7971
  nav.appendChild(row);
7807
7972
  }
7808
7973
  if (wantZones || wantSections) {
@@ -7845,86 +8010,6 @@ var SeatPicker = class _SeatPicker {
7845
8010
  }
7846
8011
  nav.appendChild(row);
7847
8012
  }
7848
- if (wantLocator) {
7849
- const locator = document.createElement("div");
7850
- locator.className = "sl-view3d-locator";
7851
- locator.setAttribute("role", "group");
7852
- locator.setAttribute("aria-label", "Find an exact seat in 3D");
7853
- const sectionSelect = document.createElement("select");
7854
- sectionSelect.setAttribute("aria-label", "Choose section in 3D");
7855
- const rowSelect = document.createElement("select");
7856
- rowSelect.setAttribute("aria-label", "Choose row in 3D");
7857
- const seatSelect = document.createElement("select");
7858
- seatSelect.setAttribute("aria-label", "Choose seat in 3D");
7859
- const view = document.createElement("button");
7860
- view.type = "button";
7861
- view.textContent = "Inspect seat";
7862
- view.disabled = true;
7863
- const fill = (select, placeholder, entries) => {
7864
- select.replaceChildren();
7865
- const first = document.createElement("option");
7866
- first.value = "";
7867
- first.textContent = placeholder;
7868
- select.appendChild(first);
7869
- for (const entry of entries) {
7870
- const option = document.createElement("option");
7871
- option.value = entry.id;
7872
- option.textContent = entry.label;
7873
- select.appendChild(option);
7874
- }
7875
- select.value = "";
7876
- };
7877
- fill(sectionSelect, "1. Section", allSections.map((section) => ({
7878
- id: section.id,
7879
- label: `${section.label} \xB7 ${section.seatCount.toLocaleString()} seats`
7880
- })));
7881
- fill(rowSelect, "2. Row", []);
7882
- fill(seatSelect, "3. Seat", []);
7883
- rowSelect.disabled = true;
7884
- seatSelect.disabled = true;
7885
- sectionSelect.addEventListener("change", () => {
7886
- const sectionId = sectionSelect.value;
7887
- view.disabled = true;
7888
- fill(seatSelect, "3. Seat", []);
7889
- seatSelect.disabled = true;
7890
- if (!sectionId || !handle.focusSection(sectionId)) {
7891
- fill(rowSelect, "2. Row", []);
7892
- rowSelect.disabled = true;
7893
- return;
7894
- }
7895
- const rows = handle.rows(sectionId);
7896
- fill(rowSelect, "2. Row", rows.map((row) => ({
7897
- id: row.id,
7898
- label: `${row.label} \xB7 ${row.seatCount} seats`
7899
- })));
7900
- rowSelect.disabled = rows.length === 0;
7901
- });
7902
- rowSelect.addEventListener("change", () => {
7903
- const rowId = rowSelect.value;
7904
- view.disabled = true;
7905
- if (!rowId || !handle.focusRow(rowId)) {
7906
- fill(seatSelect, "3. Seat", []);
7907
- seatSelect.disabled = true;
7908
- return;
7909
- }
7910
- const seats = handle.seatsInRow(rowId);
7911
- fill(seatSelect, "3. Seat", seats);
7912
- seatSelect.disabled = seats.length === 0;
7913
- });
7914
- seatSelect.addEventListener("change", () => {
7915
- const seatId = seatSelect.value;
7916
- view.disabled = !seatId;
7917
- });
7918
- view.addEventListener("click", () => {
7919
- const seatId = seatSelect.value;
7920
- if (seatId) {
7921
- setFinderOpen(false);
7922
- this.onView3dSeatPick(seatId);
7923
- }
7924
- });
7925
- locator.append(sectionSelect, rowSelect, seatSelect, view);
7926
- nav.appendChild(locator);
7927
- }
7928
8013
  overlay.appendChild(nav);
7929
8014
  }
7930
8015
  async enter3d(flySeatId) {
@@ -7940,7 +8025,7 @@ var SeatPicker = class _SeatPicker {
7940
8025
  const overlay = document.createElement("div");
7941
8026
  overlay.className = "sl-view3d";
7942
8027
  overlay.setAttribute("role", "group");
7943
- overlay.setAttribute("aria-label", "Interactive 3D venue view");
8028
+ overlay.setAttribute("aria-label", this.tf("picker.interactive3dVenueView", "Interactive 3D venue view"));
7944
8029
  const back = document.createElement("button");
7945
8030
  back.type = "button";
7946
8031
  back.className = "sl-view3d-back";
@@ -7966,7 +8051,7 @@ var SeatPicker = class _SeatPicker {
7966
8051
  fullscreen.type = "button";
7967
8052
  fullscreen.className = "sl-view3d-fs";
7968
8053
  fullscreen.textContent = "\u26F6";
7969
- fullscreen.setAttribute("aria-label", "Full screen");
8054
+ fullscreen.setAttribute("aria-label", this.tf("picker.fullScreen", "Full screen"));
7970
8055
  fullscreen.setAttribute("aria-pressed", String(!!document.fullscreenElement || this.fsFallback || this.framedFs));
7971
8056
  fullscreen.addEventListener("click", () => this.toggleFullscreen());
7972
8057
  overlay.appendChild(fullscreen);
@@ -8003,7 +8088,7 @@ var SeatPicker = class _SeatPicker {
8003
8088
  onSeatInspect: (id) => this.onView3dSeatPick(id),
8004
8089
  onSectionFocusChange: (sectionId) => {
8005
8090
  const select = overlay.querySelector(
8006
- 'select[aria-label="Choose section in 3D"]'
8091
+ 'select[data-locator="section"]'
8007
8092
  );
8008
8093
  const next = sectionId ?? "";
8009
8094
  if (!select || select.value === next) return;
@@ -8100,7 +8185,7 @@ var SeatPicker = class _SeatPicker {
8100
8185
  if (button) {
8101
8186
  button.disabled = true;
8102
8187
  button.classList.add("sl-busy");
8103
- button.innerHTML = '<span class="sl-ba-spin" aria-hidden="true"></span>Finding\u2026';
8188
+ button.innerHTML = `<span class="sl-ba-spin" aria-hidden="true"></span>${this.tf("picker.findingEllipsis", "Finding\u2026")}`;
8104
8189
  }
8105
8190
  try {
8106
8191
  const h = await this.controller.bestAvailable(qty, categoryKey, { ...opts, ttlMs: this.opts.holdTtlMs });
@@ -8122,7 +8207,7 @@ var SeatPicker = class _SeatPicker {
8122
8207
  } catch (err) {
8123
8208
  this.opts.onError?.(err);
8124
8209
  const reason = err?.reason;
8125
- const message = reason === "not_enough_together" ? `We couldn't find ${qty} seats together. Try fewer seats or another ticket type.` : reason === "sold_out" ? "That ticket type is sold out. Try another ticket type." : reason === "event_closed" ? "Seat sales have closed for this event." : "Those seats are no longer available. Try another quantity or ticket type.";
8210
+ const message = reason === "not_enough_together" ? (0, import_core2.t)("picker.couldNotFindSeatsTogether", { count: qty }) : reason === "sold_out" ? this.tf("picker.ticketTypeSoldOut", "That ticket type is sold out. Try another ticket type.") : reason === "event_closed" ? this.tf("picker.seatSalesClosedForEvent", "Seat sales have closed for this event.") : this.tf("picker.seatsNoLongerAvailableTryAnother", "Those seats are no longer available. Try another quantity or ticket type.");
8126
8211
  this.toast(message, "error");
8127
8212
  return null;
8128
8213
  } finally {
@@ -8151,7 +8236,7 @@ var SeatPicker = class _SeatPicker {
8151
8236
  }
8152
8237
  }
8153
8238
  if (!released) {
8154
- this.toast("Couldn't release your tickets. Your hold is unchanged.", "error");
8239
+ this.toast(this.tf("picker.couldNotReleaseTickets", "Couldn't release your tickets. Your hold is unchanged."), "error");
8155
8240
  return;
8156
8241
  }
8157
8242
  this.hold = null;