/* ============================================================================
   Seating Areas 2.0 — theme styles

   Architecture: _tasks/seating-areas-2.0-architecture.md §4
   Responsive layout: <880px stacked single column.
                     ≥880px two-column with persistent right-side map rail.
   StickyEventBar full-width across the top on both layouts.

   This file is additive over lib/base/. Theme-only conventions:
     - Sizing in px (never rem)
     - position: sticky, never position: fixed
     - All component selectors prefixed `.sa-`
============================================================================ */


/* Layout containers (page grid, panel, map, body-level caps, header/nav
   inner-max-width overrides) all moved to `lib/lib-overrides.css` and
   scoped under `main[data-show='panel+map']` per the design system pattern.
   No bespoke .sa-page / .sa-main / .sa-rail classes anymore. */

/* The flex parent of the rail's <rys-slider> still needs explicit
   min-width:0 so the slider can shrink below its intrinsic min-content
   width on mobile. (Without this, the slider's track pushes the parent
   wider than viewport → mobile browsers zoom out to fit.) */
.sa-rail-events { min-width: 0; }


/* ── Selected-event rectangle ─────────────────────────────────────────────
   Shown by SectionRailCtrl.onEventChanged when an event is active. Hides the
   chips + event-cards slider above; sits above the filter chips + map. Mirrors
   the esb pattern from te.1 (`.esb-selected`) — name + meta on the left,
   round × button on the right. */
/* Lives INSIDE .sa-rail-strip — the strip carries the translucent panel
   bg + blur, so the row itself is transparent. Standalone-card chrome
   (white bg, outline, shadow, outer margin) dropped accordingly. */
.sa-rail-selected {
   display: flex;
   align-items: center;
   padding: 8px 12px 8px 14px;
   color: var(--color-primary, #002448);
   min-height: 56px;
}

.sa-rail-selected[hidden] { display: none; }


.sa-rail-selected-inner {
   display: flex;
   align-items: center;
   width: 100%;
   gap: 12px;
   min-width: 0;
   max-width: 600px;
    background: white;
    border-radius: 999px;
    padding: 6px 12px;
    border: 1px solid #f1f1f1;   
}

/* Avatar slot — same 32x40 size + treatment as the event-strip cards and
   the picker rows so the visual identity stays consistent across surfaces. */
.sa-rail-selected-avatar {
   flex: 0 0 auto;
   width: 40px;
   height: 40px;
   display: flex;
   align-items: center;
   justify-content: center;
   overflow: hidden;
   border-radius: 4px;
}
.sa-rail-selected-avatar-img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
   border-radius: 999px;
}
/* MLB logos render transparent + contained (no grey loading bg). */
.sa-rail-selected-avatar-img.sa-rail-selected-avatar-mlb {
   background: transparent;
   object-fit: contain;
   border-radius: 0;
}
.sa-rail-selected-avatar:has(.sa-rail-selected-avatar-mlb) {
   background: transparent;
}
/* Non-image identifier (team-abbrev pill / sport-icon avatar via
   _cardIdentifier) sits centered in the same slot. */
.sa-rail-selected-avatar-icon {
   display: inline-flex;
   align-items: center;
   justify-content: center;
}

.sa-rail-selected-info {
   flex: 1;
   min-width: 0;
   display: flex;
   flex-direction: column;
   justify-content: center;
   cursor: pointer;
}

.sa-rail-selected-name {
   font-size: 14px;
   font-weight: 600;
   line-height: 1.25;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-rail-selected-meta {
   font-size: 12px;
   color: var(--text-low, #6b7280);
   line-height: 1.2;
   margin-top: 2px;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-rail-selected-clear {
   flex: 0 0 auto;
   width: 32px;
   height: 32px;
   border: none;
   background: transparent;
   border-radius: 50%;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   color: var(--text-medium, #4b5563);
   cursor: pointer;
   transition: background 0.12s ease, color 0.12s ease;
}

.sa-rail-selected-clear:hover {
   background: #ededed;
   color: var(--color-primary, #002448);
}

.sa-rail-selected-clear [data-is="icon"] {
   width: 18px;
   height: 18px;
}


/* Filter chips strip — supports two-tier: category chips on top,
   month chips below (when filtered to one category) */
.sa-rail-chips {
   display: flex;
   flex-direction: column;
   gap: 8px;
   padding: 8px 12px;
}

.sa-rail-chips[hidden] { display: none; }

/* Quantity-hint nudge inserted as a sibling of the rail-filter-chips
   strip (NOT a child — the strip carries data-list-rail and would
   factor any child into its track-positioning math). Hides on qty set
   (auto-apply or chip click) and on close-button (24h cooldown). The
   ::before pseudo is a small upward triangle that visually points at
   the quantity chip in the strip above. */
.sa-rail-qty-hint {
   position: relative;
   /* Parent (.sa-rail-strip) is flex-column with default align-items:
      stretch — children would full-width without this. `align-self:
      flex-start` breaks the stretch so the hint sizes to its content.
      max-width caps it on narrow screens. margin-top makes room for
      the triangle pseudo above. */
   display: inline-flex;
   align-self: flex-start;
   align-items: center;
   gap: 8px;
   margin: -6px 12px 0;
   padding: 6px 10px;
   max-width: calc(100% - 24px);
   border-radius: 8px;
   border-inline-start: 3px solid var(--color-primary, #002448);
   background: var(--color-05, rgba(0, 36, 72, 0.04));
   font-size: 12px;
   line-height: 1.35;
   color: var(--text-default);
}
/* Upward-pointing triangle ~100px in from the left edge, flush with the
   hint's top edge so the two read as a single connected callout. Color
   matches the hint background (NOT the accent border) so the arrow
   appears as a seamless extension of the hint upward toward the qty
   chip above. */
.sa-rail-qty-hint::before {
   content: "";
   position: absolute;
   /* `top: -7px` puts the triangle's bottom exactly at y=0 of the hint
      — sub-pixel rounding can leave a 1px gap on some DPRs. Bump down
      to -6px so the triangle base overlaps the hint by 1px → zero
      visible seam at any zoom level. */
   top: -6px;
   left: 100px;
   width: 0;
   height: 0;
   border-left: 7px solid transparent;
   border-right: 7px solid transparent;
   border-bottom: 7px solid var(--color-05, rgba(0, 36, 72, 0.04));
}
.sa-rail-qty-hint-body {
   flex: 1 1 auto;
   min-width: 0;
}
.sa-rail-qty-hint-body strong {
   display: inline-block;
   margin-inline-end: 4px;
   color: var(--color-primary, #002448);
}
.sa-rail-qty-hint-close {
   flex: 0 0 auto;
   border: 0;
   background: transparent;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
   font-size: 13px;
   line-height: 1;
   padding: 4px 6px;
   cursor: pointer;
   border-radius: 4px;
}
.sa-rail-qty-hint-close:hover {
   color: var(--color-primary, #002448);
   background: var(--color-10, rgba(0, 36, 72, 0.10));
}

/* Scroll behavior comes from list-rail.js (data-list-rail attribute on
   the row). The library injects its own flex + overflow rules on a
   `.list-rail-track` child it wraps the chips into; the row container
   itself stays a plain positioned block so list-rail's arrows can
   anchor to its edges. Defining display/overflow here would conflict
   with the track's scrolling. */
.sa-rail-chip-row {
   --list-rail-gap: 8px;
}

.sa-rail-chip-row-month .sa-rail-chip {
   font-size: 12px;
   padding: 4px 10px;
}

.sa-rail-chip-row-month .sa-rail-chip-count {
   font-size: 11px;
}

/* Meta filter row (Month / DOW / Opponent / More filters). Mixes the
   dismissible active-type chip (.sa-rail-chip) with dropdown chips
   (.sa-fchip — same chip style RailFilterChipsCtrl uses below). */
.sa-rail-chip-row-meta {
   align-items: center;
}

.sa-rail-chip-row-meta .sa-fchip [data-is="icon"] {
   margin-left: 2px;
   opacity: 0.7;
}

.sa-rail-chip {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   padding: 6px 14px;
   /* Height grows when the label wraps to a second line (open-ended
      event names like "Hot Wheels Monster Trucks Live Glow-N-Fire").
      `min-height` keeps single-line chips at the standard 40px so
      typical chip rows stay clean. */
   min-height: 40px;
   border: 1px solid var(--sa-border-soft);
   border-radius: 999px;
   background: #fff;
   font-size: 13px;
   cursor: pointer;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-rail-chip:hover { border-color: var(--text-low, #9ca3af); }

/* "Filter Events" lead chip — static, non-clickable, sits before the
   actual filter chips so users know what the row is for. Inline-flex
   here (not just on the `.sa-rail-chip` base) so the icon + label stay
   clustered even when the chip is used WITHOUT `.sa-rail-chip` — the
   ticket-side lead emits only `.sa-rail-chip-lead .sa-fchip-lead`. */
.sa-rail-chip-lead {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   white-space: nowrap;
   flex: 0 0 auto;
   cursor: default;
   color: var(--color-primary-subtitle);
   font-weight: 600;
   background: transparent;
   border: 0;
   padding: 0 4px 0 0;
}

.sa-rail-chip-lead:hover { border-color: transparent; }

.sa-rail-chip-lead [data-is="icon"] {
   width: 16px;
   height: 16px;
}

/* Click flash feedback — pulses the card strip so users know the filter took */
@keyframes sa-strip-flash {
   0%   { opacity: 0.4; }
   100% { opacity: 1; }
}
.sa-strip-flash {
   animation: sa-strip-flash 0.35s ease-out;
}

.sa-rail-chip.is-active {
   border-color: var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
}

.sa-rail-chip-label {
   font-weight: 500;
   /* Cap open-ended performer / event names ("Hot Wheels Monster
      Trucks Live Glow-N-Fire") at 120px and wrap to 2 lines instead
      of letting the chip stretch arbitrarily wide. */
   max-width: 120px;
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
   overflow: hidden;
   overflow-wrap: anywhere;
   line-height: 1;
}
.sa-rail-chip-count { color: var(--text-low, #6b7280); font-size: 12px; }

.sa-rail-chip-dismissible { padding-right: 8px; }
.sa-rail-chip-dismiss { opacity: 0.6; margin-left: 2px; }
.sa-rail-chip-dismissible:hover .sa-rail-chip-dismiss { opacity: 1; }


/* Event-card strip — lives inside the [data-layout='map'] column above
   the seating map. White surface with soft shadow; 16px padding on top
   and left, no right padding so the slider runs to the column's right
   edge. Extra bottom padding gives room for the cards' own shadow to
   render below the cards without clipping. */
/* `.sa-rail-strip` is the new layout container: stacks event-filter chips
   (top) + event-card slider (middle) + ticket-filter chips (bottom, event-
   mode only). Background lives here so all three children share one
   translucent panel that floats above the map. */
.sa-rail-strip {
   position: relative;
   z-index: 1;
   display: flex;
   flex-direction: column;
   gap: 8px;
   padding: 0;
   background: linear-gradient(to bottom, rgb(236 244 255 / 60%), rgb(243 247 253 / 60%));
   -webkit-backdrop-filter: blur(8px);
   backdrop-filter: blur(8px);
}

/* Strip children: drop their own backgrounds so the parent's translucent
   panel is the single visual surface. Cards are 100px tall on desktop; the
   strip lets them drive height (`min-height` removed) and adds only minimal
   left-padding so the first card has breathing room from the panel edge. */
.sa-event-strip {
   padding: 0 0 0 16px;
   flex: 0 0 auto;
   background: transparent;
   box-shadow: none;
}

/* Empty-state note. Shown by `SectionRailCtrl._renderCards` when the
   active filter chain yields zero events — slider gets hidden, this
   note takes its place. Reserves the strip's vertical space so the
   layout doesn't jump on filter changes. */
.sa-event-strip-empty {
   display: flex;
   align-items: center;
   justify-content: center;
   min-height: var(--sa-event-strip-height, 140px);
   color: var(--color-70, rgba(0,36,72,0.70));
   font-size: 14px;
   font-weight: 500;
   font-style: italic;
}
.sa-event-strip-empty[hidden] {
   display: none;
}

/* Separator between the event-card slider and the ticket-filter chip
   row. ONLY shows when the filters are visible (event mode + tickets
   have a filter taxonomy). Hidden state has `hidden` attribute and gets
   no border. */
.sa-rail-strip > .sa-rail-filters:not([hidden]) {
   border-top: 1px solid rgba(0, 0, 0, 0.08);
   padding-top: 8px;
}

/* Bottom translucent strip — holds the relocated `.sa-event-strip` in
   event mode (cards below the map so the map dominates). Mirrors
   `.sa-rail-strip`'s background + blur + flex column layout. Stays
   hidden in browse mode (`hidden` attribute from SectionRailCtrl). */
.sa-rail-strip-bottom {
   position: relative;
   z-index: 1;
   display: flex;
   flex-direction: column;
   gap: 8px;
   padding: 0;
   background: rgba(255, 255, 255, 0.60);
   -webkit-backdrop-filter: blur(8px);
   backdrop-filter: blur(8px);
   background: rgb(243 244 246);
   padding-bottom: 12px;
}
.sa-rail-strip-bottom[hidden] { display: none; }

/* Rail view toggle — Tickets / Seats. Narrow + event-mode only. Sits
   at the top of `.sa-rail-strip-bottom`, left-aligned, plain text — no
   chip background. Active option is bold + primary color; inactive is
   lighter and dimmer. Tap an option → `main.is-rail-view-seats` class
   flips; CSS reads that to swap visible content (ticket cards <-> the
   under-map explore slider). */
.sa-rail-view-toggle {
   display: none;
   gap: 18px;
   padding: 6px 16px 0;
   align-items: baseline;
}
.sa-rail-view-btn {
   background: none;
   border: 0;
   padding: 4px 0;
   font: inherit;
   font-size: 14px;
   font-weight: 500;
   color: var(--color-50, rgba(0, 36, 72, 0.50));
   cursor: pointer;
}
.sa-rail-view-btn.is-active {
   font-weight: 700;
   color: var(--color-primary, #002448);
}
@media (max-width: 879px) {
   /* Toggle only appears when an event is selected on narrow. */
   body:has(.sc-map-wrap.is-event-mode) main.sa-seating-chart .sa-rail-view-toggle {
      display: flex;
   }
   /* Seats view active — hide ticket cards in the rail-strip-bottom,
      reveal the under-map explore slider that's otherwise hidden in
      event mode. */
   main.sa-seating-chart.is-rail-view-seats .sa-rail-strip-bottom .sa-event-strip {
      display: none;
   }
   body:has(.sc-map-wrap.is-event-mode) main.sa-seating-chart.is-rail-view-seats .panel-explore {
      display: block;
      margin-top: 0px;
   }
}

/* Event-mode fullscreen on narrow — hide the site header, venue nav,
   panel-top (breadcrumbs/h1), and panel-bottom (post-map content) so
   only the rail + map area is visible. Modern "focus on the buying
   decision" pattern. User exits by clearing the event (× button on
   the selected-event row inside the rail strip). */
@media (max-width: 879px) {
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) header[data-header="main"],
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) nav[data-nav="venue"],
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > .panel-top,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > .panel-bottom,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) footer,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) #footer-page,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) #footer-basic,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) #footer-mobile {
      display: none;
   }
   /* Fullscreen layout — stage fills the viewport, map slot grows to
      consume any free vertical space, rail-strip-bottom (toggle +
      ticket cards) pins to the bottom of the map slot, panel-explore
      (Seats view) sits below the map at its natural height. Result:
      no dead whitespace; map is the biggest element on screen. */
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] {
      display: flex;
      flex-direction: column;
      min-height: 100dvh;
   }
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > [data-layout="map"] {
      flex: 1 1 0;
      min-height: 0;
      display: flex;
      flex-direction: column;
      margin-bottom: 0;
   }
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart.is-rail-view-seats > section[data-layout="stage"] > [data-layout="map"] {
      height: calc(100vh - 100px);
      flex: unset;
   }   
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > [data-layout="map"] .sa-rail-map {
      flex: 1 1 0;
      min-height: 0;
      max-height: none;
      aspect-ratio: auto;
   }
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > [data-layout="map"] .sa-rail-strip,
   body:has(main.sa-seating-chart .sc-map-wrap.is-event-mode) main.sa-seating-chart > section[data-layout="stage"] > [data-layout="map"] .sa-rail-strip-bottom {
      flex-shrink: 0;
   }
}

[data-layout='scene'].sa-available-tickets{
       margin-block-end: calc( 2 *var(--scene-gap));
}

/* ── Zone intro (cover photo + Features & Amenities) ──────────────────────
   Zone-only top-of-page block (view=zone). Cover photo leads when the
   zone has no seat-views slider; Features & Amenities renders the zone
   description. Body inherits the design-system `[data-format="content"]`
   typography. */
.sa-zone-intro {
   margin-block-start: 8px;
}
.sa-zone-cover {
   margin: 0 0 20px;
   border-radius: var(--sa-card-radius, 6px);
   overflow: hidden;
}

/* ── Event-type picker overlaid on the lead photo ─────────────────────────
   The picker is rendered server-side as a child of either the seat-views
   slider/photo (`.sa-sv-slider` / `.sa-sv-photo`) or the zone cover figure
   (`.sa-zone-cover`) — driven by `Page::pickerSlot` in init-section.php /
   init-zone.php. The host figure gets `.sa-photo-has-picker` and the
   picker gets `.is-photo-overlay` at PHP render time, so the picker lands
   in its final position on first paint — no JS move, no CLS. When there's
   no lead photo, section-title.php emits the picker inline instead. */
.sa-photo-has-picker {
   position: relative;
}
.sa-st-picker.is-photo-overlay {
   position: absolute;
   top: 8px;
   left: 8px;
   z-index: 5;
   margin: 0;
   padding: 6px 10px;
   display: inline-flex;
   align-items: center;
   min-width: 240px;
   background: #fff;
   border-radius: var(--sa-card-radius);
   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.18);
}
/* Single-event overlay: card body should grow into the available width so
   the title + seatscore align with where the multi-event card body sits.
   (`.sa-st-card-body` is `flex: 0 1 auto` to keep the chevron tight on
   multi; on single there is no chevron, so let the body breathe.) */
.sa-st-picker.is-photo-overlay .sa-st-card.is-static .sa-st-card-body {
   flex: 1 1 auto;
   padding-right: 0;
}
.sa-zone-cover img {
   display: block;
   width: 100%;
   height: clamp(200px, 32vw, 280px);
   object-fit: cover;
}
.sa-zone-features-title {
   margin: 0 0 8px;
}
/* Clamp the inline preview to ~7 lines (down from 10, Keith 2026-06-02
   tighter zone-intro pass) with a soft fade at the bottom; the full
   description opens in ContentModal('zone'). `-webkit-line-clamp` needs
   the box display + vertical orient (works across modern browsers,
   incl. Firefox 68+). */
.sa-zone-features-body {
   position: relative;
   display: -webkit-box;
   -webkit-line-clamp: 7;
   line-clamp: 7;
   -webkit-box-orient: vertical;
   overflow: hidden;
}
.sa-zone-features-body::after {
   /* Fade the last line so the cut-off reads intentional, not chopped. */
   content: "";
   position: absolute;
   left: 0; right: 0; bottom: 0;
   height: 2.2em;
   background: linear-gradient(rgba(255,255,255,0), #fff);
   pointer-events: none;
}
.sa-zone-features-more {
   appearance: none;
   border: 0;
   background: none;
   padding: 6px 0 0;
   margin: 0;
   font: inherit;
   font-size: 14px;
   font-weight: 700;
   color: var(--color-brand, #0067CE);
   cursor: pointer;
}
.sa-zone-features-more:hover { text-decoration: underline; }


/* ── Bottom-of-page event list ───────────────────────────────────────────
   Last widget inside `panel-bottom`, so it inherits the panel's
   max-width / padding / typography and flows in the left column on
   widescreen (no longer a full-width standalone band). Renders via
   `EventList` from `themes/assets/lib/scripts/eventsManager.js` (default
   theme) — row markup uses the shared `.list-events` styling already in
   `lib/base/styles/src/events.css`. Just a top gap + heading here. */
.sa-evlist {
   margin-block-start: clamp(24px, 4vw, 40px);
}
.sa-evlist-title {
   margin: 0 0 16px;
}
.sa-evlist-mount {
   width: 100%;
}

/* Shared month-filter dropdown (event-picker group-drill view + bottom
   upcoming-events list). Inline-SVG chevron + appearance:none for the
   same reasons as [data-rr="event-type-select"]: iOS Safari strips the
   native arrow on transparent-background <select>, leaving the dropdown
   looking static. */
.sa-month-filter {
   display: inline-flex;
   align-items: center;
   min-width: 0;
}
.sa-month-filter-select {
   appearance: none;
   -webkit-appearance: none;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 999px;
   background-color: #fff;
   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 fill='none' stroke='%23002448' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
   background-repeat: no-repeat;
   background-position: right 12px center;
   background-size: 10px 6px;
   color: var(--text-default, #111827);
   font: inherit;
   font-size: 13px;
   font-weight: 500;
   padding: 6px 28px 6px 12px;
   line-height: 1.2;
   cursor: pointer;
   max-width: 240px;
}
.sa-month-filter-select:focus {
   outline: 2px solid var(--color-primary, #002448);
   outline-offset: 1px;
}
/* "Filter active" affordance — when a month is selected the dropdown
   reads as an active filter chip (primary fill) so the user has a clear
   "this is on" signal. Selecting "All months" returns it to the neutral
   state. */
.sa-month-filter.is-active .sa-month-filter-select {
   background-color: var(--color-primary, #002448);
   border-color: var(--color-primary, #002448);
   color: #fff;
   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 fill='none' stroke='%23ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
}

/* Bottom upcoming-events list month filter — sits between the heading
   and the chip-bar/list mount. Right-aligned so it sits at the end of
   the row visually paired with the heading; collapses to its own row
   on narrow viewports. */
.sa-evlist-month-filter {
   display: flex;
   justify-content: flex-end;
   margin-block-end: 12px;
}

/* Event-row CTA — base `.list-events li.is-event button` rule in
   lib/base/styles/src/events.css:184 sets `--btn-bg: var(--color-brand)`
   but never `background:` to consume it, so the button is transparent
   in default state and only `:hover` (events.css:1413) gives it color.
   That reads as broken — solid CTA on hover only. Fix in SA scope so we
   don't disturb other consumers of `.list-events`. */
.sa-evlist .list-events li.is-event button {
   background: var(--btn-bg);
}

/* Count badge next to "Upcoming events" heading. Renders next to the h2,
   self-hides via [hidden] on its parent when filter yields zero events
   (set by SectionEventListBottomCtrl._wireCountObserver). */
.sa-evlist-count {
   display: inline-block;
   margin-inline-start: 8px;
   padding: 2px 8px;
   border-radius: 999px;
   background: var(--color-10, rgba(0,36,72,0.10));
   color: var(--text-low, var(--color-70));
   font-size: 13px;
   font-weight: 500;
   vertical-align: middle;
}


/* Filter-chip skeleton — sized to match the real chips that EventList
   renders (events.css:126-141 sets ~32px height + ~20px border-radius +
   ~80-160px width range). Placeholder pulse via `.u-skeleton`. */
.sa-evlist-filter-skel {
   padding: 0 0 8px;
}
.sa-evlist-chip-skel {
   display: inline-block;
   height: 32px;
   width: clamp(72px, 18%, 120px);
   border-radius: 20px;
   margin-right: 8px;
   margin-bottom: 8px;
   vertical-align: middle;
}

/* Hide EventList's native `.pagination` ("Page X of Y" markup) inside
   the SA bottom event list — we render our own custom pagination
   element (`.sa-evlist-pagination`) below the <ul> with the "Showing
   A–B of N events" format. EventList still tries to render its
   pagination after each renderEvents call; this CSS keeps it out of
   sight so we have a single visible pagination source. */
.sa-evlist .pagination {
   display: none !important;
}

/* Custom pagination — sits below the <ul>, mirrors patterns used
   elsewhere in the design system (rounded buttons + centered range
   text + responsive collapse on narrow viewports). */
.sa-evlist-pagination {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   margin-block-start: 16px;
   padding-block-start: 12px;
   border-block-start: 1px solid var(--outline-color, #E5E5E5);
}
.sa-evlist-pagination[hidden] {
   display: none;
}
.sa-evlist-page-info {
   font-size: 13px;
   color: var(--color-70, rgba(0,36,72,0.70));
   text-align: center;
   flex: 1 1 auto;
}
.sa-evlist-page-info strong {
   color: var(--text-default, var(--color-primary));
   font-weight: 600;
   white-space: nowrap;
}
.sa-evlist-page-btn {
   appearance: none;
   border: 1px solid var(--outline-color, #E5E5E5);
   background: #fff;
   color: var(--color-primary, #002448);
   font-size: 13px;
   font-weight: 500;
   padding: 8px 14px;
   border-radius: 999px;
   cursor: pointer;
   flex: 0 0 auto;
   transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.sa-evlist-page-btn:hover:not(:disabled) {
   background: var(--color-primary, #002448);
   color: #fff;
   border-color: var(--color-primary, #002448);
}
.sa-evlist-page-btn:disabled {
   opacity: 0.4;
   cursor: not-allowed;
}
/* Single-line at every breakpoint — vertical real estate is tight in the
   panel, can't afford to wrap Prev / info / Next onto two rows. Tighten
   button padding + font on narrow screens instead. */
@media (max-width: 480px) {
   .sa-evlist-pagination {
      gap: 8px;
   }
   .sa-evlist-page-btn {
      padding: 6px 10px;
      font-size: 12px;
   }
   .sa-evlist-page-info {
      font-size: 12px;
   }
}

/* ── Mobile sticky bottom CTA ─────────────────────────────────────────────
   Fixed-to-bottom bar visible only after the user scrolls past the map.
   SectionStickyCtaCtrl toggles `.is-visible` based on an IntersectionObserver
   watching the map slot. Desktop hides this entirely — the right-column
   sticky map keeps the picker reachable already. */
.sa-sticky-cta {
   position: fixed;
   left: 0;
   right: 0;
   bottom: 0;
   z-index: 60;
   padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
   background: #fff;
   border-top: 1px solid var(--sa-border-soft, #e5e7eb);
   box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);
   transform: translateY(100%);
   transition: transform 0.22s ease;
}

.sa-sticky-cta.is-visible { transform: translateY(0); }

.sa-sticky-cta[hidden] { display: none; }

.sa-sticky-cta [data-state] {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   width: 100%;
}

.sa-sticky-cta [data-state][hidden] { display: none; }

.sa-sticky-cta-text {
   display: flex;
   flex-direction: column;
   line-height: 1.15;
   min-width: 0;
   flex: 1 1 auto;
}

.sa-sticky-cta-line-1,
.sa-sticky-cta-line-3 {
   font-size: 12px;
   color: var(--text-low, #6b7280);
   font-weight: 500;
}

.sa-sticky-cta-line-2 {
   font-size: 17px;
   font-weight: 700;
   color: var(--text-default, #111827);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-sticky-cta-event {
   display: flex;
   flex-direction: column;
   line-height: 1.2;
   min-width: 0;
   flex: 1 1 auto;
   gap: 2px;
}

.sa-sticky-cta-event-name {
   font-size: 15px;
   font-weight: 600;
   color: var(--text-default, #111827);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-sticky-cta-event-meta {
   font-size: 12px;
   color: var(--text-low, #6b7280);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-sticky-cta-btn {
   appearance: none;
   flex: 0 0 auto;
   padding: 12px 18px;
   border: 0;
   border-radius: 999px;
   background: var(--color-brand, #0067CE);
   color: #fff;
   font-size: 14px;
   font-weight: 600;
   white-space: nowrap;
   cursor: pointer;
}

.sa-sticky-cta-btn:hover  { background: #0056b3; }
.sa-sticky-cta-btn:active { background: #004a99; }

@media (min-width: 880px) {
   .sa-sticky-cta { display: none; }
}

/* Event-card slider */
.sa-rail-events {
   display: block;
   width: 100%;
   /* Two ancestors clip the card shadow at the cards' bottom edge:
       (1) rys-slider's `:host { overflow: hidden }`
       (2) the endcap variant adds `:host([nav="endcap"]) .slider-viewport
           { overflow: hidden }` for clipping the track behind the nav cap
      Both need to allow vertical bleed for the shadow to paint while
      still clipping horizontally so cards don't show past the right
      edge / behind the nav. `overflow-x: clip; overflow-y: visible` is
      the right combo — `clip` (not `hidden`) on one axis sidesteps the
      spec rule that would coerce the paired `visible` back to `auto`.
      Overriding the viewport via `::part(viewport)` reaches across the
      shadow-DOM boundary. */
   overflow-x: clip;
   overflow-y: visible;
}
.sa-rail-events::part(viewport) {
   overflow-x: clip;
   overflow-y: visible;
}

.sa-rail-events[hidden] { display: none; }

/* Hide the empty rys-slider header (it ships with margin-bottom: 1rem
   which adds a phantom 16px gap above the cards when no [slot="header"]
   is provided). Same reason as .sa-tab-photo-slider further down. */
.sa-rail-events::part(header) { display: none; }

.sa-rail-card {
   /* Explicit width is required: cards are inserted dynamically via
      `insertAdjacentHTML` (SectionRailCtrl) AFTER rys-slider's `_init`
      runs, so they don't pick up the inline `flex` rys-slider would
      otherwise stamp on each slide. Without an explicit width they
      collapse to content. `flex: 0 0 160px` is the same target the
      slider uses for IPP calc (`target-width="160"` on the host).
      Slider page-shift math reads `offsetLeft` from actual rendered
      slides, so it's correct regardless of where the width came from. */

   height: 100px;
   border-radius: var(--sa-card-radius);
   overflow: visible;     /* let the box-shadow paint below the card */
   flex-shrink: 0;
}

.sa-rail-card-skel {
   background: var(--sa-bg-soft);
}


/* Lead card — section anchor + education */
.sa-rail-lead {
   background: var(--color-primary, #002448);
   color: #fff;
   border: 2px solid var(--color-brand, #0067CE);
   padding: 12px 14px;
   display: flex;
   flex-direction: column;
   justify-content: space-between;
}

.sa-rail-lead-section {
   font-size: 13px;
   font-weight: 500;
   color: rgba(255,255,255,0.85);
   line-height: 1.2;
}

.sa-rail-lead-meta {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   font-size: 11px;
   font-weight: 600;
   letter-spacing: 0.04em;
   color: rgba(255,255,255,0.85);
   margin-top: 4px;
}

.sa-rail-lead-price {
   font-size: 28px;
   font-weight: 700;
   line-height: 1;
   margin-top: 2px;
}

.sa-rail-lead-edu {
   margin: 0;
   font-size: 11px;
   line-height: 1.4;
   color: rgba(255,255,255,0.78);
}


/* Event card — card-strip pattern. 200x120 fixed. 2px top stripe is
   default black; resolves to an opponent primary color when known
   (set inline via --sa-rail-top). Header (date / time) above body
   (identifier + name + optional meta) above footer (price / select).  */
.sa-rail-event-card {
   --sa-rail-top: #000000;
   position: relative;
   background: #fff;
   border: 1px solid var(--sa-border-soft);
   border-top: 2px solid var(--sa-rail-top);
   box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
   cursor: pointer;
   display: flex;
   flex-direction: column;
   align-items: stretch;   /* override rys-slider's ::slotted align-items:center */
   transition: transform 0.15s ease, box-shadow 0.15s ease;
   text-align: left;
}

.sa-rail-event-card:hover {
   transform: translateY(-1px);
   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16);
}

.sa-rail-event-card.is-selected {
   box-shadow: 0 0 0 2px var(--color-brand, #0067CE);
}
/* Group card — collapses high-volume residencies (Sphere, Broadway runs)
   into one card with a "N shows" badge in the head slot and a "View dates"
   CTA in the footer. ti.2 parity. Click opens the picker drilled to the
   group's events. Visual chrome reuses `.sa-rail-event-card` body/footer;
   only the head row is replaced via `.sa-rail-group-head`. */
.sa-rail-event-card.is-group .sa-rail-group-head {
   display: flex;
   align-items: center;
   padding: 7px 10px 0;
}
.sa-rail-event-card.is-group .sa-rail-group-count {
   display: inline-flex;
   align-items: center;
   gap: 4px;
   font-size: 11px;
   font-weight: 700;
   line-height: 1.1;
   letter-spacing: 0.02em;
   text-transform: uppercase;
   color: var(--color-primary, #002448);
}
.sa-rail-event-card.is-group .sa-rail-group-count i[data-is="icon"] {
   width: 12px;
   height: 12px;
}

/* Header row */
.sa-rail-event-head {
   display: flex;
   align-items: center;
   justify-content: space-between;
   padding: 7px 10px 0;
   font-size: 11px;
   line-height: 1.1;
   text-transform: uppercase;
   letter-spacing: 0.02em;
   white-space: nowrap;
}

.sa-rail-event-date {
   font-weight: 600;
   color: var(--text-default);
}

.sa-rail-event-time {
   font-weight: 500;
   color: var(--color-70);
}

/* Body */
.sa-rail-event-body {
   flex: 1 1 auto;
   display: flex;
   gap: 6px;
   padding: 5px 10px 6px;
   min-width: 0;
   overflow: hidden;
}
.sa-rail-event-body[data-layout="performer"] { align-items: center; }
.sa-rail-event-body[data-layout="inline"]    { align-items: center; }

/* Identifier slots */
.sa-rail-event-img {
   flex: 0 0 36px;
   width: 36px;
   height: 40px;
   border-radius: 4px;
   object-fit: cover;
   background: var(--sa-bg-soft, #f3f4f6);
}

/* Category-icon fallback slot — same 36×40 box as the `<img>` it replaces
   when there's no performer photo (group cards without a headliner pic;
   used to fall through to the venue cover, now renders a sport/category
   icon instead). `[data-is="icon"]` would render at its `--icon-size`
   default in the middle of a 36×40 slot, but the mask `contain` rule
   makes the icon stretch to fill — override width/height for a tighter
   icon-on-soft-tile look. */
.sa-rail-event-img-icon {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   color: var(--color-primary-subtitle, #6b7280);
   /* `[data-is="icon"]` base rule paints the icon via mask. Re-declare
      the mask-position so the smaller icon stays centered within the
      36×40 host box rather than top-left. */
   -webkit-mask-position: center;
           mask-position: center;
   /* Force the rendered icon glyph to ~22px while keeping the host box
      at the 36×40 we declared above. `mask-size` controls the painted
      mask area; `contain` defaults fill the host, so set an explicit
      px length instead. */
   -webkit-mask-size: 22px;
           mask-size: 22px;
}

.sa-rail-event-mlb {
   flex: 0 0 auto;
   height: 22px;
   width: auto;
   border-radius: 3px;
   object-fit: contain;
}

.sa-rail-event-abbrev {
   flex: 0 0 auto;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   min-width: 28px;
   height: 22px;
   padding: 0 6px;
   border-radius: 4px;
   background: var(--sa-rail-abbrev-bg, #6b7280);
   color: var(--sa-rail-abbrev-fg, #fff);
   font-size: 11px;
   font-weight: 700;
   letter-spacing: 0.02em;
   white-space: nowrap;
}

.sa-rail-event-avatar {
   flex: 0 0 20px;
   width: 20px;
   height: 20px;
   border-radius: 4px;
   display: inline-flex;
   align-items: center;
   justify-content: center;
}

.sa-rail-event-avatar [data-is="icon"] {
   width: 14px;
   height: 14px;
}
.sa-rail-event-avatar.bg-basketball { background: var(--bg-basketball); color: var(--text-basketball); }
.sa-rail-event-avatar.bg-hockey     { background: var(--bg-hockey);     color: var(--text-hockey); }
.sa-rail-event-avatar.bg-baseball   { background: var(--bg-baseball);   color: var(--text-baseball); }
.sa-rail-event-avatar.bg-football   { background: var(--bg-football);   color: var(--text-football); }
.sa-rail-event-avatar.bg-soccer     { background: var(--bg-soccer);     color: var(--text-soccer); }
.sa-rail-event-avatar.bg-concert    { background: var(--bg-concert);    color: var(--text-concert); }
.sa-rail-event-avatar.bg-theater    { background: var(--bg-theater);    color: var(--text-theater); }
.sa-rail-event-avatar.bg-other      { background: var(--bg-other);      color: var(--text-other); }
.sa-rail-event-avatar.bg-fighting   { background: var(--bg-fighting);   color: var(--text-fighting); }
.sa-rail-event-avatar.bg-softball   { background: var(--bg-softball);   color: var(--text-softball); }

/* Info column */
.sa-rail-event-info {
   flex: 1 1 auto;
   min-width: 0;
   display: flex;
   flex-direction: column;
   gap: 2px;
}

.sa-rail-event-name {
   font-size: 13px;
   font-weight: 700;
   line-height: 1;
   color: var(--text-default);
   overflow: hidden;
   /* Allow wrap to 2 lines so longer matchups/titles still fit at the
      narrower 160px card width. */
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
   overflow-wrap: anywhere;
}

.sa-rail-event-meta {
   font-size: 12px;
   line-height: 1;
   color: var(--color-70);
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
}

/* Footer */
.sa-rail-event-footer {
   display: flex;
   justify-content: space-between;
   align-items: center;
   gap: 8px;
   padding: 5px 10px;
   border-top: 1px solid #EEE;
   font-size: 12px;
   line-height: 1.1;
}

.sa-rail-event-price { color: var(--color-70); }
.sa-rail-event-price strong { color: var(--text-default); font-weight: 700; }

.sa-rail-event-cta {
   display: inline-flex;
   align-items: center;
   gap: 0px;
   color: var(--color-brand);
   font-weight: 500;
}

/* ── Selected event card (lives at the head of the strip in event mode)
   Same outer card structure as browse-mode cards, just 240px wide so the
   user has a clear anchor. Footer has the [All Tickets] CTA; deselect
   is a small top-right X (dismiss pattern) instead of competing for
   footer space. */
.sa-rail-event-card.is-selected-strip {
   flex: 0 0 240px !important;
   width: 240px !important;
   position: relative;       /* anchor for the absolute-positioned X */
}

.sa-rail-event-footer-selected {
   padding: 6px 10px;
}

.sa-rail-event-allbtn {
   appearance: none;
   border: 0;
   background: transparent;
   color: var(--color-brand);
   font-weight: 600;
   font-size: 12px;
   cursor: pointer;
   padding: 4px 6px;
}
.sa-rail-event-allbtn:hover { text-decoration: underline; }

/* Top-right X. Discreet — small, neutral color, hover-darkens. Reads as
   "dismiss this selection" without dominating the card. */
.sa-rail-event-deselect {
   appearance: none;
   position: absolute;
   top: 4px;
   right: 4px;
   width: 22px;
   height: 22px;
   padding: 0;
   border: 0;
   border-radius: 50%;
   background: rgba(0, 0, 0, 0.06);
   color: var(--color-70, rgba(0,36,72,0.70));
   cursor: pointer;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   z-index: 2;
   transition: background-color .12s ease, color .12s ease;
}
.sa-rail-event-deselect:hover {
   background: rgba(0, 0, 0, 0.12);
   color: var(--color-primary, #002448);
}
.sa-rail-event-deselect [data-is="icon"] {
   color: inherit;
   pointer-events: none;
}


/* ── Ticket suggestion cards (replace event cards after selection) ──────
   Mirrors the hover card's key info but reorganised for a 200×100 card:
   top stack (avatar + section/row → marquee brief → deal label) and a
   bottom row (qty left, large price right). Marquee uses the design-
   system `marquee` icon from `lib/base/styles/src/icons.css` and shares
   the default text color — no bespoke brand-blue intro. Marquee TEXT is
   the `brief` (what the map flag prints) so card + flag say the same
   thing. */
.sa-rail-ticket-card {
   height: 116px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: var(--sa-card-radius, 6px);
   background: #fff;
   box-shadow: 0 1px 3px rgba(0,0,0,0.10);
   overflow: visible;
   display: flex;
   flex-direction: column;
   align-items: stretch;   /* override rys-slider's ::slotted align-items:center */
   gap: 6px;               /* badge → section → deal → foot rhythm */
   padding: 10px 12px;
   transition: transform 0.12s ease, box-shadow 0.12s ease;
   cursor: pointer;
   /* Suppress text selection — the card is a click target (opens
      TicketModal), not a content surface. Drag-selects of "Section 124,
      Row 5" feel broken in this context. */
   user-select: none;
   -webkit-user-select: none;
}
.sa-rail-ticket-card:hover {
   transform: translateY(-1px);
   box-shadow: 0 4px 10px rgba(0,0,0,0.14);
}

.sa-rail-ticket-skel { cursor: default; padding: 0; }
.sa-rail-ticket-skel:hover { transform: none; box-shadow: 0 1px 3px rgba(0,0,0,0.10); }

/* Tail edu card — always trails the ticket-suggestion strip in event
   mode. Same outer chrome as `.sa-rail-ticket-card` (radius, shadow,
   bg) so it slots into the slider without looking out of place; inner
   layout is title block + body text + CTA. Only the CTA at the
   bottom is the clickable link (per spec). */
.sa-rail-ticket-card-edu {
   color: var(--color-primary, #002448);
   display: flex;
   flex-direction: column;
   justify-content: space-between;
   gap: 12px;
   text-align: left;
   background: linear-gradient(135deg, rgba(0,103,206,0.06), rgba(0,103,206,0.02));
   border-color: rgba(0, 103, 206, 0.18);
   cursor: default;
}
.sa-rail-ticket-edu-body {
   display: flex;
   flex-direction: column;
   gap: 8px;
}
.sa-rail-ticket-edu-head {
   display: flex;
   align-items: center;
   gap: 6px;
   color: var(--color-primary, #002448);
   font-weight: 700;
   font-size: 12px;
   letter-spacing: 0.02em;
}
.sa-rail-ticket-edu-title { font-size: 13px; }
.sa-rail-ticket-edu-text {
   margin: 0;
   font-size: 12px;
   color: var(--color-primary-subtitle, #6b7280);
   line-height: 1.35;
}
a.sa-rail-ticket-edu-cta {
   display: inline-flex;
   align-items: center;
   gap: 4px;
   font-size: 13px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   margin-top: auto;
}

/* Filter-to-zero empty-state card. Rendered in place of the ticket
   suggestions when `tm.filteredTickets.length === 0` but `tm.allTickets`
   has rows. Same outer card chrome as the suggestion + edu cards so the
   slider's slot height stays consistent. */
.sa-rail-ticket-card-empty {
   color: var(--color-primary, #002448);
   display: flex;
   flex-direction: column;
   justify-content: space-between;
   gap: 12px;
   text-align: left;
   background: var(--sa-bg-soft, #f8f7fb);
   border-color: rgba(0, 0, 0, 0.08);
   cursor: default;
}
.sa-rail-ticket-empty-body {
   display: flex;
   flex-direction: column;
   gap: 6px;
}
.sa-rail-ticket-empty-title {
   font-size: 13px;
   font-weight: 700;
   color: var(--color-primary, #002448);
}
.sa-rail-ticket-empty-text {
   margin: 0;
   font-size: 12px;
   color: var(--color-primary-subtitle, #6b7280);
   line-height: 1.35;
}
.sa-rail-ticket-empty-cta {
   appearance: none;
   border: 0;
   background: transparent;
   font: inherit;
   font-size: 13px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   cursor: pointer;
   text-decoration: underline;
   margin-top: auto;
   padding: 0;
   text-align: left;
}
.sa-rail-ticket-empty-cta:hover { text-decoration: none; }

/* Headline badge — inline pill containing the marquee sparkle icon +
   brief text. Primary-color background, white text; sits flush at the
   card's left edge as a self-contained label (no longer offset by an
   avatar slot). `align-self: flex-start` so the badge shrinks to its
   text width instead of stretching across the card. */
.sa-rail-ticket-headline {
   align-self: flex-start;
   max-width: 100%;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 3px 8px;
   border-radius: 12px;
   background: var(--color-primary, #002448);
   color: #fff;
   font-size: 11px;
   font-weight: 700;
   line-height: 1.2;
   letter-spacing: -0.01em;
   white-space: nowrap;
   overflow: hidden;
}
.sa-rail-ticket-headline span {
   overflow: hidden;
   text-overflow: ellipsis;
}
.sa-rail-ticket-headline [data-is="icon"] {
   color: #fff;
   flex: 0 0 auto;
}

/* Plain-text variant for best-match cards (no icon). Distinct from the
   marquee headline — neutral grey-on-soft-grey so it reads as a scope
   label, not a "promoted" pill. */
.sa-rail-ticket-headline-plain {
   background: var(--color-10, rgba(0,36,72,0.10));
   color: var(--color-70, rgba(0,36,72,0.70));
}

.sa-rail-ticket-section {
   font-size: 12px;
   font-weight: 500;
   color: var(--text-default);
   line-height: 1.2;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
}

/* Bottom: qty (left) + price (right, large) — pinned to the card's
   bottom edge via `margin-top: auto` so the section/deal stack above
   doesn't crowd the foot when the badge is the only top element. */
.sa-rail-ticket-foot {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   gap: 8px;
   padding-top: 4px;
   border-top: 1px solid #EEE;
   margin-top: auto;
}
.sa-rail-ticket-qty {
   font-size: 11px;
   font-weight: 500;
   color: var(--color-70);
   white-space: nowrap;
}
.sa-rail-ticket-price {
   font-size: 17px;
   font-weight: 700;
   color: var(--text-default);
   line-height: 1;
}

/* Deal label — same `.ticket-deal` / `.ds.<tier>` shape as the hover
   card, scaled down for the smaller card. te.1's `#008a00` trailing
   label color is kept; tier color drives the score pill. */
.sa-rail-ticket-deal {
   color: #008a00;
   font-size: 11px;
   font-weight: 500;
   line-height: 1.3;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}
.sa-rail-ticket-deal span.ds {
   color: #fff;
   border-radius: 3px;
   padding: 1px 4px;
   font-size: 10px;
   font-weight: 600;
   margin-right: 3px;
}
.sa-rail-ticket-deal span.ds.excellent { background: #1A8828; }
.sa-rail-ticket-deal span.ds.great     { background: #429B46; }
.sa-rail-ticket-deal span.ds.good      { background: #5fa95d; }
.sa-rail-ticket-deal span.ds.fair      { background: #FFB61F; }
.sa-rail-ticket-deal span.ds.ok        { background: #FFB61F; }
.sa-rail-ticket-deal span.ds.poor      { background: #F34A1C; }

/* Map-flag spotlight when a ticket card is hovered. Chart tags each
   flag with `data-ticket-id`; `_bindTicketCardActions` toggles
   `.is-card-hover` on the paired flag. Visual treatment matches the
   chart's own `.is-hover` rule (`lib/seating-chart/seating-chart.css`
   L1468-1489) so card-hover and direct flag-hover look identical.
   Inline `transform` is set by the chart's positioning pass every
   frame; we never touch it. */
#sa-imap .sc-marker-flag.is-card-hover {
   background: #000 !important;
   border-color: #000 !important;
   box-shadow: 0 10px 26px rgba(0, 0, 0, 0.32) !important;
   z-index: 60 !important;
}
#sa-imap .sc-marker-flag.is-card-hover .sc-dbf-price,
#sa-imap .sc-marker-flag.is-card-hover .sc-dbf-debug,
#sa-imap .sc-marker-flag.is-card-hover .sc-mf-spark {
   color: #fff !important;
}
#sa-imap .sc-marker-flag.is-card-hover .sc-dbf-tail {
   background: #000 !important;
   border-right-color: #000 !important;
   border-bottom-color: #000 !important;
}


/* ── Condensed mobile card (< 880px) ────────────────────────────────────
   Same structure, smaller footprint: 180×88. The footer (price / select)
   stays untouched — it's the CTA. Concert/theater no longer get the
   double-line image; everything collapses to single-line height so cards
   look uniform regardless of event type. Meta sub-line hidden. */
@media (max-width: 879px) {
   /* (b) Shrink filter chips on phone — chip strip carries the full-height
      40px target on desktop, but at phone widths it eats vertical space
      and reads heavy. 40px → 32px (min-)height, 6px/14px → 4px/10px
      padding, 13px → 12px font. Two chip classes in play: `.sa-rail-chip`
      (event-type filter, top row) uses `min-height: 40px` to let labels
      wrap to 2 lines; `.sa-fchip` (ticket filter, bottom row in event
      mode) uses a fixed `height: 40px`. Override both — min-height on
      the wrapper, height on the fixed one. */
   .sa-rail-chip {
      min-height: 32px;
      padding: 4px 10px;
      font-size: 12px;
   }
   .sa-fchip {
      height: 32px;
      padding: 0 10px;
      font-size: 12px;
   }

   /* Smaller font fits more characters per line in the chip-label's max-
      width cap, so labels that used to wrap to 2 lines at desktop
      (`max-width: 120px` / 13px → ~10 chars per line) now fit on 1 line
      at 12px and the tall 2-line chip variant disappears. Tighten the
      cap proportionally so the wrap threshold matches desktop. */
   .sa-rail-chip-label {
      max-width: 100px;
   }

   /* (c) Belt-and-suspenders for the card shadow bleed. `.sa-rail-events`
      already does the `overflow-x: clip; overflow-y: visible` trick at the
      slider host + viewport (see the comment above the rule), but the
      `.sa-event-strip` wrapper around it can still clip on mobile when the
      strip's own height crunches to fit. Apply the same trick here so the
      `box-shadow: 0 2px 6px ...` on every event card paints below the card
      instead of getting cut off at the strip's bottom edge. */
   .sa-event-strip,
   .sa-rail-strip,
   .sa-rail-strip-bottom {
      overflow-x: clip;
      overflow-y: visible;
   }

   /* (d) Tighten rys-slider gap on phone so one more card fits per screen.
      `--rys-gap` is read dynamically by rys-slider (`_resolveGapPx()` at
      lib/components/js/rys-slider.js:571) and feeds both slide-width math
      and page-translate offsets, so overriding the var on the host is
      regression-safe — the slider recomputes slide widths on the next
      resize/render pass. Default 16px → 8px on mobile. */
   .sa-rail-events {
      --rys-gap: 8px;
   }

   /* Mobile map sizing — track the venue's natural content aspect via the
      `--sa-map-aspect` CSS var set by `InteractiveSeatingMapCtrl._apply
      MapAspect()` on `SeatingChart:ready`. Falls back to 4/3 on cold
      load before JS runs. Min-height keeps small/short maps usable;
      max-height caps tall maps so they can't dominate the viewport.

      `min-width: 0; max-width: 100%` prevents iOS Safari 18+ from
      back-solving the width from a clamped min/max-height through the
      aspect-ratio relationship — without these caps the browser would
      compute width = clamped-height × aspect (e.g. 400px × 1.71 ≈ 684px)
      and overflow the right edge on narrow viewports. iOS 18 tightened
      its aspect-ratio spec compliance; older iOS versions silently kept
      width at 100%. */
   .sa-rail-map {
      aspect-ratio: var(--sa-map-aspect, 4 / 3);
      width: 100%;
      max-width: 100%;
      min-width: 0;
      height: auto;
      min-height: 400px;
      max-height: 60vh;
   }

   .sa-rail-card {
      height: 88px;
   }

   /* Ticket-card content (marquee headline / section-row / deal pill /
      qty+price footer) varies per pick; let the card grow to fit and
      keep the 88px floor from `.sa-rail-card` above for consistency
      with event cards in the same row. */
   .sa-rail-ticket-card {
      height: auto;
      min-height: 88px;
   }

   .sa-rail-event-head {
      padding: 5px 8px 0;
      font-size: 10px;
   }

   .sa-rail-event-body {
      gap: 6px;
      padding: 4px 8px 5px;
   }

   /* Image collapses to match avatar/abbrev — single-line height */
   .sa-rail-event-img {
      flex: 0 0 28px;
      width: 28px;
      height: 28px;
   }

   .sa-rail-event-name,
   .sa-rail-event-name.is-clamp-1,
   .sa-rail-event-name.is-clamp-2 {
      font-size: 12px;
   }

   .sa-rail-event-meta {
      font-size: 10px;
      line-height: 1.2;
   }

   .sa-rail-event-footer {
      padding: 5px 8px;
      font-size: 11px;
   }
}


/* ── Rail filter chips (event-aware, post-event-selection) ──────────────
   Functional scaffolding — design polish pending. Horizontal strip of
   chips below the event cards. Click → group picker. Last chip is
   "More filters" → full filter sheet. */

/* Host is a positioning container for list-rail's ← → arrows. The actual
   flex layout + horizontal overflow lives on the `.list-rail-track` child
   that list-rail injects. Existing flex/overflow rules on the host are
   replaced by list-rail's behavior. */
.sa-rail-filters {
   padding: 8px 16px;
   align-items: center;
}
.sa-rail-filters[hidden] { display: none; }
/* list-rail puts the chips inside `.list-rail-track`. Re-apply the
   vertical-center alignment that the old `align-items` did. */
.sa-rail-filters .list-rail-track {
   align-items: center;
}

/* Lead "Filter Tickets" label — matches the event-strip lead chip. */
.sa-fchip-lead {
   flex: 0 0 auto;
}

.sa-fchip {
   appearance: none;
   border: 1px solid var(--sa-border-soft);
   background: #fff;
   color: var(--text-default);
   padding: 0 14px;
   height: 40px;
   border-radius: 999px;
   font-size: 13px;
   font-weight: 500;
   cursor: pointer;
   white-space: nowrap;
   display: inline-flex;
   align-items: center;
   gap: 6px;
   transition: border-color 0.15s ease, background 0.15s ease;
}
.sa-fchip:hover    { border-color: var(--text-low, #9ca3af); }
.sa-fchip.is-active {
   border-color: var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
}
.sa-fchip-count {
   font-size: 11px;
   font-weight: 700;
   color: var(--color-brand, #0067CE);
   background: rgba(0, 103, 206, 0.12);
   border-radius: 999px;
   padding: 1px 7px;
   min-width: 18px;
   text-align: center;
}
.sa-fchip-more {
   color: var(--color-brand, #0067CE);
   font-weight: 600;
}

/* Active filter pill — appears at the start of the chip strip showing the
   actual selected value (e.g. "$50 – $200", "Aisle", "2 tickets") with
   an × icon. Clicking removes that one selection. Modern 2026 pattern:
   filters communicate their state inline rather than only via count badges. */
.sa-fchip-active-pill {
   background: var(--color-primary, #002448);
   border-color: var(--color-primary, #002448);
   color: #fff;
   font-weight: 600;
   padding-right: 10px;
}
.sa-fchip-active-pill:hover {
   background: #001a36;
   border-color: #001a36;
}
.sa-fchip-active-pill .sa-fchip-remove {
   font-size: 18px;
   line-height: 1;
   opacity: 0.85;
   margin-left: 2px;
   margin-top: -1px;
}
.sa-fchip-active-pill:hover .sa-fchip-remove { opacity: 1; }

/* Single-group dropdown (portaled to <body>, positioned via JS) */
.sa-fdropdown {
   background: #fff;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   box-shadow: 0 8px 24px rgba(0,0,0,0.12);
   max-height: 60vh;
   overflow-y: auto;
   min-width: 200px;
}

.sa-foptlist {
   list-style: none;
   margin: 0;
   padding: 4px;
}
.sa-fopt {
   width: 100%;
   appearance: none;
   border: 0;
   background: transparent;
   text-align: left;
   padding: 12px 10px;
   border-radius: var(--sa-card-radius);
   font-size: 15px;
   line-height: 1.35;
   color: var(--text-default);
   cursor: pointer;
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
}
.sa-fopt:hover       { background: var(--sa-bg-soft); }
.sa-fopt.is-selected { color: var(--color-brand, #0067CE); font-weight: 600; }
.sa-fopt-check       { color: var(--color-brand, #0067CE); }
.sa-fopt-label       { flex: 1 1 auto; min-width: 0; }
.sa-fopt-count       { margin-left: auto; flex: 0 0 auto; font-size: 13px; color: var(--text-low, #6b7280); }
.sa-fopt.is-disabled,
.sa-fopt[disabled]   { opacity: 0.4; cursor: not-allowed; }
.sa-fopt.is-disabled:hover,
.sa-fopt[disabled]:hover { background: transparent; }
/* "All" item — separator below sets it apart from the value rows so the
   clear-selection role reads visually. */
.sa-foptlist li:has(.sa-fopt-all) { border-bottom: 1px solid var(--sa-border-soft, #eef0f4); margin-bottom: 4px; padding-bottom: 4px; }


/* ── Price filter: dual-thumb slider + open-ended min/max inputs ───────────
   Slider sits on top; two number inputs below. Empty Max = no upper bound. */
.sa-fprice {
   padding: 18px 18px 16px;
   min-width: 300px;
}

/* Histogram: 20 vertical bars showing ticket-count density across the
   price extent. Sits ABOVE the slider track. Bars use the same left/right
   margin as the slider so bar 0 aligns with the min thumb's home and
   bar 19 with the max thumb's home. */
.sa-fprice-hist {
   display: flex;
   align-items: flex-end;
   gap: 1px;
   height: 36px;
   margin: 0 8px 4px;
   padding: 0 6px;     /* match slider thumb half-width so bars align */
}
.sa-fprice-hist-bar {
   flex: 1 1 0;
   min-width: 0;
   background: var(--color-primary, #002448);
   border-radius: 2px 2px 0 0;
   opacity: 0.25;
   transition: opacity 120ms ease;
}
.sa-fprice-hist:hover .sa-fprice-hist-bar { opacity: 0.4; }

/* All-fees notice — trust-building copy at the bottom of the price panel.
   No background fill; the tag icon is the visual anchor. Larger text so
   the reassurance reads at a glance. */
.sa-fprice-fees {
   margin: 14px 14px 12px;
   padding: 0;
   display: flex;
   align-items: center;
   gap: 8px;
   font-size: 14px;
   font-weight: 500;
   color: var(--text-medium, #4b5563);
   line-height: 1.4;
}
.sa-fprice-fees i { flex: 0 0 auto; color: var(--color-primary, #002448); font-size: 16px; }

/* Footer row: Clear (text button, left) + Apply (solid CTA, right).
   Top border separates from the controls above. */
.sa-fprice-footer {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   padding: 10px 14px;
   border-top: 1px solid var(--sa-border-soft, #e5e7eb);
   margin-top: 4px;
}

/* Clear — text-only button on the left of the footer. Resets the range
   but keeps the panel open. */
.sa-fprice-clear {
   appearance: none;
   background: none;
   border: 0;
   padding: 6px 4px;
   color: var(--text-medium, #4b5563);
   font-size: 13px;
   font-weight: 600;
   cursor: pointer;
   text-decoration: underline;
   text-underline-offset: 3px;
   text-decoration-color: transparent;
   transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
.sa-fprice-clear:hover {
   color: var(--color-primary, #002448);
   text-decoration-color: currentColor;
}

/* Close-and-apply CTA. Filters auto-apply live; this is the explicit
   "I'm done filtering" affordance — closes the panel. Right-aligned in
   the footer, smaller than v3 (fits-content width, not full-width). */
.sa-fprice-apply {
   appearance: none;
   padding: 8px 14px;
   background: var(--color-primary, #002448);
   color: #fff;
   border: 0;
   border-radius: 8px;
   font-size: 13px;
   font-weight: 700;
   cursor: pointer;
   transition: background 0.15s ease;
}
.sa-fprice-apply:hover { background: #013768; }
.sa-fprice-apply:active { transform: scale(0.99); }

/* In the "More filters" / All-filters sheet, the sheet's own Done/Clear
   footer drives commits — the price filter's inline Clear/Apply row would
   compete with that flow. Hide the price footer when nested in either
   the desktop (.sa-fsheet) or mobile (.sa-fsheet-mobile) full-sheet
   wrapper. The single-chip price dropdown still shows it. */
.sa-fsheet .sa-fprice-footer,
.sa-fsheet-mobile .sa-fprice-footer { display: none; }

/* Price-axis tick labels under the histogram — four subtle rounded-number
   marks so users can read bar density against actual dollar amounts. */
.sa-fprice-ticks {
   position: relative;
   height: 14px;
   margin: 0 8px 2px;
   padding: 0 6px;       /* match histogram + slider padding so left/right align */
}
.sa-fprice-tick {
   position: absolute;
   transform: translateX(-50%);
   top: 0;
   font-size: 10px;
   font-weight: 500;
   color: var(--text-low, #9ca3af);
   line-height: 1;
   font-variant-numeric: tabular-nums;
   pointer-events: none;
}

/* Slider: two transparent range inputs overlap a shared track. The
   `.is-front` class (toggled on pointerdown) keeps the most recently-touched
   thumb on top so both stay grabbable when they overlap. */
.sa-fprice-slider {
   position: relative;
   height: 24px;
   margin: 6px 8px 22px;
}

.sa-fprice-track,
.sa-fprice-fill {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   height: 3px;
   border-radius: 2px;
   pointer-events: none;
}

.sa-fprice-track {
   left: 0;
   right: 0;
   background: var(--sa-border-soft, #e5e7eb);
}

.sa-fprice-fill {
   background: var(--color-primary, #002448);
}

.sa-fprice-range {
   position: absolute;
   left: -8px;
   right: -8px;
   top: 0;
   width: calc(100% + 16px);
   height: 24px;
   margin: 0;
   padding: 0;
   appearance: none;
   -webkit-appearance: none;
   background: transparent;
   pointer-events: none;
   z-index: 2;
}

.sa-fprice-range.is-front { z-index: 3; }

.sa-fprice-range::-webkit-slider-runnable-track {
   background: transparent;
   border: 0;
   height: 24px;
}

.sa-fprice-range::-moz-range-track {
   background: transparent;
   border: 0;
   height: 24px;
}

.sa-fprice-range::-webkit-slider-thumb {
   -webkit-appearance: none;
   appearance: none;
   width: 20px;
   height: 20px;
   border-radius: 50%;
   background: #fff;
   border: 2px solid var(--color-primary, #002448);
   box-shadow: 0 1px 3px rgba(0,0,0,0.18);
   cursor: pointer;
   pointer-events: auto;
   margin-top: 2px;        /* center 20px thumb on 24px track */
   transition: transform 0.1s ease, box-shadow 0.15s ease;
}

.sa-fprice-range::-moz-range-thumb {
   width: 20px;
   height: 20px;
   border-radius: 50%;
   background: #fff;
   border: 2px solid var(--color-primary, #002448);
   box-shadow: 0 1px 3px rgba(0,0,0,0.18);
   cursor: pointer;
   pointer-events: auto;
   transition: transform 0.1s ease, box-shadow 0.15s ease;
}

.sa-fprice-range:hover::-webkit-slider-thumb,
.sa-fprice-range:focus::-webkit-slider-thumb,
.sa-fprice-range:active::-webkit-slider-thumb {
   transform: scale(1.08);
   box-shadow: 0 2px 6px rgba(0,0,0,0.22);
}

.sa-fprice-range:hover::-moz-range-thumb,
.sa-fprice-range:focus::-moz-range-thumb,
.sa-fprice-range:active::-moz-range-thumb {
   transform: scale(1.08);
   box-shadow: 0 2px 6px rgba(0,0,0,0.22);
}

.sa-fprice-range:focus { outline: none; }

/* Min / Max inputs sit below the slider. Single-row grid, even widths. */
.sa-fprice-fields {
   display: grid;
   grid-template-columns: 1fr 1fr;
   gap: 12px;
}

.sa-fprice-field {
   display: flex;
   flex-direction: column;
   gap: 4px;
   min-width: 0;
}

.sa-fprice-field-label {
   font-size: 11px;
   font-weight: 600;
   text-transform: uppercase;
   letter-spacing: 0.05em;
   color: var(--text-low, #6b7280);
}

.sa-fprice-field-input {
   display: flex;
   align-items: center;
   gap: 2px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 8px;
   padding: 8px 12px;
   background: #fff;
   transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.sa-fprice-field-input:focus-within {
   border-color: var(--color-primary, #002448);
   box-shadow: 0 0 0 2px rgba(0, 36, 72, 0.08);
}

.sa-fprice-prefix {
   color: var(--text-low, #6b7280);
   font-size: 14px;
   font-weight: 500;
}

.sa-fprice-field-input input {
   appearance: none;
   -webkit-appearance: none;
   -moz-appearance: textfield;
   border: 0;
   background: transparent;
   font-size: 14px;
   font-weight: 600;
   color: var(--text-default);
   padding: 0;
   min-width: 0;
   width: 100%;
   outline: none;
}

.sa-fprice-field-input input::-webkit-outer-spin-button,
.sa-fprice-field-input input::-webkit-inner-spin-button {
   -webkit-appearance: none;
   margin: 0;
}

.sa-fprice-field-input input::placeholder {
   color: var(--text-low, #9ca3af);
   font-weight: 500;
}

/* In the full filter sheet, drop outer padding/min-width — the sheet
   already provides its gutters and the column is fluid. */
.sa-fsheet-group .sa-fprice {
   padding: 0;
   min-width: 0;
}

/* Full filter sheet — desktop slides in from right; mobile uses BottomSheet
   (see RailFilterChipsCtrl._openFullSheet — different path on mobile). */
.sa-fsheet {
   position: fixed;
   top: 0;
   right: 0;
   bottom: 0;
   width: min(420px, 92vw);
   background: #fff;
   z-index: 110;
   display: flex;
   flex-direction: column;
   box-shadow: -4px 0 16px rgba(0,0,0,0.18);
   transform: translateX(100%);
   transition: transform 0.25s ease;
}
.sa-fsheet.is-open { transform: translateX(0); }

.sa-fsheet-head {
   display: flex;
   align-items: center;
   justify-content: space-between;
   padding: 14px 16px;
   border-bottom: 1px solid var(--sa-border-soft);
}
.sa-fsheet-head h2 { margin: 0; }
.sa-fsheet-close {
   appearance: none;
   border: 0;
   background: transparent;
   font-size: 18px;
   cursor: pointer;
   color: var(--text-low);
   padding: 4px 8px;
}
.sa-fsheet-body {
   flex: 1 1 auto;
   overflow-y: auto;
   padding: 16px 18px 18px;
}
.sa-fsheet-group {
   margin-bottom: 24px;
}
.sa-fsheet-group h3 {
   margin: 0 0 8px;
   padding: 0 14px;
}
.sa-fsheet-foot {
   display: flex;
   gap: 8px;
   padding: 12px 16px;
   border-top: 1px solid var(--sa-border-soft);
}
.sa-fsheet-clear, .sa-fsheet-done {
   appearance: none;
   border: 1px solid var(--sa-border-soft);
   background: #fff;
   color: var(--text-default);
   padding: 8px 16px;
   border-radius: 999px;
   font-size: 13px;
   font-weight: 600;
   cursor: pointer;
}
.sa-fsheet-clear { flex: 0 0 auto; }
.sa-fsheet-done  {
   flex: 1 1 auto;
   border-color: var(--color-brand);
   color: #fff;
   background: var(--color-brand);
}

.sa-fsheet-mobile .sa-fsheet-group {
   margin-bottom: 20px;
}


/* Interactive map container — holds the SVG from lib/interactive-map/.
   Position relative so the map's working/loading absolute children
   anchor correctly. SVG sized to 100% via the rule below. */
.sa-rail-map {
   position: relative;
   z-index: 0;            /* sits below `.sa-rail-strip` (z-index: 1) */
   background: var(--sa-bg-soft);
   border-radius: var(--sa-card-radius);
   overflow: hidden;
   /* Mobile sizing lives in the `@media (max-width: 879px)` block below
      and the desktop flex-fill in the `@media (min-width: 880px)` block
      further down. No base height — both contexts override. */
}

/* Release vertical drag to page scroll in browse mode on touch devices.
   `lib/seating-chart/seating-chart.css:44` sets `touch-action: none` on
   `.sc-map > svg` so the chart's JS captures every gesture — great in
   event mode (drag pans the map across ticket markers), bad in browse
   mode (user is mid page-scroll, finger lands on the map, scroll gets
   hijacked into a no-op map pan). When `<main>` is in browse mode AND
   the device has a coarse pointer, override the SVG's touch-action to
   `pan-y` so vertical drag becomes a page scroll instead. Browser-level
   gesture claim → chart's pointer handler receives `pointercancel` and
   bails. Tap (pointerdown + quick pointerup, low movement) still fires
   normally, so the picker open path is preserved. Event mode (no
   `is-browse-mode` class) → rule doesn't apply → drag still pans.
   Coarse-pointer gate keeps desktop mouse-drag behavior unchanged. */
@media (pointer: coarse) {
   main.is-browse-mode .sa-rail-map .sc-map > svg {
      touch-action: pan-y;
   }
}

/* Widescreen rail column → flex column. The column itself is sticky
   100vh from layout.css:662-669; here we lay its children out as
   flex so the banner, top strip, and bottom strip take their natural
   height while `.sa-rail-map` consumes whatever's left. Browse mode
   (bottom strip hidden) → map gets nearly the full column. Event
   mode (bottom strip carrying ticket-suggestion cards) → map auto-
   shrinks by exactly the strip's height. No magic numbers, no
   overflow clipping. `min-height: 0` lets the flex item shrink past
   its content's intrinsic size — the SVG inside is sized via the
   chart's ResizeObserver, so it reflows on each layout change. */
@media (min-width: 880px) {
   main[data-show='panel+map'] [data-layout='map'][data-component='section-rail'] {
      display: flex;
      flex-direction: column;
   }
   main[data-show='panel+map'] [data-layout='map'][data-component='section-rail'] .sa-rail-map {
      flex: 1 1 0;
      min-height: 0;
      height: auto;
   }
}

/* Plugin-event mask. JS-injected as a child of #sa-imap (which is
   already `position: relative`) by SectionRailCtrl._togglePluginOverlay.
   Positions absolutely over the chart, blocks pointer events to the
   chart underneath so any click goes to our CTA. */
.sa-rail-map-plugin-overlay {
   position: absolute;
   inset: 0;
   /* Must outrank every internal chart element. Chart pushes some
      hover/zoom labels to z-index: 99999 (seating-chart.css:182);
      others sit at 100, 1000, etc. 100001 wins unconditionally. */
   z-index: 100001;
   /* Opaque light panel — completely wipes the chart from view so no
      high-z-index hover labels / marker flags can show through.
      Reads as "map area is intentionally blank right now", not as a
      modal mask. */
   background: #f5f6f8;
   border-radius: var(--sa-card-radius);
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   gap: 18px;
   padding: 24px;
   text-align: center;
}
.sa-rail-map-plugin-msg {
   color: var(--color-70, rgba(0,36,72,0.70));
   font-size: clamp(15px, 2.2vw, 18px);
   font-weight: 600;
   line-height: 1.4;
   max-width: 360px;
   margin: 0;
}

/* Browse-mode (no event selected) on widescreen: tuck the map's top edge
   under the translucent strip so the strip reads as floating above the
   map. The chart's viewBox + SVG render stay untouched — only the
   container box shifts. `main.is-browse-mode` is toggled by
   `SectionRailCtrl.mount` + `onEventChanged`. */
@media (min-width: 880px) {
   /* Only tuck when the strip is actually visible. When the active type
      has zero events, `_renderCards` hides `.sa-event-strip` — without
      this `:has()` gate the negative margin would still slide the map up,
      clipping the top-right map controls against whatever sits above
      (heading / chips). */
   main.is-browse-mode:has(.sa-event-strip:not([hidden])) .sa-rail-map {
      margin-top: -40px;
   }
   /* The strip (z-index:1) paints over `.sa-rail-map`'s top 40px in the
      tuck zone (map z-index:0 is its own stacking context — children can't
      escape). Push every map-anchored overlay down by 40px in that scope
      so the edu marquee and the top-right control cluster sit clear of
      the strip's overlap. Adds to each element's own gutter (14px / 12px). */
   main.is-browse-mode:has(.sa-event-strip:not([hidden])) .sa-rail-map .sa-edu-slim-marquee {
      top: 54px;
   }
   main.is-browse-mode:has(.sa-event-strip:not([hidden])) .sa-rail-map .sc-map-controls {
      top: 52px;
   }
}

/* ── Season Explorer edu overlay (browse mode) ─────────────────────────────
   Compact speech-bubble callout overlaid on the top-left of the map area
   (`.sa-rail-map`) with an upward-pointing arrow tail bridging visually
   toward the event strip above — ti.2 `.hint-bubble` + `.arrow-up` parity.
   The whole callout is the hit target (opens the event picker). The pink
   top pill remains in the stylesheet but is currently commented out in JS.
   JS injects the marquee into `#sa-imap` in `SectionRailCtrl.mount`
   AFTER the chart constructor wipes the container. CSS gates visibility on
   `.sa-rail-map.has-edu` so the nodes stay dormant in event mode.

   Inline SVGs replace the lab's `iconify-icon` (not loaded on production).
   `.sa-edu-icon` sizes the svg in line with the lab's `width=""` props. */
/* Pill still descendant-scoped (pill is currently commented out in JS, but
   left here in case it's re-enabled). */
.sa-rail-map .sa-edu-pink-top-pill {
   display: none;
}
.sa-rail-map.has-edu .sa-edu-pink-top-pill {
   display: flex;
}
/* Marquee is injected INSIDE `.sa-rail-map` (`#sa-imap`) as an overlay
   sibling of `.sc-map-wrap`. Hidden by default; visible when the host map
   carries `.has-edu` (browse-mode only — `SectionRailCtrl.onEventChanged`
   toggles the class). */
.sa-rail-map .sa-edu-slim-marquee {
   display: none;
}
.sa-rail-map.has-edu .sa-edu-slim-marquee {
   display: flex;
}

.sa-edu-icon {
   width: 14px;
   height: 14px;
   flex-shrink: 0;
   line-height: 1;
   pointer-events: none;
}

.sa-edu-pink-top-pill {
   position: absolute;
   top: 10px; left: 50%;
   transform: translateX(-50%);
   background: var(--color-primary, #002448);
   color: #fff;
   font-size: 14px;
   font-weight: 700;
   padding: 16px 12px;
   border-radius: 999px;
   align-items: center;
   gap: 6px;
   box-shadow: 0 8px 18px rgba(0, 36, 72, 0.40), 0 2px 4px rgba(7,18,41,0.10);
   white-space: nowrap;
   animation: sa-edu-pink-pill-bob 1.6s ease-in-out infinite;
   z-index: 6;
   pointer-events: auto;
   cursor: pointer;
   border: 0;
   font-family: inherit;
}
@keyframes sa-edu-pink-pill-bob {
   0%, 100% { transform: translateX(-50%) translateY(0); }
   50%      { transform: translateX(-50%) translateY(-5px); }
}
.sa-edu-pink-top-pill--left {
   left: 12px;
   transform: translateX(0);
   animation: sa-edu-pink-pill-bob-left 1.6s ease-in-out infinite;
}
/* Widescreen browse mode shifts the map up by -40px (so the strip floats
   over the map top edge). The pill's default `top: 10px` would land
   BEHIND the strip's bottom edge. Push it past the 40px overlap zone so
   it stays visible below the strip. (Pill itself is currently commented
   out in JS; rule preserved in case it's re-enabled.) */
@media (min-width: 880px) {
   main.is-browse-mode .sa-rail-map .sa-edu-pink-top-pill { top: 50px; }
   /* Marquee no longer pinned to viewport bottom on widescreen — it's now
      an in-flow sibling between the event-strip and the map, so it scrolls
      with the page naturally. Previous `position: fixed` override removed. */
}
@keyframes sa-edu-pink-pill-bob-left {
   0%, 100% { transform: translateX(0) translateY(0); }
   50%      { transform: translateX(0) translateY(-5px); }
}
.sa-edu-pink-top-pill .sa-edu-icon { width: 14px; height: 14px; }

.sa-edu-slim-marquee {
   /* Position:absolute callout overlaid on the top-left of the map area —
      anchors to `.sa-rail-map` (`position: relative`). An upward-pointing
      arrow tail (`::before`) extends above the top edge of the marquee to
      bridge visually toward the event strip above. Modeled on ti.2's
      `.hint-bubble` + `.arrow-up`. `overflow: visible` here lets the tail
      paint outside the rounded rect; the `.sa-edu-smq-fx` child owns the
      clipped glow/sparkles. */
   position: absolute;
   top: 14px;
   left: 14px;
   /* High enough to clear chart-internal layers — flags (z=80-100),
      focus markers, hover cards (z=1000). The marquee + its stacking
      context live inside `.sa-rail-map { z-index: 0 }`, so this value is
      scoped to that context and doesn't affect the strip overlap above. */
   z-index: 1001;
   background: var(--color-primary, #002448);
   border-radius: 14px;
   padding: 11px 14px;
   color: #fff;
   display: flex;
   align-items: center;
   gap: 10px;
   overflow: visible;
   box-shadow: 0 12px 26px rgba(0, 36, 72, 0.40), 0 2px 6px rgba(7,18,41,0.16);
   /* Whole marquee is clickable (opens the event picker). Cursor + hover
      lift give the affordance. */
   cursor: pointer;
   transition: transform 140ms ease;
}
/* Arrow tail pointing UP — CSS triangle, same fill as the marquee bg so it
   reads as part of the same rounded rectangle. Bottom border is the color
   (= triangle points up); top/left/right transparent. Sits at left: 20px so
   it lands roughly under the leading edge of the eyebrow text. */
.sa-edu-slim-marquee::before {
   content: '';
   position: absolute;
   top: -9px;
   left: 20px;
   width: 0;
   height: 0;
   border-style: solid;
   border-width: 0 10px 10px 10px;
   border-color: transparent transparent var(--color-primary, #002448) transparent;
   pointer-events: none;
}
.sa-edu-slim-marquee:hover { transform: translateY(-2px); }
.sa-edu-slim-marquee:active { transform: translateY(0); }
/* FX wrapper — owns the rounded-rect clipping for the glow/sparkles so the
   marquee root can keep `overflow: visible` for the arrow tail. */
.sa-edu-smq-fx {
   position: absolute;
   inset: 0;
   border-radius: 14px;
   overflow: hidden;
   pointer-events: none;
   z-index: 0;
}
.sa-edu-smq-glow {
   position: absolute;
   inset: -40%;
   /* Soft white shimmer on the navy bg. Previous pink stop
      (`rgba(255,180,210,0.40)`) sat invisibly on the cyan-gradient bg but
      reads as a jarring pink blob on `--color-primary`. Both radials now
      use white at low alpha so the rotation reads as a subtle bloom
      rather than colored splotches. */
   background:
      radial-gradient(circle at 20% 30%, rgba(255,255,255,0.18) 0%, transparent 35%),
      radial-gradient(circle at 80% 70%, rgba(255,255,255,0.12) 0%, transparent 35%);
   pointer-events: none;
   animation: sa-edu-mq-glow-spin 14s linear infinite;
}
@keyframes sa-edu-mq-glow-spin {
   0%   { transform: rotate(0deg); }
   100% { transform: rotate(360deg); }
}
.sa-edu-smq-sparkles {
   position: absolute;
   inset: 0;
   pointer-events: none;
   overflow: hidden;
}
.sa-edu-smq-sparkles span {
   position: absolute;
   left: var(--x); top: var(--y);
   width: 4px; height: 4px;
   border-radius: 50%;
   background: #fff;
   transform: scale(0);
   box-shadow: 0 0 6px rgba(255,255,255,0.9);
   animation: sa-edu-mq-twinkle 2.6s ease var(--d, 0s) infinite;
}
@keyframes sa-edu-mq-twinkle {
   0%, 30%   { transform: scale(0); opacity: 0; }
   45%, 60%  { transform: scale(1); opacity: 1; }
   75%, 100% { transform: scale(0); opacity: 0; }
}
.sa-edu-smq-body {
   flex: 1;
   min-width: 0;
   position: relative;
   z-index: 1;   /* above the .sa-edu-smq-fx wrapper (z-index: 0) */
}
.sa-edu-smq-eyebrow {
   display: inline-flex;
   align-items: center;
   gap: 4px;
   font-size: clamp(10px, 1.5vw, 11px);
   font-weight: 700;
   letter-spacing: 0.7px;
   text-transform: uppercase;
   color: #fff;
   line-height: 1;
   margin-bottom: 8px;
}
.sa-edu-smq-eyebrow .sa-edu-icon { width: 13px; height: 13px; }
.sa-edu-smq-head {
   font-size: clamp(14px, 2vw, 16px);
   font-weight: 700;
   letter-spacing: -0.01em;
   line-height: 1.15;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}
/* ── Map hover preview card (event mode, non-touch) ────────────────────────
   Direct port of te.1's `.map-popup-hover` (themes/te.1/lib/styles-map-
   desktop.css ~L17–100). Same class names + DOM shape so visual parity is
   structural — not a bespoke remake. JS lives in
   `InteractiveSeatingMapCtrl._showHoverCard`; CSS lives here. */
.sa-map-hover-card.map-popup-hover {
   position: fixed;
   z-index: 1000;
   pointer-events: none;
   width: 300px;
   background: #fff;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
   font-family: var(--font-family, 'Geist', sans-serif);
   color: #151515;
   animation: sa-mhc-fade 120ms ease-out;
   display: block;       /* override te.1 `display: none` default */
}
.sa-map-hover-card.has-instruction { width: 324px; }
@keyframes sa-mhc-fade {
   from { opacity: 0; transform: translateY(2px); }
   to   { opacity: 1; transform: none; }
}

.sa-map-hover-card .header {
   overflow: hidden;
   line-height: 1.2;
   position: relative;
   border-radius: 12px;
}
.sa-map-hover-card .header img.preview {
   display: block;
   width: 72px;
   height: 72px;
   left: 0;
   float: left;
}
.sa-map-hover-card.has-instruction .header img.preview {
   width: 100%;
   height: 120px;
   object-fit: cover;
   float: none;
}
.sa-map-hover-card .header .header-title {
   padding: 8px 12px;
   overflow: hidden;
   min-height: 72px;
   float: left;
   width: 218px;
}
.sa-map-hover-card.has-instruction .header-title {
   min-height: 96px;
   width: auto;
   float: none;
}
.sa-map-hover-card .header.no-image .header-title {
   padding-left: 10px;
   width: auto;
   float: none;
}

/* Price chip — top-right, white pill, "/ea" suffix. */
.sa-map-hover-card .header-price {
   position: absolute;
   top: 8px;
   right: 8px;
   font-weight: bold;
   font-size: 20px;
   background: white;
   padding: 8px 12px;
   border-radius: 8px;
   text-align: center;
   padding-right: 26px;
   line-height: 1;
   color: #151515;
}
.sa-map-hover-card .header-price::after {
   position: absolute;
   content: "/ea";
   font-size: 12px;
   font-weight: normal;
   bottom: 10px;
   right: 8px;
}

/* Marquee feature line — icon + long-form description ("Best Overall
   Value + View"). Mixed case; the sparkle is the differentiator. */
.sa-map-hover-card .feature {
   color: var(--sc-marquee-pink, #ef356c);
   font-weight: 600;
   font-size: 12px;
   line-height: 1.35;
   margin-bottom: 6px;
   display: flex;
   align-items: baseline;
   gap: 4px;
}
.sa-map-hover-card .ticket-marquee-icon {
   font-size: 13px;
   line-height: 1;
   flex: 0 0 auto;
}
.sa-map-hover-card .ticket-marquee-text {
   flex: 1 1 auto;
}

/* Deal score pill + tier label. Pill colors mirror te.1's
   `.ticket-deal span.ds.{tier}` palette; the trailing tier label is also
   colored (hard green for excellent, medium green for great/good) so the
   line reads as a deal callout, not muted gray running text. */
.sa-map-hover-card .ticket-deal {
   color: #008a00;                 /* te.1 `.ticket-deal` green */
   font-size: 12px;
   font-weight: 500;
   line-height: 1.6;
   margin-bottom: 4px;
}
.sa-map-hover-card .ticket-deal span.ds {
   color: white;
   border-radius: 2px;
   padding: 1px 4px;
   font-size: 11px;
   font-weight: 600;
   margin-right: 4px;
}
.sa-map-hover-card .ticket-deal span.ds.excellent { background: #1A8828; }
.sa-map-hover-card .ticket-deal span.ds.great     { background: #429B46; }
.sa-map-hover-card .ticket-deal span.ds.good      { background: #5fa95d; }
.sa-map-hover-card .ticket-deal span.ds.fair      { background: #FFB61F; }
.sa-map-hover-card .ticket-deal span.ds.ok        { background: #FFB61F; }
.sa-map-hover-card .ticket-deal span.ds.poor      { background: #F34A1C; }
/* Single trailing-label color — `#008a00` like te.1's `.ticket-deal` rule.
   The score pill (above) carries the tier color; the text label is just
   green across all tiers. We never print this line for composite < 70,
   so there's no "poor" / "fair" case to worry about here. */

/* Section + row line. */
.sa-map-hover-card .ticket-section {
   font-size: 14px;
   font-weight: 600;
   color: #151515;
   line-height: 1.3;
   margin-bottom: 2px;
}

/* Qty line. */
.sa-map-hover-card .qtyinfo {
   color: #666;
   font-size: 12px;
   line-height: 1.4;
   margin-bottom: 6px;
}

/* "Click the dot to see all details" — black pill, white text. */
.sa-map-hover-card .ticket-instruction {
   font-weight: 500;
   background: black;
   color: white;
   margin-top: 8px;
   padding: 4px 8px;
   border-radius: 4px;
   display: inline-block;
   font-size: 11px;
   line-height: 1.4;
}

/* Skip the hover card on touch devices — pinch/pan would conflict and
   there's no cursor to anchor on. */
@media (pointer: coarse) {
   .sa-map-hover-card { display: none !important; }
}


/* Legacy .sa-map-rail kept for compatibility; commented-out InteractiveMap
   re-enable will reuse it. Defaults to hidden so the old slot doesn't ship. */
.sa-map-rail {
   display: none;
}


/* ── Sticky event bar — full-width across the top ───────────────────────── */

.sa-sticky-bar {
   position: sticky;
   top: 0;
   z-index: 90;
   width: 100%;
   background: #fff;
   border-bottom: 1px solid var(--sa-border-soft);
   margin: 0 calc(-1 * var(--sa-page-pad-mobile));
   padding: 8px var(--sa-page-pad-mobile);
   /* Reserve exact height to prevent CLS during hydration */
   min-height: var(--sa-sticky-bar-height);
}

.sa-seb-inner {
   display: flex;
   flex-direction: column;
   gap: 6px;
}

@media (min-width: 880px) {
   .sa-seb-inner {
      flex-direction: row;
      align-items: center;
      gap: 16px;
   }
}

.sa-seb-anchor {
   font-size: 14px;
   color: var(--text-default);
   line-height: 1.4;
}

.sa-seb-area {
   font-weight: 600;
}

.sa-seb-floor {
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   margin-left: 4px;
}

.sa-seb-insight {
   color: var(--text-medium, #4b5563);
   margin-left: 4px;
}

.sa-seb-hotbuttons {
   list-style: none;
   margin: 0;
   padding: 0;
   display: flex;
   gap: 8px;
   overflow-x: auto;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: none;
}

.sa-seb-hotbuttons::-webkit-scrollbar { display: none; }

.sa-seb-hotbuttons > li {
   flex: 0 0 auto;
}

.sa-seb-hotbtn {
   display: inline-flex;
   align-items: baseline;
   gap: 6px;
   padding: 6px 12px;
   border: 1px solid var(--sa-border-soft);
   border-radius: 999px;
   background: #fff;
   font-size: 13px;
   cursor: pointer;
   white-space: nowrap;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-seb-hotbtn:hover {
   border-color: var(--color-brand, #0067CE);
}

.sa-seb-hotbtn.is-selected {
   border-color: var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
}

.sa-seb-hotbtn.is-soldout {
   opacity: 0.6;
}

.sa-seb-hotbtn-label {
   font-weight: 500;
}

.sa-seb-hotbtn-price {
   color: var(--color-brand, #0067CE);
   font-weight: 600;
}

.sa-seb-allevents {
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 6px 12px;
   font-size: 13px;
   color: var(--text-medium, #4b5563);
   text-decoration: none;
   white-space: nowrap;
}

.sa-seb-allevents:hover {
   color: var(--color-brand, #0067CE);
}

.sa-seb-fallback {
   align-self: flex-start;
   padding: 6px 12px;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius-sm);
   background: #fff;
   font-size: 13px;
   cursor: pointer;
}


/* Component vertical rhythm comes from the design system's
   `[data-layout='scene'] { margin-block-end: var(--scene-gap); }`
   (lib/base/styles/src/layout.css). Every top-level component carries
   data-layout='scene'. No bespoke section-rhythm rule here. */

.sa-breadcrumbs {
   margin-bottom: 6px;
   /* Single line — `Str::shorten($venue, 16)` keeps long venue names
      from blowing past the row, and `white-space: nowrap; overflow-x: auto`
      lets unusual long crumbs scroll horizontally instead of wrapping
      to a second line (which made the page header look broken on mobile). */
   white-space: nowrap;
   overflow-x: auto;
   scrollbar-width: none;
}
.sa-breadcrumbs::-webkit-scrollbar { display: none; }


/* ── Section title ──────────────────────────────────────────────────────── */

/* h1 sizing/weight/color comes from the design system (lib/base defs.css). */

/* Skeleton placeholder for the picker slot — reserves space to prevent CLS */
.sa-st-skeleton {
   height: 56px;
   margin-top: 16px;
   border-radius: var(--sa-card-radius);
}

/* Inline seatscore — "4.5 ★ - {category} Seats".
   Used by the SectionTitleCtrl picker (single-event row, multi-event card,
   dropdown list items). Format: 13px, 80% primary color per spec.
   Uses data-rr=* so it co-locates semantically with the other rating
   primitives in the design system. */
[data-rr="seatscore-inline"] {
   font-size: 13px;
   color: var(--color-primary-dim);
   line-height: 1.3;
}

/* Single-event mode — used directly under the h1 on venues with one event
   type. Slightly larger (16px) with the "SeatScore™" suffix instead of "Seats". */
[data-rr="seatscore-inline"][data-mode="single"] {
   font-size: 16px;
   font-weight: 600;
}

/* Multi-event card (collapsed picker trigger) */
.sa-st-picker {
   position: relative;
   margin-top: 0;
}

/* Multi-event venues: wrap the picker card in a light outline so it reads
   as an interactive control. Single-event venues skip this (no `.is-multi`)
   since there's nothing to pick. */
.sa-st-picker.is-multi {
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   padding: 6px 10px;
   display: inline-block;
   min-width: 300px;
}

.sa-st-card {
   display: flex;
   align-items: center;
   gap: 12px;
   width: 100%;
   border: 0;
   border-radius: 0;
   background: transparent;
   text-align: left;
   cursor: pointer;
   transition: opacity 0.15s ease, border-color 0.15s ease;
   max-width: 360px;
}


.sa-st-card:hover { opacity: 0.85; }
.sa-st-card.is-open { opacity: 0.85; }

/* Single-event venues use the same avatar + two-line body, but it isn't
   interactive — no cursor change, no hover dim, no chevron. */
.sa-st-card.is-static {
   cursor: default;
}
.sa-st-card.is-static:hover { opacity: 1; }

.sa-st-card-avatar {
   flex: 0 0 auto;
   width: 36px;
   height: 36px;
   border-radius: 8px;
   display: inline-flex;
   align-items: center;
   justify-content: center;
}

.sa-st-card-avatar i[data-is="icon"] {
   --icon-size: 16px;
}

.sa-st-card-body {
   flex: 0 1 auto;        /* don't push the chevron to the far right */
   min-width: 0;
   display: flex;
   flex-direction: column;
   justify-content: center;
   gap: 2px;
   padding-right:24px;
}

/* Title-only treatment (no score) — center the title vertically */
.sa-st-card.is-titleonly .sa-st-card-body,
.sa-st-list-item.is-titleonly .sa-st-card-body {
   justify-content: center;
}

.sa-st-card-title {
   font-size: 15px;
   font-weight: 600;
   color: var(--text-default);
   line-height: 1.2;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
}

/* Chevron sits inside a light circular wrapper on the interactive
   (non-static) picker card. The wrapper rotates on .is-open so the
   chevron flips in place. */
.sa-st-card-chevron-wrap {
   flex: 0 0 auto;
   width: 24px;
   height: 24px;
   border-radius: 50%;
   background: var(--sa-bg-soft, #f3f4f6);
   display: inline-flex;
   align-items: center;
   justify-content: center;
   transition: transform 0.15s ease, background 0.15s ease;
position: absolute;
    right: 8px;   
}

.sa-st-card:hover .sa-st-card-chevron-wrap {
   background: #e5e7eb;
}

.sa-st-card.is-open .sa-st-card-chevron-wrap {
   transform: rotate(180deg);
}

.sa-st-card-chevron {
   color: var(--text-low, #6b7280);
}

.sa-st-card-chevron i[data-is="icon"],
.sa-st-card-chevron-wrap i[data-is="icon"] {
   --size: 14px;
}

/* Avatar background tints — reuse ESB vars from lib/base/styles/src/events.css */
.sa-st-card-avatar.bg-baseball   { background: var(--bg-baseball);   color: var(--text-baseball); }
.sa-st-card-avatar.bg-basketball { background: var(--bg-basketball); color: var(--text-basketball); }
.sa-st-card-avatar.bg-hockey     { background: var(--bg-hockey);     color: var(--text-hockey); }
.sa-st-card-avatar.bg-football   { background: var(--bg-football);   color: var(--text-football); }
.sa-st-card-avatar.bg-soccer     { background: var(--bg-soccer);     color: var(--text-soccer); }
.sa-st-card-avatar.bg-concert    { background: var(--bg-concert);    color: var(--text-concert); }
.sa-st-card-avatar.bg-theater    { background: var(--bg-theater);    color: var(--text-theater); }
.sa-st-card-avatar.bg-fighting   { background: var(--bg-fighting);   color: var(--text-fighting); }
.sa-st-card-avatar.bg-softball   { background: var(--bg-softball);   color: var(--text-softball); }
.sa-st-card-avatar.bg-other      { background: var(--bg-other);      color: var(--text-other); }

/* Dropdown (desktop) */
/* Portaled to <body> by SectionTitleCtrl._openDropdown — position/top/left/
   width/z-index are set as inline styles via getBoundingClientRect() on the
   picker card. We only style the surface here. */
.sa-st-dropdown {
   padding: 6px;
   background: #fff;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

/* Dropdown scrim moved to the shared `.ui-dropdown-backdrop` +
   `.ui-dropdown-elevated` primitives in lib/base/styles/src/extras.css.
   SectionTitleCtrl applies both when opening the desktop dropdown. */

/* List items shared between dropdown + bottom sheet */
.sa-st-list {
   display: flex;
   flex-direction: column;
   gap: 2px;
}

.sa-st-list-item {
   display: flex;
   align-items: center;
   gap: 12px;
   width: 100%;
   padding: 8px 10px;
   border: 0;
   background: transparent;
   text-align: left;
   cursor: pointer;
   border-radius: var(--sa-card-radius-sm);
   transition: background 0.15s ease;
}

.sa-st-list-item:hover { background: var(--sa-bg-soft); }
/* Active-state styling intentionally removed — picker doesn't need a
   "selected" indicator (no grey bg, no checkmark) per design. */


/* =============================================================
   Ratings & Reviews — [data-scene="ratings-reviews"]
   Pulled verbatim from the seating-areas archive (failed test) so
   the data-rr=* selectors in views/ratings-reviews.php +
   views/section-rating.php + views/questions.php render as designed.
   ============================================================= */

[data-scene="questions"],
[data-scene="ratings-reviews"] {
   display: flex;
   flex-direction: column;
}

[data-rr="header"] {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   flex-wrap: wrap;
   gap: 8px;
   margin-block-end: calc(var(--scene-gap, 36px) * 0.75);
}

[data-rr="title"] {
   margin: 0 !important;
}

[data-rr="event-type-toggle"] {
   display: flex;
   align-items: center;
   gap: 0.35em;
   white-space: nowrap;
   width: max-content;
}

[data-rr="event-type-select"] {
   border: none;
   /* Custom chevron — iPad / iOS Safari strip the native arrow on a
      transparent-background <select>, leaving the dropdown looking
      static. Inline SVG chevron as background-image renders consistently
      across iOS, Android, and desktop. `appearance: none` prevents the
      OS from drawing its own arrow on top of ours. */
   appearance: none;
   -webkit-appearance: none;
   background-color: transparent;
   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 fill='none' stroke='%23002448' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
   background-repeat: no-repeat;
   background-position: right center;
   background-size: 10px 6px;
   padding: 0 16px 0 0;
   cursor: pointer;
   font: inherit;
   font-weight: bold;
}

[data-rr="event-type-static"] {
   font-weight: bold;
}


/* SeatScore Billboard — populated by JS via data-reactive-id="seatscore" */
[data-scene="seatscore-billboard"] {
   display: flex;
   flex-direction: row;
   gap: 40px;
   flex-wrap: wrap;
}

[data-rr="seatscore-block"] {
   display: flex;
   flex-direction: column;
   flex-shrink: 0;
}

[data-rr="seatscore-rating"] {
   display: flex;
   flex-direction: row;
   gap: 15px;
}

[data-rr="seatscore-number"] {
   font-weight: 700;
   line-height: 1;
   font-size: 36px;
}

[data-rr="seatscore-meta"] {
   display: flex;
   flex-direction: column;
   gap: 0.15em;
}

[data-rr="seatscore-tm"] {
   letter-spacing: 0.04em;
   font-size: 12px;
   color: var(--text-low, #6b7280);
}

[data-rr="seatscore-category"] {
   font-weight: bold;
   font-size: 16px;
}

[data-rr="seatscore-stars"] [data-is='icon-group'][data-group='stars'] {
   font-size: 28px;
}


/* Right column: meter bars */
[data-rr="meter-bars"] {
   display: flex;
   flex-direction: column;
   gap: 8px;
   flex: 1;
   min-width: 180px;
   max-width: 360px;
}

[data-rr="meter-row"] {
   display: flex;
   align-items: center;
   gap: 12px;
}

[data-rr="meter-label"] {
   width: 96px;
   flex-shrink: 0;
}

[data-rr="meter-track"] {
   flex: 1;
   height: 8px;
   background: #e5e7eb;
   border-radius: 9999px;
   overflow: hidden;
   display: block;
}

[data-rr="meter-fill"] {
   display: block;
   height: 100%;
   background: #FF6600;
   border-radius: 9999px;
   transition: width 0.4s ease;
}

@media (max-width: 600px) {
   [data-scene="seatscore-billboard"] {
      flex-direction: column;
      align-items: flex-start;
      gap: 20px;
   }
   [data-rr="meter-bars"] {
      width: 100%;
      max-width: 100%;
   }
}


/* Expert Reviews */
[data-scene="expert-reviews"] {
   border-left: 4px solid #3B5EA6;
   background: #f0f4ff;
   border-radius: 0 12px 12px 0;
   padding: 24px;
}

[data-rr="expert-header"] {
   display: flex;
   gap: 8px;
}

[data-rr="expert-icon"] {
   flex-shrink: 0;
}

[data-rr="expert-title"] {
   margin: 0;
}

[data-rr="expert-body"] {
   display: flex;
   flex-direction: column;
   gap: 20px;
   padding-left: 24px;
}

[data-rr="expert-item-inner"] > * {
   display: inline;
}

[data-rr="expert-item-title"] {
   margin: 0 0 0.25em;
   font-weight: bold;
}

[data-rr="expert-item-inner"] {
   overflow: hidden;
   display: -webkit-box;
   -webkit-line-clamp: 2;
   -webkit-box-orient: vertical;
   margin-bottom: 6px;
}

[data-rr="expert-read-more"] {
   display: inline-flex;
   align-items: center;
   gap: 0.2em;
   font-weight: bold;
   margin-top: 8px;
}


/* Fan Reviews */
[data-rr="fan-title"] {
   margin: 0;
}

/* Single-card constraint: don't let one review stretch to full panel width */
[data-rr="single-card"] rys-slider { max-width: 480px; }

[data-rr="fan-item"] {
   display: flex;
   flex-direction: column;
   height: 100%;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius, 10px);
   background: #fff;
   overflow: hidden;
   cursor: pointer;
   transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

[data-rr="fan-item"]:hover {
   border-color: var(--text-low, #9ca3af);
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

/* ── Card header: stars or "Fan Feedback" label ── */

[data-rr="fan-item-header"] {
   padding: 12px 14px 0;
}

[data-rr="fan-item-header"] [data-is='icon-group'][data-group='stars'] {
   font-size: 20px;
}

[data-rr="fan-item-label"] {
   font-size: 11px;
   font-weight: 600;
   letter-spacing: 0.04em;
   text-transform: uppercase;
   color: var(--text-low, #6b7280);
}

/* ── Card body: caption + comments, clamped at 5 lines ── */

[data-rr="fan-item-body"] {
   padding: 4px 14px 0;
   flex: 1 1 auto;
   max-height: calc(4 * 1.5 * 16px);
   margin-bottom: 12px;
   overflow: hidden;
}

[data-rr="fan-item-body"] p {
   margin: 0;
   font-size: 14.8px;
   line-height: 1.5;
   color: var(--color-80);
}

[data-rr="fan-item-headline"] {
   font-size: 14.8px;
   font-weight: 600;
   color: var(--text-default, #111827);
   margin-right: 0.25em;
}
[data-rr="fan-item-headline"]:hover {
   text-decoration: underline;
}


/* ── Card footer: meta left, read more right ── */

[data-rr="fan-item-footer"] {
   display: flex;
   justify-content: space-between;
   align-items: center;
   padding: 10px 14px;
   margin-top: auto;
   font-size: 13px;
}

[data-rr="fan-item-meta"] {
   color: var(--text-low, #6b7280);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
   min-width: 0;
}

[data-rr="fan-item-readmore"] {
   color: var(--text-low, #6b7280);
   font-weight: 500;
   white-space: nowrap;
   flex-shrink: 0;
   margin-left: 12px;
}
[data-rr="fan-item-readmore"]:hover {
   color: var(--text-default);
   text-decoration: underline;
}

[data-rr="fan-read-more"] {
   display: inline-flex;
   align-items: center;
   gap: 0.2em;
   font-weight: bold;
   margin-top: 4px;
}


/* ── Q&A cards (rys-slider) ─────────────────────────────────────────────── */

/* Single-card constraint */
[data-qa="single-card"] rys-slider { max-width: 480px; }

[data-qa="card"] {
   display: flex;
   flex-direction: column;
   height: 100%;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius, 10px);
   background: #fff;
   overflow: hidden;
   cursor: pointer;
   transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

[data-qa="card"]:hover {
   border-color: var(--text-low, #9ca3af);
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

[data-qa="card-header"] {
   padding: 14px 14px 0;
}

[data-qa="card-question"] {
   font-size: 16px;
   font-weight: 600;
   line-height: 1.35;
   color: var(--text-default, #111827);
}
[data-qa="card-question"]:hover {
   text-decoration: underline;
}

[data-qa="card-body"] {
   padding: 6px 14px 0;
   flex: 1 1 auto;
   margin-bottom: 12px;
}

/* Clamp the answer preview at 4 lines with an ellipsis on the last visible
   line. Full Q&A stays in the DOM (for SEO) — only the visual preview is
   trimmed. */
[data-qa="card-answer"] {
   font-size: 15px;
   line-height: 1.5;
   color: var(--color-80);
   display: -webkit-box;
   -webkit-line-clamp: 4;
   line-clamp: 4;
   -webkit-box-orient: vertical;
   overflow: hidden;
}

/* Hide figures/images in the card preview — full answer stays in DOM for SEO */
[data-qa="card-answer"] figure,
[data-qa="card-answer"] img {
   display: none;
}

[data-qa="card-footer"] {
   display: flex;
   justify-content: space-between;
   align-items: center;
   padding: 10px 14px;
   margin-top: auto;
   font-size: 13px;
}

[data-qa="card-meta"] {
   color: var(--text-low, #6b7280);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
   min-width: 0;
}

[data-qa="card-readmore"] {
   color: var(--text-low, #6b7280);
   font-weight: 500;
   white-space: nowrap;
   flex-shrink: 0;
   margin-left: 12px;
}
[data-qa="card-readmore"]:hover {
   color: var(--text-default);
   text-decoration: underline;
}


/* ── Section hero (seat view + raised picker card + Up Next) ──────────────
   Replaces section-tabs. The image is edge-to-edge (bleeds past the panel's
   horizontal padding via negative margins). A raised white card overlaps
   the bottom of the image by exactly 40px (card is 80px tall = 40px on,
   40px off). Up Next renders the next two events in a compact card style. */
.sa-hero {
   margin-top: 0px;
}

.sa-hero-image {
   position: relative;
   margin: 0 calc(var(--sa-page-pad-mobile, 16px) * -1);
   height: 320px;     /* prev 200px + 40 (Keith's "40px taller than prev spec") */
   overflow: hidden;
   border-radius: 0;
   background: var(--sa-bg-soft, #f3f4f6);
}

@media (min-width: 480px) {
   .sa-hero-image { max-height: 44vh; height: unset;}    /* prev 240px + 40 */

}

@media (min-width: 880px) {
   .sa-hero-image {
      margin: 0 calc(var(--sa-page-pad-desktop, 24px) * -1);
   }
}

.sa-hero-slide img{
   aspect-ratio: 4/3;
}

.sa-hero-image img {
   display: block;
   width: 100%;
   height: 100%;
   object-fit: cover;
   object-position: center;
   border-radius: 0;     /* override any global img radius */
}

.sa-hero-image-empty {
   background: linear-gradient(180deg, #e5e7eb 0%, #f3f4f6 100%);
}

/* Multi-photo slider — CSS scroll-snap track with overlapping prev/next
   buttons. Zero gap between slides, no border-radius on photos. */
.sa-hero-slider {
   position: relative;
}

.sa-hero-slider-track {
   display: flex;
   flex-direction: row;
   gap: 0;
   width: 100%;
   height: 100%;
   overflow-x: auto;
   overflow-y: hidden;
   scroll-snap-type: x mandatory;
   scroll-behavior: smooth;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: none;
}

.sa-hero-slider-track::-webkit-scrollbar { display: none; }

.sa-hero-slide {
   flex: 0 0 100%;
   width: 100%;
   height: 100%;
   margin: 0;
   position: relative;
   scroll-snap-align: start;
   scroll-snap-stop: always;
   cursor: pointer;
}

.sa-hero-slide img {
   display: block;
   width: 100%;
   height: 100%;
   object-fit: cover;
   object-position: center;
   border-radius: 0;
   transition: transform 0.4s ease, filter 0.2s ease;
}

/* Desktop hover feedback — subtle zoom + dim. The nav buttons sit above
   the slide with their own pointer-events:auto, so hovering on a button
   doesn't trigger this. */
@media (hover: hover) and (pointer: fine) {
   .sa-hero-slide:hover img {
      transform: scale(1.015);
      filter: brightness(0.96);
   }
}

/* Single-image (no slider) variant — same click + hover treatment. */
.sa-hero-image[data-trigger="gallery"] { cursor: pointer; }

@media (hover: hover) and (pointer: fine) {
   .sa-hero-image[data-trigger="gallery"] img {
      transition: transform 0.4s ease, filter 0.2s ease;
   }
   .sa-hero-image[data-trigger="gallery"]:hover img {
      transform: scale(1.015);
      filter: brightness(0.96);
   }
}

/* Overlapping nav — 32px black-transparent circle, white SVG arrow.
   Hidden at the boundaries (SectionHeroCtrl toggles `hidden`). */
.sa-hero-slider-btn {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   z-index: 2;
   width: 32px;
   height: 32px;
   border: 0;
   border-radius: 50%;
   background-color: rgba(0, 0, 0, 0.55);
   background-repeat: no-repeat;
   background-position: center;
   background-size: 16px 16px;
   cursor: pointer;
   padding: 0;
   transition: background-color 0.15s ease, opacity 0.15s ease;
}

.sa-hero-slider-btn[hidden] { display: none; }
.sa-hero-slider-btn:hover  { background-color: rgba(0, 0, 0, 0.75); }
.sa-hero-slider-btn:active { background-color: rgba(0, 0, 0, 0.85); }

.sa-hero-slider-prev {
   left: 10px;
   background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='m10.8 12l3.9 3.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275l-4.6-4.6q-.15-.15-.212-.325T8.425 12t.063-.375t.212-.325l4.6-4.6q.275-.275.7-.275t.7.275t.275.7t-.275.7z'/%3E%3C/svg%3E");
}

.sa-hero-slider-next {
   right: 10px;
   background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12.6 12L8.7 8.1q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.6 4.6q.15.15.213.325t.062.375t-.062.375t-.213.325l-4.6 4.6q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7z'/%3E%3C/svg%3E");
}

/* "See all photos" final slide in the hero — reuses the .sa-photo-more-*
   primitives from section-tabs but strips their card-radius (hero is
   edge-to-edge, no rounding). */
.sa-hero-slide.sa-photo-more-slide {
   cursor: pointer;
}

.sa-hero-slide .sa-photo-more-overlay {
   border-radius: 0;
}


/* Caption — top-left over the image. White text on a translucent dark
   pill so it's legible against any photo. */
.sa-hero-caption {
   position: absolute;
   bottom: 32px;
   right: 14px;
   max-width: calc(100% - 28px);
   padding: 6px 12px;
   background: rgba(0, 0, 0, 0.55);
   color: #fff;
   font-size: 12px;
   font-weight: 600;
   line-height: 1.2;
   border-radius: 6px;
   backdrop-filter: blur(8px);
}


/* ── Seat Views scene ─────────────────────────────────────────────────────
   The h2 "Seat Views" scene that replaces the prior edge-to-edge hero.
   Reuses the .sa-hero-slider* track + .sa-hero-slider-btn nav for
   one-slide-per-page scroll-snap behaviour and overlapping prev/next
   buttons, then layers in:
     - 6px rounded corners on photos (vs the hero's edge-to-edge zero radius)
     - Lives inside panel padding (no negative-margin bleed)
     - Caption rendered bottom-left via data-pattern="photo-caption"
       (shared lib/vibes/content/styles/src/defs.css pattern)
   Container uses aspect-ratio so it scales with panel width while keeping
   photos consistent. */

.sa-seat-views .sa-sv-slider {
   position: relative;
   aspect-ratio: 1.71;
   max-height: 44vh;
   overflow: hidden;
   border-radius: 6px;
}

.sa-seat-views .sa-sv-slider.sa-photo-has-picker {
   aspect-ratio: 1.5;
}

/* Same picker-aware sizing for the zone cover figure — give the photo
   enough vertical room that the overlaid picker (~52px tall card +
   8px inset) doesn't crowd the focal point. Base `.sa-zone-cover img`
   uses a `clamp(200px, 32vw, 280px)` height; when the picker overlays
   it, the lower bound (200px on narrow widths) is too tight. Switch to
   the same `1.43` aspect-ratio the seat-views slider uses for parity
   and let the img fill 100% of the host so the transform-based focal-
   point shift (further down) can still center the visible window. */
.sa-zone-cover.sa-photo-has-picker {
   aspect-ratio: 1.5;
}
.sa-zone-cover.sa-photo-has-picker img {
   height: 100%;
}

/* When the picker is overlaid on the lead photo, shift the image's focal
   point down so the picker-uncovered area below shows the photo's natural
   center. Plain `object-position: 50% calc(50% + 48px)` doesn't work alone:
   `object-fit: cover` only produces VERTICAL excess (to clip) when the
   image's aspect is taller than the container's. A 16:9 photo in this
   container has only HORIZONTAL excess, so any Y offset leaves a gap at
   the top. The transform-based approach below works for any image aspect:
   scale up to create symmetric vertical excess, then translateY shifts
   the visible window down into the uncovered region. The scale buffer
   (1.3 = 15% each side) is sized to exceed the translate (10% of the
   image's own height ≈ 13% of container height) so there's no gap. */
.sa-seat-views .sa-sv-slider.sa-photo-has-picker .sa-sv-slide img,
.sa-seat-views .sa-sv-photo.sa-photo-has-picker img,
.sa-zone-cover.sa-photo-has-picker img {
   transform: scale(1.1) translateY(4%);
   transform-origin: center;
}

.sa-seat-views .sa-sv-slide {
   border-radius: 6px;
   overflow: hidden;
}

/* Override the hero's `border-radius: 0` on slide images. */
.sa-seat-views .sa-sv-slide img {
   border-radius: 6px;
}

/* Single-photo variant — no slider, same rounded photo + bottom-left caption. */
.sa-seat-views .sa-sv-photo {
   position: relative;
   display: block;
   aspect-ratio: 4 / 3;
   max-height: 44vh;
   overflow: hidden;
   border-radius: 6px;
}

.sa-seat-views .sa-sv-photo img {
   display: block;
   width: 100%;
   height: 100%;
   object-fit: cover;
   object-position: center;
   border-radius: 6px;
}

/* "See all photos" tail slide — strip the rounded look on the inner overlay
   so the dark mask fills the rounded slide cleanly (the slide's own
   border-radius + overflow:hidden does the clipping). */
.sa-seat-views .sa-photo-more-slide .sa-photo-more-overlay {
   border-radius: 0;
}


/* ── Key Insights scene ───────────────────────────────────────────────────
   Top-level scene rendering of ContentPackage's `insights`. Reuses the
   .sa-keyinfo-* tile primitives but strips the horizontal padding the
   tabs-panel version uses — at scene level we're already inside the panel
   padding and don't want to double-inset. Per Keith 2026-05-17, no colored
   background card and no CTA footer (vs the archive's _renderInsights). */
[data-scene='key-insights'] .sa-keyinfo-grid {
   padding: 0;
   padding-top: 6px;
}

/* Row modifier on a staff-pick insight (e.g., "Rows 12-18"). Falls to its
   own line under the headline; smaller + duller than the headline text. */
.sa-keyinfo-text .sa-keyinfo-rows {
   display: block;
   margin-top: 2px;
   font-size: 11px;
   font-weight: 500;
   color: var(--color-70);
}


/* Raised picker card — overlaps the image by exactly 40px. The card holds
   title + trigger + education in a single white bordered block. The 80px
   spec refers to the "raised/elevated" zone (the top 80px that's lifted
   above the panel's normal flow — the 40px above the image's bottom edge
   plus 40px below it). Card itself grows for content. */
.sa-hero-card {
   --sa-hero-trigger-border: rgba(0, 36, 72, 0.65);  /* primary @ 65% */
   position: relative;
   z-index: 2;
   margin-top: -8px;
   background: #fff;
   border-radius: 12px;
   padding: 14px 16px 16px;
   margin-inline: calc(-1 * 16px);
}

.sa-hero-card-default,
.sa-hero-card-selected {
   display: flex;
   flex-direction: column;
   gap: 10px;
}

.sa-hero-card-default[hidden],
.sa-hero-card-selected[hidden] { display: none; }

.sa-hero-card-title {
   font-size: clamp(11px, 1.5vw, 12px);
   font-weight: 600;
   color: var(--color-primary-subtitle);   /* design-system token: primary @ 70% */
   line-height: 1.25;
}

/* Picker trigger — two-line layout (title bold on top, sub muted below)
   with a paler primary-color border (rgba). Calendar icon on the left,
   chevron on the right. */
.sa-hero-picker {
   appearance: none;
   width: 100%;
   display: flex;
   align-items: center;
   gap: 12px;
   border: 2px solid var(--sa-hero-trigger-border);
   background: #fff;
   border-radius: 10px;
   padding: 9px 13px;
   cursor: pointer;
   text-align: left;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-hero-picker:hover {
   border-color: var(--color-primary, #002448);
}

.sa-hero-picker-icon {
   flex: 0 0 auto;
   width: 20px;
   height: 20px;
   color: var(--color-primary, #002448);
}

.sa-hero-picker-text {
   flex: 1;
   min-width: 0;
   display: flex;
   flex-direction: column;
   gap: 2px;
   overflow: hidden;
}

.sa-hero-picker-title {
   font-size: 17px;
   font-weight: 700;
   color: var(--color-primary, #002448);
   line-height: 1.2;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.sa-hero-picker-sub {
   font-size: 12px;
   color: var(--text-low, #6b7280);
   line-height: 1.2;
   white-space: nowrap;
}

.sa-hero-picker-chevron {
   flex: 0 0 auto;
   width: 16px;
   height: 16px;
   color: var(--color-primary, #002448);
   opacity: 0.6;
}

.sa-hero-edu {
   margin: 0;
   font-size: 13px;
   font-weight: 600;
   line-height: 1.45;
   color: var(--color-primary-subtitle);
}


/* Selected-event state — matches `_design-references/selected event.png`.
   White card stays white; selection is communicated via the SELECTED EVENT
   eyebrow + circle close button, large event name, long-form date/time,
   bold underlined $X lowest-price row, and a full-width "See All Tickets"
   CTA pill. */

.sa-hero-card-selected {
   gap: 8px;
}

.sa-hero-sel-head {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 8px;
}

.sa-hero-sel-eyebrow {
   font-size: clamp(11px, 1.5vw, 12px);
   font-weight: 600;
   letter-spacing: 0.06em;
   color: var(--color-primary-subtitle);
}

.sa-hero-sel-close {
   appearance: none;
   width: 28px;
   height: 28px;
   border-radius: 50%;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   background: #fff;
   color: var(--color-primary-subtitle);
   font-size: 18px;
   line-height: 1;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   cursor: pointer;
   transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sa-hero-sel-close:hover {
   background: var(--sa-bg-soft, #f3f4f6);
   color: var(--color-primary, #002448);
}

.sa-hero-sel-name {
   font-size: 18px;
   font-weight: 700;
   color: var(--color-primary, #002448);
   line-height: 1.2;
   letter-spacing: -0.2px;
}

.sa-hero-sel-when {
   font-size: 13px;
   color: var(--color-primary-subtitle);
   line-height: 1.3;
   /* Cancel the parent .sa-hero-card-selected gap (8px) so the date sits
      flush under the event name as one block. All other gaps in the
      card stay at their 8px spacing. */
   margin-top: -8px;
}

.sa-hero-sel-price {
   margin-top: 6px;
   display: flex;
   flex-direction: column;
   gap: 4px;
}

.sa-hero-sel-price-line {
   display: flex;
   align-items: baseline;
   gap: 8px;
}

.sa-hero-sel-price-amount {
   font-size: 18px;
   font-weight: 700;
   color: var(--text-default);
   text-decoration: underline;
   text-decoration-thickness: 2px;
   text-underline-offset: 3px;
}
/* No-tickets-in-scope state: amount is blank, only the label renders. */
.sa-hero-sel-price-line .sa-hero-sel-price-amount:empty {
   display: none;
}

.sa-hero-sel-price-label {
   font-size: 13px;
   color: var(--color-primary-subtitle);
}
.sa-hero-sel-price-scope {
   color: var(--color-70);
   font-size: 12px;
}

a.sa-hero-sel-cta {
   appearance: none;
   display: block;
   box-sizing: border-box;
   width: 100%;
   margin-top: 12px;
   padding: 14px 16px;
   border: 0;
   border-radius: 999px;
   background: var(--color-brand, #0067CE);
   color: #fff;
   font-size: 15px;
   font-weight: 600;
   text-align: center;
   text-decoration: none;
   cursor: pointer;
   transition: background 0.15s ease;
}

.sa-hero-sel-cta:hover { background: #0056b3; color: #fff; text-decoration: none; }
.sa-hero-sel-cta:active { background: #004a99; color: #fff; }

/* Available Tickets list — populated by SectionComparePricesCtrl.onTicketsLoaded.
   Each row is a button that opens TicketModal on click. */
.sa-hero-sel-available {
   /* no border/padding here — the panel-bottom wrapper above provides
      the visual separation now. */
}
.sa-hero-sel-available-title {
   margin: 0 0 8px;
   font-size: 14px;
   font-weight: 700;
   color: var(--text-default);
}
/* Pill toggle between current section + all sections */
.sa-hero-sel-available-toggle {
   display: inline-flex;
   gap: 0;
   margin-bottom: 12px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 999px;
   padding: 2px;
   background: var(--sa-bg-soft, #f5f6f8);
}
.sa-hero-sel-toggle-btn {
   appearance: none;
   border: 0;
   background: transparent;
   color: var(--color-70);
   font: inherit;
   font-size: 12px;
   font-weight: 600;
   padding: 6px 14px;
   border-radius: 999px;
   cursor: pointer;
   transition: background 120ms ease, color 120ms ease;
   white-space: nowrap;
}
.sa-hero-sel-toggle-btn:hover { color: var(--text-default); }
.sa-hero-sel-toggle-btn.is-active {
   background: #fff;
   color: var(--text-default);
   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
/* "See all tickets →" link below the all-sections list. Matches the
   pagination's bordered breathing room so the bottom of the section has
   a consistent rhythm whether the list is paginated or capped + linked. */
.sa-hero-sel-available-seeall {
   display: block;
   margin-block-start: 16px;
   padding-block-start: 12px;
   border-block-start: 1px solid var(--outline-color, #E5E5E5);
   font-size: 13px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   text-decoration: none;
   text-align: center;
}
.sa-hero-sel-available-seeall:hover { text-decoration: underline; }

/* Pagination controls — section/zone-mode Available Tickets list when
   more than 10 in-scope tickets exist. Visually identical to the bottom
   event list's `.sa-evlist-pagination` so users learn one pattern. */
.sa-hero-sel-available-pagination {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   margin-block-start: 16px;
   padding-block-start: 12px;
   border-block-start: 1px solid var(--outline-color, #E5E5E5);
}
.sa-hero-sel-available-page-info {
   font-size: 13px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
   text-align: center;
   flex: 1 1 auto;
}
.sa-hero-sel-available-page-btn {
   appearance: none;
   border: 1px solid var(--outline-color, #E5E5E5);
   background: #fff;
   color: var(--color-primary, #002448);
   font-size: 13px;
   font-weight: 500;
   padding: 8px 14px;
   border-radius: 999px;
   cursor: pointer;
   flex: 0 0 auto;
   transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.sa-hero-sel-available-page-btn:hover:not(:disabled) {
   background: var(--color-primary, #002448);
   color: #fff;
   border-color: var(--color-primary, #002448);
}
.sa-hero-sel-available-page-btn:disabled {
   opacity: 0.4;
   cursor: not-allowed;
}
@media (max-width: 480px) {
   .sa-hero-sel-available-pagination {
      gap: 8px;
   }
   .sa-hero-sel-available-page-btn {
      padding: 6px 10px;
      font-size: 12px;
   }
   .sa-hero-sel-available-page-info {
      font-size: 12px;
   }
}
.sa-hero-sel-available-list {
   list-style: none;
   margin: 0;
   padding: 0;
   display: flex;
   flex-direction: column;
   gap: 4px;
   
}

.sa-explore-overlay .sa-hero-sel-available-list{
min-height: 300px;
}

.sa-hero-sel-available-row {
   appearance: none;
   width: 100%;
   display: flex;
   align-items: center;
   gap: 12px;
   padding: 10px 12px;
   background: transparent;
   border: 1px solid transparent;
   border-radius: 8px;
   text-align: left;
   font: inherit;
   color: inherit;
   cursor: pointer;
   transition: background 0.12s ease, border-color 0.12s ease;
}
.sa-hero-sel-available-row:hover {
   background: var(--sa-bg-soft, #f7f8fa);
   border-color: var(--sa-border-soft, #e5e7eb);
}
.sa-hero-sel-available-row-main {
   flex: 1 1 auto;
   min-width: 0;
   display: flex;
   flex-direction: column;
   gap: 2px;
}
.sa-hero-sel-available-row-name {
   font-size: 14px;
   font-weight: 600;
   color: var(--text-default);
   line-height: 1.2;
}
.sa-hero-sel-available-row-qty {
   font-size: 12px;
   font-weight: 500;
   color: var(--color-70);
   line-height: 1.2;
}
.sa-hero-sel-available-deal {
   flex: 0 0 auto;
}
.sa-hero-sel-available-deal .ds {
   color: #fff;
   border-radius: 2px;
   padding: 2px 5px;
   font-size: 10px;
   font-weight: 700;
}
.sa-hero-sel-available-row-price {
   flex: 0 0 auto;
   font-size: 15px;
   font-weight: 700;
   color: var(--text-default);
}


/* ── Event picker modal (desktop) ──────────────────────────────────────────
   ESB-style month-grouped event list. Inner list is rendered by
   EventsManager.renderEventList() — its own .el-* classes already live in
   lib/base/styles/src/events.css; we just style the modal chrome. */
.sa-event-picker-modal {
   position: fixed;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   z-index: 160;
   /* Widescreen: lock the size so the picker doesn't bounce as filters
      change. Min-width keeps it readable on smaller-but-still-desktop
      viewports; max-width prevents it from blowing out on very wide
      screens; 80vh fixed height. The 92vw cap keeps narrow viewports
      from clipping (desktop modal only opens above 768px, so 600px
      min-width is safe). */
   width: min(720px, 92vw);
   min-width: min(600px, 92vw);
   height: 80vh;
   max-height: 80vh;
   display: flex;
   flex-direction: column;
   background: #fff;
   border-radius: 12px;
   box-shadow: 0 20px 60px rgba(0, 0, 0, 0.24);
   overflow: hidden;
}

/* Fixed header: title row + (optional) chip row. Nothing inside the
   body needs to be sticky — months pin to the body's own scroll. */
.sa-event-picker-head {
   flex: 0 0 auto;
   display: flex;
   flex-direction: column;
   border-bottom: 1px solid var(--sa-border-soft, #e5e7eb);
   background: #fff;
}

.sa-event-picker-titlerow {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 10px;
   padding: 14px 18px;
}

/* Optional brief message under the title — set when the picker is
   opened from a source that wants to explain WHY ("Select your event
   to see the correct seating chart..."). Source-aware callers pass
   `briefMessage` to `_openEventList`.
   Visual treatment mirrors `.sa-rail-qty-hint` — light primary-tinted
   background with a 3px left accent border so it reads as a
   contextual callout, not body copy. The header row keeps its 18px
   horizontal padding for the title/close; the brief gets its OWN
   margin-inline so the left border isn't crowded by the parent
   padding. */
.sa-event-picker-brief {
   display: block;
   margin: 0 18px 12px;
   padding: 8px 12px;
   border-radius: 8px;
   border-inline-start: 3px solid var(--color-primary, #002448);
   background: var(--color-05, rgba(0, 36, 72, 0.04));
   font-size: 13px;
   line-height: 1.45;
   color: var(--text-default);
}
.sa-event-picker-sheet-body .sa-event-picker-brief {
   margin: 0 4px 12px;
}

.sa-event-picker-title {
   font-size: 16px;
   font-weight: 700;
   color: var(--color-primary, #002448);
}

.sa-event-picker-close {
   appearance: none;
   border: 0;
   background: transparent;
   color: var(--color-primary-subtitle);
   font-size: 18px;
   line-height: 1;
   cursor: pointer;
   padding: 4px 8px;
}

.sa-event-picker-close:hover { color: var(--color-primary, #002448); }

/* Back button — surfaces in the title row only when the picker is drilled
   into a group ("See N shows" → group-scoped view). Click reopens the
   unfiltered picker so the user can pick a different residency / event. */
.sa-event-picker-back {
   appearance: none;
   border: 0;
   background: transparent;
   color: var(--color-primary-subtitle);
   cursor: pointer;
   padding: 4px 6px;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   font: inherit;
}
.sa-event-picker-back:hover { color: var(--color-primary, #002448); }
.sa-event-picker-back svg { display: block; pointer-events: none; }
/* Sheet variant — back button sits ABOVE the chip tabs as its own row
   (the sheet's title is owned by BottomSheet and we can't inject into it). */
.sa-event-picker-back-sheet {
   width: 100%;
   justify-content: flex-start;
   padding: 8px 16px;
   font-size: 14px;
   font-weight: 600;
   border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.sa-event-picker-body {
   flex: 1 1 auto;
   min-height: 0;
   overflow-y: auto;
   padding: 0;
}

.sa-event-picker-backdrop { z-index: 155; }

/* ── EOPOP compact confirmation card (selected-event scope) ──────────────
   Owned by EopopCtrl. Reuses .sa-event-picker-backdrop for the dim layer
   so backdrop chrome matches the existing picker. Self-contained 380px
   card on desktop; full-bleed inside the BottomSheet body on mobile. */
.sa-eopop-compact-modal {
   position: fixed;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   z-index: 200;
   max-width: 92vw;
}
.sa-eopop-compact {
   position: relative;
   width: 380px;
   max-width: 100%;
   padding: 28px 24px 22px;
   display: flex;
   flex-direction: column;
   align-items: center;
   text-align: center;
   gap: 14px;
   background: #fff;
   border-radius: 16px;
   box-shadow: 0 24px 60px -12px rgba(7, 18, 41, 0.30), 0 2px 6px rgba(7, 18, 41, 0.06);
}
.sa-eopop-compact-close {
   position: absolute;
   top: 10px;
   right: 12px;
   width: 28px;
   height: 28px;
   border: 0;
   background: transparent;
   color: var(--color-60, rgba(0, 36, 72, 0.60));
   font-size: 18px;
   line-height: 1;
   cursor: pointer;
   border-radius: 999px;
   display: flex;
   align-items: center;
   justify-content: center;
   transition: background 0.15s ease, color 0.15s ease;
}
.sa-eopop-compact-close:hover {
   background: var(--color-05, rgba(0, 36, 72, 0.04));
   color: var(--color-primary, #002448);
}
.sa-eopop-compact-eyebrow {
   font-size: 11px;
   font-weight: 700;
   letter-spacing: 0.08em;
   text-transform: uppercase;
   color: var(--color-60, rgba(0, 36, 72, 0.60));
}
/* Avatar — performer photo (square), MLB logo (transparent + contain),
   or sport-colored letter tile. 56px square, 14px corner radius. */
.sa-eopop-avatar {
   flex: 0 0 auto;
   width: 56px;
   height: 56px;
   border-radius: 14px;
   object-fit: cover;
   background: var(--color-10, rgba(0, 36, 72, 0.10));
}
.sa-eopop-avatar-fallback {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   color: #fff;
   font-weight: 700;
   font-size: 22px;
   line-height: 1;
}
.sa-eopop-avatar-mlb {
   background: transparent;
   object-fit: contain;
}
.sa-eopop-compact-namebl {
   width: 100%;
}
.sa-eopop-compact-name {
   font-size: 18px;
   font-weight: 700;
   color: var(--text-default, #111827);
   line-height: 1.25;
   letter-spacing: -0.01em;
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 3;
   overflow: hidden;
}
.sa-eopop-compact-detail {
   font-size: 13px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
   line-height: 1.3;
   margin-top: 2px;
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 2;
   overflow: hidden;
}
.sa-eopop-compact-meta {
   display: flex;
   align-items: center;
   gap: 10px;
   font-size: 13px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
}
.sa-eopop-compact-dot {
   width: 3px;
   height: 3px;
   background: var(--color-40, rgba(0, 36, 72, 0.40));
   border-radius: 999px;
}
.sa-eopop-compact-meta strong {
   color: var(--text-default, #111827);
   font-weight: 700;
}
.sa-eopop-compact-cta {
   appearance: none;
   border: 0;
   background: var(--color-primary, #002448);
   color: #fff;
   padding: 12px 22px;
   border-radius: 999px;
   font: inherit;
   font-size: 15px;
   font-weight: 600;
   cursor: pointer;
   width: 100%;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   gap: 8px;
   margin-top: 4px;
   transition: background 0.15s ease, transform 0.08s ease;
}
.sa-eopop-compact-cta:hover { background: var(--color-primary-hover, #001a36); }
.sa-eopop-compact-cta:active { transform: translateY(1px); }
.sa-eopop-compact-arrow {
   display: inline-block;
   width: 14px;
   text-align: center;
}
.sa-eopop-compact-switch {
   font-size: 12px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
}
.sa-eopop-compact-switch a {
   color: var(--color-primary-soft, #0067CE);
   font-weight: 600;
   text-decoration: none;
   cursor: pointer;
}
.sa-eopop-compact-switch a:hover { text-decoration: underline; }

/* Mobile BottomSheet variant — sheet owns the surrounding chrome, so we
   shed our own shadow/radius/padding-top to avoid a doubled rounded box. */
.sa-eopop-compact-sheet-body {
   padding: 0 8px 12px;
}
.sa-eopop-compact-sheet-body .sa-eopop-compact {
   width: 100%;
   max-width: 100%;
   box-shadow: none;
   border-radius: 0;
   padding: 14px 16px 18px;
}
.sa-eopop-compact-sheet-body .sa-eopop-compact-close {
   /* Sheet has its own dismissal affordance (drag handle + backdrop).
      Keep the in-card close button for explicit X targeting but tighten
      its position for the sheet padding. */
   top: 6px;
   right: 6px;
}

/* Chip strip now lives inside the fixed header (no longer sticky); month
   separators inside the scrolling body are the only pinned element. The
   strip is a list-rail — chips stay on one line and the row scrolls
   horizontally when content exceeds the modal width. */
/* Scroll behavior comes from list-rail.js (data-list-rail attribute set
   in JS). The library wraps children in `.list-rail-track` and owns flex
   + overflow on that track. Don't redeclare flex/overflow here or the
   outer container would scroll instead of the track. */
.sa-event-picker-tabs {
   --list-rail-gap: 8px;
   padding: 0 14px;       /* no vertical padding — would shift arrow */
   margin-bottom: 12px;   /* breathing room above the body separator */
   background: #fff;
   min-width: 0;
}

.sa-ep-tab {
   flex: 0 0 auto;
   padding: 6px 12px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 999px;
   background: #fff;
   color: var(--text-default, #111827);
   font-size: 13px;
   font-weight: 500;
   white-space: nowrap;
   cursor: pointer;
}
.sa-ep-tab:hover { border-color: var(--text-low, #9ca3af); }
.sa-ep-tab.is-active {
   background: var(--color-primary, #002448);
   border-color: var(--color-primary, #002448);
   color: #fff;
}

/* Picker header row when both chip tabs and month dropdown are present.
   Tabs take the available width (list-rail scrolls horizontally inside);
   month dropdown stays put on the right. When only one of them exists,
   it's passed to _openModal directly with no wrapper. */
.sa-event-picker-header-row {
   display: flex;
   align-items: center;
   gap: 8px;
   padding: 0 14px;
   margin-bottom: 12px;
   background: #fff;
   min-width: 0;
}
.sa-event-picker-header-row .sa-event-picker-tabs {
   flex: 1 1 auto;
   padding: 0;
   margin-bottom: 0;
}
.sa-event-picker-header-row .sa-month-filter { flex: 0 0 auto; }

/* Group-drill picker month dropdown — sits in the picker header. Stand-
   alone (without chip tabs) it gets its own row's padding; nested in
   .sa-event-picker-header-row, padding comes from the row. */
.sa-event-picker-head > .sa-month-filter {
   padding: 0 14px;
   margin-bottom: 12px;
}

/* Month separator — grey "section header" treatment matching the esb
   pattern in lib/base/styles/src/events.css:1943. Pins to the top of
   the picker body as the user scrolls past. `top: -1px` absorbs the
   1px sub-pixel gap that otherwise appears between the fixed header
   bottom and the pinned month (rows would briefly peek through as you
   scrolled past). */
.sa-event-picker-list .el-month-sep,
.sa-event-picker-sheet-body .el-month-sep {
   position: sticky;
   top: -1px;
   z-index: 2;
   list-style: none;
   padding: 8px 14px 7px;
   font-size: 13px;
   font-weight: 700;
   letter-spacing: .04em;
   text-transform: uppercase;
   background: #f8f8f8;
   border-top: 1px solid #f1f1f1;
   border-bottom: 1px solid #f1f1f1;
   color: var(--color-60);
}

/* ── Event-list row: every row gets a same-size 32×40 avatar slot so
   event names always align in a vertical line. Slot contains either an
   image (performer photo or MLB logo) or a non-image identifier
   (team-abbrev pill / sport-icon avatar) centered inside. */
.sa-ep-event-item {
   align-items: center;
   /* Override base .el-event-item gap (20px). 12px base gap; avatar gets
      +4px margin-left so date→avatar reads 16px while name reads 12px
      from avatar — Keith's spec. */
   gap: 12px;
}

.sa-ep-event-avatar-img,
.sa-ep-event-avatar-icon {
   flex: 0 0 32px;
   width: 32px;
   height: 40px;
   margin-left: 4px;       /* +4px so date→avatar visual gap reads 16px */
}

.sa-ep-event-avatar-img {
   border-radius: 6px;
   object-fit: cover;
   background: var(--sa-bg-soft, #f3f4f6);
}

/* MLB team logos opt out of the grey loading bg and use object-fit:
   contain so the logo isn't cropped. Pattern matches `.sa-rail-event-mlb`
   on the event-strip cards — MLB licensing/visual treatment expects a
   neutral surround. */
.sa-ep-event-avatar-img.sa-ep-event-avatar-mlb {
   background: transparent;
   object-fit: contain;
   border-radius: 0;
}

/* Icon-variant slot: same 32×40 footprint as the image slot, but holds
   the borrowed event-strip identifier (team-abbrev pill or sport-icon
   avatar) centered inside. */
.sa-ep-event-avatar-icon {
   display: inline-flex;
   align-items: center;
   justify-content: center;
}
.sa-ep-event-avatar-icon .sa-rail-event-abbrev {
   width: 100%;
   min-width: 32px;
   height: 100%;
   padding: 0 4px;
   font-size: 12px;
   border-radius: 6px;
}
/* Sport-icon avatar fills the 32×40 slot like the image / abbrev
   variants do — previously sized 28×28 which left the icon column
   looking skinny + shorter than the other rows. Need to override the
   base `.sa-rail-event-avatar { flex: 0 0 20px }` — flex-basis on a
   flex item wins over `width` along the main axis, so width:100%
   alone wasn't enough. Reset flex to `0 0 auto` so width/height
   resolve against the 32×40 slot. */
.sa-ep-event-avatar-icon .sa-rail-event-avatar {
   flex: 0 0 auto;
   width: 100%;
   height: 100%;
   border-radius: 6px;
}
.sa-ep-event-avatar-icon .sa-rail-event-avatar [data-is="icon"] {
   width: 18px;
   height: 18px;
}

/* Date-TBD rows: the day slot becomes a single "TBA" label instead of
   the day-number + dow stack. Sized down so it fits the same vertical
   footprint as the normal date block. */
.sa-ep-event-item .el-day-tba {
   font-size: 12px;
   font-weight: 700;
   letter-spacing: .05em;
   color: var(--color-70);
   text-transform: uppercase;
}

.sa-ep-event-name-text {
   min-width: 0;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
}

.sa-event-picker-empty {
   padding: 24px 16px;
   text-align: center;
   color: var(--color-70);
   font-size: 13px;
}

/* ── Send-mode (eopop): rows present as senders, not picker options. The
   row gets a single Tickets+arrow CTA on the right (replacing Select/+),
   and the whole row is clickable to navigate. Hover lifts to read as a
   clear "this row will take me somewhere" affordance. */
.sa-ep-event-item-send {
   cursor: pointer;
}
.sa-ep-event-item-send:hover {
   background: rgba(0, 103, 206, 0.04);
}
.sa-ep-cta-block {
   display: flex;
   align-items: center;
}
.sa-ep-send-btn {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   height: 34px;
   padding: 0 12px 0 14px;
   border: 0;
   border-radius: 999px;
   background: var(--color-brand, #0067CE);
   color: #fff;
   font-family: inherit;
   font-size: 13px;
   font-weight: 600;
   letter-spacing: 0.01em;
   cursor: pointer;
   transition: background-color 120ms ease, transform 120ms ease;
}
.sa-ep-send-btn:hover {
   background: var(--color-primary, #002448);
}
.sa-ep-send-btn:active {
   transform: translateX(1px);
}
.sa-ep-send-label {
   line-height: 1;
}
.sa-ep-send-arrow {
   display: block;
   flex: 0 0 auto;
   pointer-events: none;
}

/* Group row — residency collapse in the picker. Replaces date block with
   a calendar icon, replaces Select/+ with a "See N shows" button that
   drills the picker into the group's events. Whole row is clickable. */
.sa-ep-event-item-group {
   cursor: pointer;
}
.sa-ep-event-item-group:hover {
   background: rgba(0, 103, 206, 0.04);
}
.sa-ep-group-date-block {
   display: flex;
   align-items: center;
   justify-content: center;
   color: var(--color-60, #677889);
}
.sa-ep-group-date-block svg { pointer-events: none; }
.sa-ep-group-btn svg { pointer-events: none; }
.sa-ep-group-details {
   color: var(--color-60, #677889);
   font-style: italic;
}
.sa-ep-group-cta-block {
   display: flex;
   align-items: center;
}
.sa-ep-group-btn {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   height: 34px;
   padding: 0 14px;
   border: 1px solid var(--color-brand, #0067CE);
   border-radius: 999px;
   background: #fff;
   color: var(--color-brand, #0067CE);
   font-family: inherit;
   font-size: 13px;
   font-weight: 600;
   letter-spacing: 0.01em;
   cursor: pointer;
   white-space: nowrap;
   transition: background-color 120ms ease, color 120ms ease;
}
.sa-ep-group-btn:hover {
   background: var(--color-brand, #0067CE);
   color: #fff;
}
/* Compact circular CTA variant for the group row — matches the
   `.el-select-btn-sm` plus-circle on regular event rows so the visual
   weight reads the same. 28×28, grey-border default, brand color on
   hover. Chevron icon (not `+`) signals "drill into N shows." */
.sa-ep-group-btn-circle {
   width: 28px;
   height: 28px;
   padding: 0;
   border: 2px solid #c8cdd6;
   border-radius: 50%;
   background: #fff;
   color: var(--color-60, #677889);
   justify-content: center;
   align-items: center;
   gap: 0;
   flex: 0 0 28px;
   transition: all .15s;
}
.sa-ep-group-btn-circle:hover {
   background: #fff;
   border-color: var(--color-primary, #002448);
   color: var(--color-primary, #002448);
}
.sa-ep-group-btn-circle svg { display: block; }


/* ── Compare Prices — section under the event picker. h2 + floor price +
   big CTA + Up Next + info line. Indented 8px each side with light
   top/bottom borders to read as a contained block. */
.sa-compare-prices {
   padding: 16px;
   background: linear-gradient(to right, rgba(0, 103, 206, 0.1) 0%, rgba(0, 103, 206, 0.01) 100%);   
   border-radius: 6px;
}

.sa-compare-prices.is-event-selected{
   background: white;
   border: 1px solid #e5e5e5;
   padding-top: 8px;
       box-shadow: 0 4px 10px rgba(0, 0, 0, 0.14);
       border-radius: 8px;
}

.sa-compare-prices[hidden] { display: none; }

.sa-compare-prices > h2 {
   margin: 0 0 12px;
}

.sa-cp-floor {
   display: flex;
   align-items: baseline;
   gap: 8px;
   margin-bottom: 16px;
}

.sa-cp-floor-amount {
   font-size: 24px;
   font-weight: 700;
   color: var(--text-default);
   text-decoration: underline;
   text-decoration-thickness: 2px;
   text-underline-offset: 3px;
}

.sa-cp-floor-label {
   color: var(--color-85);
}

/* Big full-width CTA pill — matches `.sa-hero-sel-cta` from the selected
   state. Tag icon sits to the left of the label. */
.sa-cp-cta {
   appearance: none;
   width: 100%;
   padding: 14px 16px;
   border: 0;
   border-radius: 999px;
   background: var(--color-brand, #0067CE);
   color: #fff;
   font-size: 15px;
   font-weight: 600;
   cursor: pointer;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   gap: 8px;
   transition: background 0.15s ease;
}

.sa-cp-cta:hover  { background: #0056b3; }
.sa-cp-cta:active { background: #004a99; }

.sa-cp-cta [data-is="icon"] {
   width: 18px;
   height: 18px;
}

.sa-cp-info {
   margin: 14px 0 0;
   display: flex;
   align-items: flex-start;
   gap: 4px;
   font-size: 12px;
   line-height: 1.4;
   color: var(--color-primary-subtitle);
   margin-left: 8px;
}

.sa-cp-info [data-is="icon"] {
   flex: 0 0 auto;
   width: 16px;
   height: 16px;

}

/* Selected-event slot — reuses `.sa-hero-sel-*` markup from the hero card
   pattern, so styling is shared. The flex column + 8px gap matches the
   `.sa-hero-card-selected` rhythm so the `.sa-hero-sel-when` rule (which
   uses `margin-top: -8px` to flush the date under the name) still lands. */
.sa-cp-selected {
   display: flex;
   flex-direction: column;
   gap: 8px;
}

.sa-cp-browse[hidden],
.sa-cp-selected[hidden] { display: none; }


/* ── Up Next — next 2 events, compact card style ────────────────────────── */
.sa-up-next {
   margin-top: 20px;
}

.sa-up-next-head {
   margin: 0 0 10px;
   font-size: 11px;
   font-weight: 600;
   line-height: 1.2;
   color: var(--color-primary-subtitle);   /* design-system token: primary @ 70% */
}

.sa-up-next[hidden] { display: none; }

.sa-up-next-list {
   display: flex;
   flex-direction: column;
   gap: 8px;
}

.sa-un-card {
   --sa-un-edge: var(--color-primary);
   display: flex;
   flex-direction: column;
   gap: 6px;
   padding: 10px 12px;
   border: 1px solid var(--sa-border-soft);
   border-left: 3px solid var(--sa-un-edge);
   border-radius: 10px;
   background: #fff;
   cursor: pointer;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-un-card:hover { border-color: var(--text-low); border-left-color: var(--sa-un-edge); }

.sa-un-card-top {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   font-size: 11px;
   line-height: 1.1;
   letter-spacing: 0.02em;
   text-transform: uppercase;
   white-space: nowrap;
}

.sa-un-card-date {
   font-weight: 600;
   color: var(--text-default);
}

.sa-un-card-time {
   font-weight: 500;
   color: var(--color-70);
}

.sa-un-card-body {
   display: flex;
   align-items: center;
   gap: 10px;
   min-width: 0;
}

.sa-un-card-avatar {
   flex: 0 0 40px;
   width: 40px;
   height: 40px;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   border-radius: 6px;
}

.sa-un-card-avatar i[data-is="icon"] {
   --size: 24px;
}

.sa-un-card-avatar-img {
   object-fit: cover;
   background: var(--sa-bg-soft);
}

/* Sports identifier slot: same 40×40 footprint as the avatar, but holds
   the borrowed event-strip identifier (MLB logo / team-abbrev pill /
   sport-icon avatar) scaled up to "two-line" tall so it reads alongside
   the name + foot row, not as a short pill against a tall body. Mirrors
   the picker's `.sa-ep-event-avatar-icon` pattern. */
.sa-un-card-avatar-slot {
   background: transparent;
}
.sa-un-card-avatar-slot .sa-rail-event-abbrev {
   min-width: 32px;
   height: 28px;
   padding: 0 6px;
   font-size: 12px;
   border-radius: 5px;
}
.sa-un-card-avatar-slot .sa-rail-event-mlb {
   height: 28px;
}
.sa-un-card-avatar-slot .sa-rail-event-avatar {
   width: 28px;
   height: 28px;
   border-radius: 5px;
}
.sa-un-card-avatar-slot .sa-rail-event-avatar [data-is="icon"] {
   width: 18px;
   height: 18px;
}

.sa-un-card-middle {
   flex: 1 1 auto;
   min-width: 0;
   display: flex;
   flex-direction: column;
   gap: 2px;
}

/* "See all events" button — full-width outlined pill placed between the
   Up Next list and the .sa-cp-info description. Uses the design-system
   40px `data-is="btn" .btn-ghost` for height/structure; overrides below
   swap to brand-blue text on a soft grey outline with a 24px pill
   radius. Hover keeps the brand identity but tints in. The attribute
   form (`button[data-is='btn'].btn-ghost`) is needed to outrank the
   base `lib/base/styles/src/buttons.css` rule (specificity 0,2,1). */
[data-up-next-footer] {
   display: block;
   margin: 12px 0 8px;
}
button[data-is='btn'].btn-ghost.sa-un-see-all {
   width: 100%;
   color: var(--color-brand);
   border-color: #e5e5e5;
   border-radius: 24px;
   background: white;
   height: 48px;
}
button[data-is='btn'].btn-ghost.sa-un-see-all:hover {
   color: var(--color-brand);
   border-color: var(--color-brand);
   background: color-mix(in srgb, var(--color-brand) 8%, transparent);
}

/* "Select an event to search tickets…" — prompt line above the event
   rail. Browse-mode only; SectionRailCtrl hides it when an event is
   selected (rail mode flips to the selected-card + ticket-suggestions
   pattern). */
.sa-rail-prompt {
   margin: 4px 16px 0;
   font-size: 13px;
   font-weight: 500;
   color: var(--text-low, #6b7280);
}

/* "Interactive Ticket Map" — narrow-screen-only title above the map.
   Hidden on widescreen where the map sits in the sticky right column
   and the title would just be noise. */
.sa-rail-map-title {
   margin: 16px 16px 8px;
}
@media (min-width: 880px) {
   .sa-rail-map-title { display: none; }
}

.sa-un-card-name {
   /* Open-ended event/performer names ("Hot Wheels Monster Trucks Live
      Glow-N-Fire at United Center") cap at 120px + 2-line clamp so
      they wrap inside the card instead of ellipsing the whole brand
      down to a few chars. */
   flex: 1;
   min-width: 0;
   font-size: 14px;
   font-weight: 600;
   color: var(--color-primary);
   line-height: 1.25;
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
   overflow: hidden;
   overflow-wrap: anywhere;
}

.sa-un-card-meta {
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   color: var(--color-70);
   font-size: 12px;
}

.sa-un-card-cta { margin-left: auto; flex: 0 0 auto; }

.sa-un-card-cta {
   appearance: none;
   border: 0;
   background: transparent;
   font: inherit;
   font-weight: 600;
   color: var(--color-brand);
   cursor: pointer;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 0;
   line-height: 1;
   transition: color 0.15s ease, text-decoration-color 0.15s ease;
}

.sa-un-card-cta i[data-is="icon"] {
   --size: 14px;
   transition: transform 0.15s ease;
}

/* Hover feedback — fires on direct CTA hover AND when the card itself
   is hovered (the whole card is clickable, so the user expects the CTA
   to react to the parent hover too). Underlines the text and nudges the
   plus icon slightly forward. */
.sa-un-card-cta:hover,
.sa-un-card:hover .sa-un-card-cta {
   text-decoration: underline;
   text-underline-offset: 3px;
}
.sa-un-card-cta:hover i[data-is="icon"],
.sa-un-card:hover .sa-un-card-cta i[data-is="icon"] {
   transform: translateX(2px) scale(1.05);
}

/* Selected-event styling lives on the hero card (.sa-hero-card.is-event-selected)
   — Up Next is hidden entirely when an event is picked, so it doesn't need a
   "selected" treatment of its own. */

/* :link/:visited bump beats the base `a:link, a:visited` rule (0,1,1) which
   would otherwise force `--link-default` on the link. */
.sa-up-next-all,
.sa-up-next-all:link,
.sa-up-next-all:visited,
.sa-up-next-all:hover {
   display: inline-block;
   margin-top: 10px;
   font-size: 13px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   text-decoration: none;
}

.sa-up-next-all:hover { text-decoration: underline; }


/* ── Section tabs (Seat Views / Key Info / Location / Tickets) ──────────── */

/* .sa-tabs is the tab component wrapper. Vertical rhythm comes from
   data-layout='scene' on the section; no bespoke margin rule needed. */

.sa-tabs-nav {
   display: flex;
   gap: 4px;
   border-bottom: 1px solid var(--sa-border-soft);
   overflow-x: auto;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: none;
}
.sa-tabs-nav::-webkit-scrollbar { display: none; }

.sa-tab-btn {
   flex: 0 0 auto;
   appearance: none;
   border: 0;
   background: transparent;
   padding: 0 14px;
   margin: 0;
   height: 44px;
   line-height: 1;
   font-family: inherit;
   font-size: 15px;
   font-weight: 600;
   letter-spacing: -0.005em;
   cursor: pointer;
   border-bottom: 3px solid transparent;
   color: var(--text-medium, #4b5563);
   transition: color 0.15s ease, border-color 0.15s ease;
}

.sa-tab-btn:hover {
   color: var(--text-default);
}

.sa-tab-btn.is-active {
   color: var(--color-brand, #0067CE);
   border-bottom-color: var(--color-brand, #0067CE);
}

/* Body — fixed height, content fills */
.sa-tabs-body {
   position: relative;
   height: 200px;   /* <480px */
   overflow: hidden;
}

@media (min-width: 480px) {
   .sa-tabs-body { height: 240px; }
}

.sa-tab-panel {
   position: absolute;
   inset: 0;
   display: none;
}

/* Show only the panel matching the active tab. */
.sa-tabs[data-active-tab="seat-views"] [data-tab="seat-views"],
.sa-tabs[data-active-tab="key-info"]   [data-tab="key-info"],
.sa-tabs[data-active-tab="location"]   [data-tab="location"],
.sa-tabs[data-active-tab="tickets"]    [data-tab="tickets"] {
   display: block;
}
.sa-tabs[data-active-tab] .sa-tabs-nav .sa-tab-btn[data-tab] { display: inline-flex; align-items: center; }


/* ── Seat Views panel ──────────────────────────────────────────────────── */

.sa-tab-photo-single {
   position: relative;
   margin: 0;
   width: 100%;
   height: 100%;
   overflow: hidden;
   cursor: pointer;
   border-radius: 8px;
   background: #111;
}

.sa-tab-photo-single img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
   border-radius: 8px;
   transition: transform 0.2s ease, filter 0.2s ease;
}

.sa-tab-photo-slider {
   display: block;
   width: 100%;
   height: 100%;
}

/* rys-slider renders an empty <div part="header"> with margin-bottom: 1rem
   even when no [slot="header"] is provided. That eats ~16px off the top of
   the viewport, pushing slide bottoms past the host's overflow:hidden box
   and clipping the photos. Hide the empty header so the viewport gets the
   full panel height. */
.sa-tab-photo-slider::part(header) { display: none; }

/* Subtle light-white outline + soft shadow on the overlapping nav buttons
   so they read against varied photo backgrounds. */
.sa-tab-photo-slider::part(prev-btn),
.sa-tab-photo-slider::part(next-btn) {
   border: 1px solid rgba(255, 255, 255, 0.65);
   box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

/* Slides need to fill the body height. rys-slider ships its own track sizing
   but slides default to auto height; force them to fill. */
.sa-tab-photo-slider .rys-slide {
   height: 200px;
}
@media (min-width: 480px) {
   .sa-tab-photo-slider .rys-slide { height: 240px; }
}

.sa-photo-slide {
   position: relative;
   overflow: hidden;
   cursor: pointer;
   border-radius: 8px;
   background: #111;
}

.sa-photo-slide img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
   border-radius: 8px;
   transition: transform 0.2s ease, filter 0.2s ease;
}

.sa-photo-slide:hover img,
.sa-tab-photo-single:hover img {
   transform: scale(1.02);
   filter: brightness(0.92);
}

/* Caption styling now lives in lib/vibes/content/styles/src/defs.css under
   [data-pattern='photo-caption']. The figure wrappers above carry that
   attribute so figcaption inherits the shared overlay treatment. */

.sa-photo-more-btn {
   position: absolute;
   top: 8px;
   right: 8px;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 4px 10px;
   background: var(--sa-bg-overlay);
   color: #fff;
   font-size: 12px;
   font-weight: 500;
   border-radius: var(--sa-card-radius-sm);
   pointer-events: none;
}

/* "See all photos" last card — same photo treatment as a regular slide
   but with a 60% black mask + centered white underlined label. The
   background image is the next un-picked photo from the gallery (chosen
   in section-tabs.php). */
.sa-photo-more-slide {
   /* Inherits .sa-photo-slide treatment (figure, position:relative,
      data-pattern='photo-caption' is NOT on this one — no caption). */
}

.sa-photo-more-overlay {
   position: absolute;
   inset: 0;
   background: rgba(0, 0, 0, 0.6);
   display: flex;
   align-items: center;
   justify-content: center;
   border-radius: var(--sa-card-radius);
   pointer-events: none;
}

.sa-photo-more-label {
   color: #fff;
   text-decoration: underline;
   font-size: 18px;
   font-weight: 600;
   letter-spacing: 0.01em;
}


/* ── Photos grid (catch-all below fan reviews) ─────────────────────────── */

.sa-photo-grid {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
   gap: 6px;
}

.sa-photo-grid-cell {
   position: relative;
   aspect-ratio: 10 / 7;
   overflow: hidden;
   border: 0;
   padding: 0;
   border-radius: 10px;
   cursor: pointer;
   background: #111;
}

.sa-photo-grid-cell img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
   transition: transform 0.2s ease, filter 0.2s ease;
}

.sa-photo-grid-cell:hover img {
   transform: scale(1.04);
   filter: brightness(0.9);
}

.sa-photo-grid-overlay {
   position: absolute;
   inset: 0;
   display: flex;
   align-items: center;
   justify-content: center;
   background: rgba(0, 0, 0, 0.5);
   color: #fff;
   font-size: 20px;
   font-weight: 700;
   pointer-events: none;
}


/* ── Key Info panel ────────────────────────────────────────────────────── */

.sa-panel-key-info {
   padding: 16px 0;
}

.sa-keyinfo-grid {
   /* 2-column CSS grid (mirrors the archive's `data-flow='tiles' data-tiles='2'`
      pattern — see `_lab/KH/seating-areas-failed-test/lib/functions-render.php
      #_renderInsights`). Each tile sits in its own cell; rows auto-height so
      tiles with one or two lines of text both look right. */
   list-style: none;
   padding: 0 16px;
   margin: 0;
   display: grid;
   grid-template-columns: repeat(2, minmax(0, 1fr));
   gap: 16px;
   align-content: start;
   margin-top: 6px;
}

.sa-keyinfo-tile {
   display: flex;
   /* Icon always anchors to the headline row — when an insight has a
      second line (e.g. row modifier under a staff pick), centering would
      slide the icon down between the two lines. */
   align-items: flex-start;
   gap: 10px;
   padding: 0 6px;

   border-radius: var(--sa-card-radius);
   background: #fff;
   line-height: 1.35;
   min-width: 0;     /* let grid track shrink past intrinsic content */
   height: 100%;
   max-height: 100%;
}

.sa-keyinfo-icon {
   flex: 0 0 auto;
   color: var(--color-brand, #0067CE);
   display: inline-flex;
   align-items: center;
   /* Match the headline line-height so when the tile is `align-items:
      flex-start` the icon container vertically centers on the first line
      rather than sitting flush to the top edge (which would look
      slightly below the line when the icon is taller than the line). */
   height: 1.35em;
}

.sa-keyinfo-text { color: var(--text-default); }

.sa-keyinfo-empty {
   padding: 0 16px;
   color: var(--text-medium, #4b5563);
   font-style: italic;
}


/* ── Location panel ────────────────────────────────────────────────────── */

.sa-tab-location {
   margin: 0;
   width: 100%;
   height: 100%;
   position: relative;
   overflow: hidden;
   background: var(--sa-bg-soft);
   cursor: pointer;
}

.sa-tab-location img {
   width: 100%;
   height: 100%;
   object-fit: contain;
   display: block;
}

.sa-tab-location-cta {
   position: absolute;
   bottom: 8px;
   right: 8px;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 6px 10px;
   background: var(--sa-bg-overlay);
   color: #fff;
   font-size: 12px;
   font-weight: 500;
   border-radius: var(--sa-card-radius-sm);
   pointer-events: none;
}

@media (min-width: 880px) {
   /* On desktop, the persistent right-rail map handles the deeper view —
      Location panel becomes informational only (no fullscreen trigger).
      Keep the cursor a pointer on mobile only. */
   .sa-tab-location { cursor: default; }
   .sa-tab-location-cta { display: none; }
}


/* ── Tickets panel (placeholder) ───────────────────────────────────────── */

.sa-tickets-placeholder {
   display: flex;
   align-items: center;
   justify-content: center;
   height: 100%;
   color: var(--text-medium, #4b5563);
   font-style: italic;
}


/* ── Seat view media (legacy — old SeatViewMedia component) ─────────────── */

.sa-svm-figure {
   position: relative;
   margin: 0;
   aspect-ratio: 16 / 9;
   overflow: hidden;
   border-radius: var(--sa-card-radius);
   background: var(--sa-bg-soft);
   cursor: pointer;
}

.sa-svm-primary {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
}

.sa-svm-map-as-primary {
   object-fit: contain;
   background: #fff;
}

/* Photo count badge */
.sa-svm-photo-count {
   position: absolute;
   bottom: 12px;
   left: 12px;
   display: inline-flex;
   align-items: center;
   gap: 4px;
   padding: 6px 10px;
   background: var(--sa-bg-overlay);
   color: #fff;
   border-radius: var(--sa-card-radius-sm);
   font-size: 12px;
   font-weight: 500;
   pointer-events: none;
}

/* Map overlay thumbnail in the corner */
.sa-svm-overlay-toggle {
   position: absolute;
   bottom: 12px;
   right: 12px;
   width: 80px;
   height: 80px;
   padding: 0;
   border: 2px solid #fff;
   border-radius: var(--sa-card-radius-sm);
   background: #fff;
   cursor: pointer;
   overflow: hidden;
   box-shadow: 0 2px 6px rgba(0,0,0,0.25);
   transition: transform 0.15s ease;
}

.sa-svm-overlay-toggle:hover {
   transform: scale(1.05);
}

.sa-svm-overlay-toggle img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
}

@media (min-width: 880px) {
   .sa-svm-overlay-toggle {
      width: 100px;
      height: 100px;
   }
}

/* Placeholder state (no photo, no map) */
.sa-svm-placeholder {
   cursor: default;
}

.sa-svm-placeholder-inner {
   position: absolute;
   inset: 0;
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   gap: 8px;
   color: var(--text-medium, #4b5563);
}

.sa-svm-caption {
   margin-top: 8px;
   font-size: 14px;
   color: var(--text-medium, #4b5563);
}


/* ── Interactive map (inline + rail) ────────────────────────────────────── */

.sa-im-wrapper {
   position: relative;
}

.sa-im-container {
   width: 100%;
   height: 360px;
   background: #f9fafb;
   border-radius: 8px;
   overflow: hidden;
}

.sa-im-header {
   margin-bottom: 8px;
   min-height: 32px;       /* reserve space for "selected event" bar to prevent CLS */
}


/* ── More at {venue} link list (above related-seating slider) ───────────── */

.sa-more-at-list {
   display: flex;
   flex-direction: column;
   gap: 4px;
   margin: 8px 0 16px;
}

.sa-more-at-item {
   display: flex;
   align-items: center;
   gap: 12px;
   width: 100%;
   padding: 12px 4px;
   border-radius: 8px;
   text-decoration: none;
   color: inherit;
   -webkit-tap-highlight-color: transparent;
   transition: background 120ms ease;
}

.sa-more-at-item:hover,
.sa-more-at-item:active {
   background: var(--sa-bg-soft, #f5f5f5);
}

.sa-more-at-item--highlight {
   background: rgba(247, 198, 61, 0.12);
}

.sa-more-at-item--highlight:hover,
.sa-more-at-item--highlight:active {
   background: rgba(247, 198, 61, 0.22);
}

.sa-more-at-iconbox {
   flex: 0 0 auto;
   width: 28px;
   display: inline-flex;
   align-items: center;
   justify-content: center;
   color: var(--text-medium, #4b5563);
}

.sa-more-at-iconbox [data-is="icon"] {
   width: 22px;
   height: 22px;
}

.sa-more-at-item--highlight .sa-more-at-iconbox {
   color: #b8860b;
}

.sa-more-at-text {
   flex: 1;
   min-width: 0;
   display: flex;
   flex-direction: column;
   gap: 2px;
}

.sa-more-at-title {
   font-weight: 600;
   line-height: 1.3;
   letter-spacing: -0.1px;
}

.sa-more-at-sub {
   font-size: 13px;
   color: var(--text-soft, #6b7280);
   line-height: 1.3;
}

.sa-more-at-chevron {
   flex: 0 0 auto;
   color: var(--text-muted, #9ca3af);
   width: 18px;
   height: 18px;
}


/* ── Popular Seating slider — compact thumb + 2-line 13px title ─────────── */
.sa-popular-seating-slider {
   --rys-gap: 8px;
}

/* The popular-seating card stacks a 90×72 image on top of a two-line
   title underneath, so the slider's overall height is taller than the
   image. The gutter nav's default `top: 50%` centers the button on the
   whole slider — which lands it on the title text. Override via the
   nav's exposed CSS-var API so the 36px button's center (y=36) lines up
   with the 72px image's center. */
.sa-popular-seating-slider {
   --rys-gutter-top: 18px;
   --rys-gutter-transform: none;
}

.sa-popular-seating-slider [data-pattern='card'][data-card='hero'] {
   width: 100%;
   /* No max-width — let the slider's slide-width define how wide each card
      is. Capping with max-width was fighting the slider's sizing and
      leaving inconsistent dead-space inside slides, causing the gutter
      nav buttons to land on card content on some host widths. */
   /* Strip the base [data-pattern='card'] 12px padding + gap so the
      thumb + 13px title actually get the full slide width. */
   padding: 0;
   gap: 6px;
}

/* The base [data-slot='hero'] rule (patterns.css:97) sets a negative
   margin = the card padding + a wider width + top-only radius — that
   pattern was designed for cards WITH padding. We zeroed the padding
   here, so the slot needs to be reset: no overflow margin, full radius,
   and overflow:hidden still clips the img to the rounded shape. */
.sa-popular-seating-slider [data-pattern='card'][data-card='hero'] [data-slot='hero'] {
   margin: 0;
   width: 100%;
   border-radius: 8px;
   overflow: hidden;
   position: relative;   /* anchor for the event-type badge overlay */
}

/* Event-type pill overlaid on the photo's top-left. Only emitted for
   single-event-type-resolved cards on multi-event-type venues (see
   `_getPopularSeating` in lib/vibes/content/php/functions.php). */
.sa-popular-seating-badge {
   position: absolute;
   top: 4px;
   left: 4px;
   z-index: 1;
   padding: 2px 6px;
   border-radius: 4px;
   background: rgba(0, 0, 0, 0.72);
   color: #fff;
   font-size: 10px;
   font-weight: 600;
   line-height: 1;
   letter-spacing: 0.03em;
   text-transform: uppercase;
   pointer-events: none;
}

.sa-popular-seating-slider [data-pattern='card'][data-card='hero'] [data-slot='hero'] img {
   width: 100%;
   height: 72px;
   object-fit: cover;
}

.sa-popular-seating-slider [data-pattern='card'][data-card='hero'] [data-slot='header'] {
   font-size: 13px;
   line-height: 1.25;
   font-weight: 600;
   display: -webkit-box;
   -webkit-line-clamp: 2;
   line-clamp: 2;
   -webkit-box-orient: vertical;
   overflow: hidden;
   text-overflow: ellipsis;
   padding-top: 4px;
}


/* ── Skeleton scrollers (cluster patterns for chips/cards) ──────────────── */

.sa-event-picker-skeleton,
.sa-similar-skeleton,
.sa-related-skeleton {
   list-style: none;
   padding: 0;
   margin: 8px 0 0;
   display: flex;
   gap: 12px;
   overflow-x: auto;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: thin;
}

.sa-event-picker-skeleton li,
.sa-similar-skeleton li,
.sa-related-skeleton li {
   flex: 0 0 auto;
   border-radius: 8px;
}


/* ── Section about (accordion) ──────────────────────────────────────────── */

.sa-about-details {
   border-top: 1px solid #e5e7eb;
   padding: 16px 0;
}

.sa-about-details summary {
   cursor: pointer;
   list-style: none;
   display: flex;
   align-items: center;
   justify-content: space-between;
}

.sa-about-details summary::after {
   content: '+';
   font-size: 24px;
   color: var(--text-medium, #4b5563);
}

.sa-about-details[open] summary::after {
   content: '–';
}

.sa-about-content {
   margin-top: 12px;
}


/* ── Section reviews ────────────────────────────────────────────────────── */

.sa-reviews-header {
   display: flex;
   align-items: center;
   gap: 16px;
   flex-wrap: wrap;
   margin-bottom: 16px;
}

.sa-reviews-aggregate {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   font-size: 14px;
   color: var(--text-medium, #4b5563);
}

.sa-reviews-score {
   font-size: 16px;
   font-weight: 600;
   color: var(--text-default);
}

.sa-reviews-count {
   color: var(--text-low, #6b7280);
}

.sa-reviews-list {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   flex-direction: column;
   gap: 16px;
}

.sa-review {
   padding: 12px 14px;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   cursor: pointer;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-review:hover {
   border-color: var(--text-low, #9ca3af);
   background: var(--sa-bg-soft);
}

.sa-review-headline {
   margin: 0 0 4px;
   font-size: 16px;
   font-weight: 600;
}

.sa-review-comments {
   margin: 0 0 8px;
   font-size: 14px;
   color: var(--text-default);
   line-height: 1.5;
}

.sa-review-meta {
   margin: 0;
   font-size: 12px;
   color: var(--text-low, #6b7280);
}

.sa-reviews-empty {
   color: var(--text-medium, #4b5563);
   font-style: italic;
}

.sa-reviews-more {
   margin-top: 16px;
}

/* Shared scene footer — wraps trailing "View all X ›" / "See all ›" links
   inside a scene (ratings-reviews, questions, etc.). Pulls the link a
   quarter of the scene-gap below the preceding card list so it reads as
   the scene's tail without inheriting full block spacing. */
[data-footer="text"] {
   margin-block-start: calc(var(--scene-gap) * 0.25);
}


/* ── Event type filter chips (multi-tenant only) ────────────────────────── */

.sa-etfc-chips {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   flex-wrap: wrap;
   gap: 8px;
}

.sa-etfc-chip {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   padding: 6px 12px;
   border: 1px solid var(--sa-border-soft);
   border-radius: 999px;
   background: #fff;
   font-size: 13px;
   cursor: pointer;
   transition: border-color 0.15s ease, background 0.15s ease;
}

.sa-etfc-chip:hover {
   border-color: var(--color-brand, #0067CE);
}

.sa-etfc-chip.is-active {
   border-color: var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
}

.sa-etfc-label {
   font-weight: 500;
}

.sa-etfc-count {
   color: var(--text-low, #6b7280);
   font-size: 12px;
}


/* ── Event picker chips ─────────────────────────────────────────────────── */

.sa-ep-list {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   gap: 12px;
   overflow-x: auto;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: thin;
}

.sa-ep-list > li {
   flex: 0 0 220px;
}

.sa-ep-chip {
   display: flex;
   align-items: center;
   gap: 12px;
   width: 100%;
   padding: 10px 12px;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   background: #fff;
   text-align: left;
   cursor: pointer;
   transition: border-color 0.15s ease, transform 0.15s ease;
}

.sa-ep-chip:hover {
   border-color: var(--text-low, #9ca3af);
   transform: translateY(-1px);
}

.sa-ep-chip.is-selected {
   border-color: var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
}

.sa-ep-date {
   flex: 0 0 auto;
   display: flex;
   flex-direction: column;
   align-items: center;
   padding: 4px 8px;
   border-radius: var(--sa-card-radius-sm);
   background: var(--sa-bg-soft);
   font-size: 11px;
   line-height: 1.1;
   text-transform: uppercase;
}

.sa-ep-month {
   font-weight: 600;
   color: var(--color-brand, #0067CE);
}

.sa-ep-day {
   font-size: 16px;
   font-weight: 600;
   color: var(--text-default);
}

.sa-ep-body {
   flex: 1 1 auto;
   display: flex;
   flex-direction: column;
   gap: 2px;
   min-width: 0;
}

.sa-ep-name {
   font-size: 13px;
   font-weight: 500;
   line-height: 1.3;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
}

.sa-ep-meta {
   font-size: 11px;
   color: var(--text-low, #6b7280);
}

.sa-ep-price {
   font-size: 12px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
}

.sa-ep-price-soft {
   color: var(--text-low, #6b7280);
   font-weight: 500;
}

.sa-event-picker-empty {
   color: var(--text-medium, #4b5563);
   font-style: italic;
}


/* ── Best seats recommendations (Phase 4 rebuild) ───────────────────────── */

.sa-bs-header {
   margin-bottom: 16px;
}

.sa-bs-context {
   margin: 0;
   font-size: 13px;
   color: var(--text-medium, #4b5563);
   line-height: 1.4;
}

.sa-bs-picks {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   flex-direction: column;
   gap: 12px;
}

.sa-bs-pick {
   padding: 14px 16px;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   background: #fff;
}

.sa-bs-pick-head {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   gap: 12px;
   margin-bottom: 4px;
}

.sa-bs-pick-descriptor {
   font-size: 15px;
   font-weight: 600;
   color: var(--text-default);
}

.sa-bs-pick-price {
   font-size: 14px;
   font-weight: 600;
   color: var(--color-brand, #0067CE);
   white-space: nowrap;
}

.sa-bs-pick-row {
   font-size: 13px;
   color: var(--text-medium, #4b5563);
   margin-bottom: 8px;
}

.sa-bs-attrs {
   list-style: none;
   padding: 0;
   margin: 0 0 8px;
   display: flex;
   flex-wrap: wrap;
   gap: 6px;
}

.sa-bs-attr {
   display: inline-flex;
   align-items: center;
   padding: 2px 8px;
   border: 1px solid var(--sa-border-soft);
   border-radius: 999px;
   background: #fff;
   font-size: 11px;
   color: var(--text-medium, #4b5563);
   line-height: 1.5;
}

.sa-bs-attr.is-primary {
   border-color: var(--color-brand, #0067CE);
   background: var(--color-brand, #0067CE);
   color: #fff;
   font-weight: 500;
}

.sa-bs-pick-reasoning {
   margin: 0;
   font-size: 12px;
   color: var(--text-low, #6b7280);
   line-height: 1.5;
   font-style: italic;
}

.sa-bs-footer {
   margin-top: 12px;
   text-align: right;
}

.sa-bs-soldout {
   padding: 16px;
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   background: var(--sa-bg-soft);
}

.sa-bs-soldout p {
   margin: 0 0 8px;
   font-size: 14px;
}

.sa-best-seats-callout {
   margin-top: 24px;
   padding: 16px;
   border-left: 3px solid var(--color-brand, #0067CE);
   background: var(--sa-bg-soft);
   border-radius: 0 var(--sa-card-radius) var(--sa-card-radius) 0;
}

.sa-best-seats-callout p {
   margin: 0 0 8px;
   font-size: 14px;
   line-height: 1.5;
}


/* ── Similar sections carousel ──────────────────────────────────────────── */

.sa-similar-list {
   list-style: none;
   padding: 0;
   margin: 12px 0 0;
   display: flex;
   gap: 12px;
   overflow-x: auto;
   -webkit-overflow-scrolling: touch;
   scrollbar-width: thin;
}

.sa-similar-list > li {
   flex: 0 0 180px;
}

.sa-similar-card {
   display: block;
   text-decoration: none;
   color: var(--text-default);
   border: 1px solid var(--sa-border-soft);
   border-radius: var(--sa-card-radius);
   overflow: hidden;
   transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.sa-similar-card:hover {
   transform: translateY(-2px);
   border-color: var(--text-low, #9ca3af);
   box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}

.sa-similar-thumb {
   margin: 0;
   aspect-ratio: 16 / 9;
   overflow: hidden;
   background: var(--sa-bg-soft);
}

.sa-similar-thumb img {
   width: 100%;
   height: 100%;
   object-fit: cover;
   display: block;
}

.sa-similar-body {
   padding: 10px 12px;
}

.sa-similar-name {
   display: block;
   font-size: 14px;
   font-weight: 500;
   line-height: 1.3;
}


/* ── Related seating thumbnails ─────────────────────────────────────────── */
/* Markup uses <rys-slider> + the design-system data-pattern="card" hero
   variant — visuals come from those existing systems. No theme-level CSS
   needed beyond the section-margin rhythm at the top of this file. */


/* ── Reactive transitions (skeleton replay) ─────────────────────────────── */

.reactive-transition {
   /* Skeletons inside this wrapper use existing .u-skeleton from lib/base */
}


/* ──────────────────────────────────────────────────────────────────────────
   Desktop (≥880px) — bespoke layout grid lived here, now moved to
   `lib/lib-overrides.css` under `main[data-show='panel+map']` per the
   design-system pattern (data-layout='stage' > panel+map).
   Component-level desktop tweaks below.
   ────────────────────────────────────────────────────────────────────────── */

@media (min-width: 880px) {

   /* Map placeholder fills the remaining vertical space inside the map slot
      (which is flex-direction: column under main[data-show='panel+map']). */
   .sa-rail-map {
      flex: 1 1 auto;
      height: auto;
      min-height: 0;
   }
}


/* Zone-only static seating chart panel (amp-box + curated charts). */
[data-component="seating-chart"] {
   margin-block: 20px;
}
.sa-seating-chart-img {
   display: block;
   width: 100%;
   max-width: 100%;
   height: auto;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 6px;
}
.sa-seating-chart-list {
   margin: 0;
   padding: 0;
   list-style: none;
   display: flex;
   flex-direction: column;
   gap: 8px;
}
.sa-seating-chart-item a {
   display: inline-flex;
   align-items: center;
   gap: 12px;
   text-decoration: none;
}
.sa-seating-chart-thumb {
   width: 60px;
   height: 40px;
   object-fit: cover;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 4px;
   flex: 0 0 60px;
}

/* ── Mobile isolate mode ─────────────────────────────────────────────────
   Off by default. Opt in via `localStorage.setItem('sa-mobile-isolate','1')`.
   When a user actively picks an event on a narrow viewport AND the flag
   is on, `scripts-ready.js` adds `.is-mobile-isolate` to <main>. The
   page collapses to the section-rail strip (its selected-event card with
   close button = primary exit) + map + Available Tickets list. Browser
   back button is the secondary exit (popstate handler removes the class). */
@media (max-width: 879px) {
   /* Strip every section + scene inside <main> except the stage that
      contains panel-top / map / panel-bottom. */
   main.is-mobile-isolate > *:not(section[data-layout="stage"]) {
      display: none !important;
   }
   main.is-mobile-isolate section[data-layout="stage"] {
      display: flex !important;
      flex-direction: column;
      position: fixed;
      inset: 0;
      width: 100vw;
      /* `100dvh` (dynamic viewport height) accounts for the iOS Safari
         URL bar that slides in/out during scroll — `100vh` leaves the
         bottom 50-80px cut off when the bar is showing, hiding part of
         the Available Tickets list. Safari 15.4+ supports `dvh`. */
      height: 100dvh;
      z-index: 9000;
      background: #fff;
      overflow: hidden;
   }
   main.is-mobile-isolate [data-layout="panel"].panel-top {
      display: none !important;
   }
   main.is-mobile-isolate [data-layout="map"] {
      flex: 1 1 auto;
      min-height: 0;
      overflow: hidden;
   }
   main.is-mobile-isolate [data-layout="panel"].panel-bottom {
      flex: 0 0 auto;
      /* `dvh` matches the parent's dynamic-viewport unit so the list
         doesn't get pushed offscreen when iOS Safari's URL bar shows. */
      max-height: 50dvh;
      overflow-y: auto;
      /* iOS momentum scroll inside a `position: fixed` parent — without
         this, the inner scroll can lock up on Safari < 13.  Harmless on
         modern browsers (the property is a no-op outside iOS). */
      -webkit-overflow-scrolling: touch;
      padding: 12px 14px 16px;
      background: #fff;
      border-top: 1px solid rgba(0, 0, 0, 0.08);
   }
   main.is-mobile-isolate [data-layout="panel"].panel-bottom > *:not(.sa-available-tickets) {
      display: none !important;
   }
   main.is-mobile-isolate .sa-available-tickets {
      display: block !important;
   }
   /* Hide the Available Tickets section title (h2) in isolate — the list
      is the only thing in that slot, label is redundant + eats height. */
   main.is-mobile-isolate .sa-available-tickets .sa-hero-sel-available-title {
      display: none !important;
   }
}


/* ═══════════════════════════════════════════════════════════════════════
   SEATING-CHART LANDING (view=seating-chart-landing)
   ──────────────────────────────────────────────────────────────────────
   Rides the SAME `<main data-show="panel+map">` stage as section/zone
   pages so the L/R split previews where the interactive map slots in
   after the user picks a chart. Slot bodies differ — see
   `views/seating-chart-landing.php` — but the stage geometry is
   inherited from `lib-overrides.css`'s `main[data-show='panel+map']`
   rule so we DON'T re-declare it here.

   Tiles use the `data-flow="tiles"` design-system primitive (defined in
   `lib/base/styles/src/zero.css`) — we ONLY style the tile internals,
   not the layout primitive itself, per [[feedback_no_bespoke_layout_classes]].
   ═══════════════════════════════════════════════════════════════════════ */

main.sa-landing h1 {
   margin: 8px 0 12px;
}
.sa-landing-intro {
   margin: 0 0 20px;
   font-size: 15px;
   line-height: 1.55;
   color: var(--text-default);
}
.sa-landing-chooser-title {
   margin: 8px 0 14px;
}
.sa-landing-empty {
   color: var(--color-70, rgba(0, 36, 72, 0.70));
   font-style: italic;
}

/* ── Left panel: small tile "navigation" list ──────────────────────
   Mirrors ti.2's `#list-explore-map` sidebar list — thumbnail-left,
   label-right rows. Used as a SECONDARY nav under the h1; the BIG
   colored grid in the map slot is the primary affordance. */
.sa-landing-list {
   list-style: none;
   padding: 0;
   margin: 0 0 24px;
   display: flex;
   flex-direction: column;
   gap: 10px;
}
.sa-landing-list-item {
   background: #fff;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 10px;
   overflow: hidden;
   transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.sa-landing-list-item:hover {
   border-color: var(--color-primary, #002448);
   box-shadow: 0 2px 8px rgba(7, 18, 41, 0.06);
}
.sa-landing-list-item a {
   display: flex;
   align-items: center;
   gap: 12px;
   padding: 8px 12px;
   color: inherit;
}
.sa-landing-list-thumb {
   flex: 0 0 auto;
   width: 56px;
   height: 56px;
   border-radius: 6px;
   object-fit: cover;
   background: var(--color-05, rgba(0, 36, 72, 0.04));
}
.sa-landing-list-label {
   flex: 1 1 auto;
   min-width: 0;
   font-size: 15px;
   line-height: 1.25;
}
/* Other Events row — no thumbnail photo (no representative image for
   the catch-all bucket). Use the same 56×56 footprint as the regular
   thumbs so labels line up; fill with the design-system stadium icon
   centered on a tinted background. */
.sa-landing-list-thumb--other {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   color: var(--color-primary, #002448);
   background: var(--color-05, rgba(0, 36, 72, 0.04));
}
.sa-landing-list-thumb--other > [data-is="icon"] {
   width: 24px;
   height: 24px;
}

/* ── Right map slot: big colored grid ─────────────────────────────
   1:1 visual port of ti.2's `#section-interactive-map .grid-container`
   block (themes/ti.2/lib/styles-default.css:1454-1463). Rules below
   are copied verbatim from ti.2 — DO NOT freelance these proportions
   without checking the original. ti.2's `grid-container { height: 90% }`
   relied on `#section-interactive-map` having an explicit height set by
   its containing pane; in the SA map slot the section is `height: auto`
   by default, so percentage heights collapse. Wrap the section in a
   flex column with `height: 100%` so it fills the map slot, then let
   the grid-container claim its 90%. */
#section-interactive-map {
   height: 100%;
   display: flex;
   flex-direction: column;
}
#section-interactive-map > h2 {
   flex: 0 0 auto;
}
#section-interactive-map .grid-container {
   flex: 1 1 auto;
   width: 100%;
   padding: 4%;
   padding-top: 0;
}
#section-interactive-map .grid-container .card {
   width: 46%;
   justify-content: center;
   min-height: 120px;
   display: inline-flex;
   align-items: center;
   border: 1px solid #CCC;
   margin: 2%;
   border-radius: 20px;
   position: relative;
   overflow: hidden;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
#section-interactive-map .grid-container[data-rows='1'] .card { height: 40%; }
#section-interactive-map .grid-container[data-rows='2'] .card { height: 36%; }
#section-interactive-map .grid-container[data-rows='3'] .card { height: 26%; }
#section-interactive-map .grid-container .card img {
   height: 100%;
   width: 100%;
   position: absolute;
   object-fit: cover;
   border-radius: 20px;
}
#section-interactive-map .grid-container .card .filter {
   position: absolute;
   height: 100%;
   width: 100%;
   opacity: 0.80;
   border-radius: 20px;
   transition: opacity 0.15s ease;
}
#section-interactive-map .grid-container .card a {
   color: #fff;
   font-size: min(30px, 4vw);
   text-transform: uppercase;
   z-index: 10;
   font-weight: 700;
   text-decoration: none;
   /* Fill the entire card so a click anywhere routes to this link.
      Earlier `bottom: 15%; position: absolute` made only the bottom
      strip clickable, so users tapping the image got nothing. Use
      flex to keep the text visually anchored ~15% from the bottom. */
   position: absolute;
   inset: 0;
   padding: 0 10px 15%;
   text-align: center;
   line-height: 1.15;
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: flex-end;
}
#section-interactive-map .grid-container .card:hover .filter { opacity: 1; }
#section-interactive-map .grid-container .card:hover { cursor: pointer; }
#section-interactive-map[data-type='landing'] h2 {
   position: unset;
   display: block !important;
   margin-top: 30px;
   text-align: center;
   margin-left: 5px;
}

/* Subtitle line — second line under the title showing the next upcoming
   event of the chart's sport ("CHICAGO FOOTBALL CLASSIC" under the Bears
   tile, etc.). Same `<a>` block as the title; the title span sets the
   big uppercase size, the sub span shrinks below it. */
#section-interactive-map .grid-container .card a .sa-grid-card-title {
   display: block;
}
#section-interactive-map .grid-container .card a .sa-grid-card-sub {
   display: -webkit-box;
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
   overflow: hidden;
   margin-top: 6px;
   font-size: 0.45em;
   font-weight: 600;
   letter-spacing: 0.04em;
   opacity: 0.95;
}

/* "Other Events" — odd-count tile (fills the empty last-row slot) and
   even-count large button below the grid. Tile reuses the standard
   grid-card mold; button is a roomy single-line block. Both open the
   sa-event-picker with the "Other" tab pre-selected. */
#section-interactive-map .grid-container .card.sa-landing-other-tile a {
   text-align: center;
}
/* Other Events tile — lives inside `.grid-container` as the last item.
   Same margin / box-shadow / border-radius as `.card` so it sits in the
   grid's flex flow without a gap. Width swaps via the `--full` modifier:
     • Default (totalWithOther EVEN) → 46%, fills the empty last cell.
     • `.sa-landing-other-tile--full` (totalWithOther ODD) → 100%, its
       own bottom row spanning both columns.
   Visual treatment: white background, primary-color uppercase text. */
#section-interactive-map .grid-container .sa-landing-other-tile {
   display: flex;
   align-items: center;
   justify-content: center;
   width: 46%;
   min-height: 60px;
   margin: 2%;
   padding: 18px 16px;
   background: #fff;
   color: var(--color-primary, #002448);
   border: 1px solid #CCC;
   border-radius: 20px;
   text-align: center;
   text-decoration: none;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
   transition: background-color 0.15s ease;
}
#section-interactive-map .grid-container .sa-landing-other-tile--full {
   width: 96%;     /* matches `.card` width arithmetic (100% - 2% margin × 2) */
}
#section-interactive-map .grid-container .sa-landing-other-tile:hover {
   background: var(--color-05, rgba(0, 36, 72, 0.04));
   cursor: pointer;
}
.sa-landing-other-tile-title {
   display: block;
   font-size: clamp(13px, 2vw, 16px);
   font-weight: 700;
   text-transform: uppercase;
   letter-spacing: 0.02em;
}

/* Rows-chart full-width image — caps width so 2000px-wide source images
   don't dominate the page; click-to-enlarge opens the original in a new
   tab (preserved ti.2 behavior). */
.sa-landing-rows-chart-link {
   display: block;
   max-width: 720px;
   margin: 0;
}
.sa-landing-rows-chart-link img {
   display: block;
   width: 100%;
   height: auto;
   border-radius: 8px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
}

/* Seats mini-guide — body paragraph styling matches existing prose. */
.sa-landing-seats-guide p {
   margin: 0;
   max-width: 720px;
   font-size: 14px;
   line-height: 1.55;
   color: var(--text-default);
}


/* ═══════════════════════════════════════════════════════════════════════
   SEATING-CHART DETAIL (view=seating-chart with chart_id)
   ──────────────────────────────────────────────────────────────────────
   Reuses panel+map stage. Explore-items list on the left, real
   interactive map on the right (existing section-rail), postmap blocks
   below. Visual targets ti.2's #list-explore-map sidebar pattern.
   ═══════════════════════════════════════════════════════════════════════ */

main.sa-seating-chart h1 {
   margin: 8px 0 14px;
   font-size: clamp(20px, 2.4vw, 28px);
   line-height: 1.2;
}

/* Explore-items list — small thumbnail-left tiles. Ports ti.2's
   `#list-explore-map li` (styles-default-wide.css:67-77). */
.sa-explore { margin: 0 0 16px; }
.sa-explore-heading {
   margin: 0 0 12px;
   font-size: 14px;
   font-weight: 700;
   letter-spacing: 0.02em;
   color: var(--text-default);
}
.sa-explore-list {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   flex-direction: column;
   gap: 8px;
}
.sa-explore-tile {
   position: relative;
   display: flex;
   align-items: center;
   gap: 12px;
   padding: 8px;
   padding-left: 80px;
   min-height: 72px;
   background: #fff;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
   border-radius: 10px;
   cursor: pointer;
   transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.sa-explore-tile:hover {
   border-color: var(--color-primary, #002448);
   box-shadow: 0 2px 8px rgba(7, 18, 41, 0.06);
}
.sa-explore-tile.is-secondary { display: none; }
.sa-explore-tile.is-secondary.is-expanded { display: flex; }

/* Mobile chart-detail — explore panel lives BELOW the map. Transform
   the zone-tile list into a horizontal scroll-snap row showing just
   title + "from $X" (drops the photo, find-a-section, and guide tiles
   from the slider since they're not zones). Hidden entirely when an
   event is selected — at that point the map's ticket markers + the
   tickets panel below own the user's attention. */
@media (max-width: 879px) {
   main.sa-seating-chart .panel-explore {
      padding: 0;
      box-shadow: none;
      margin-top: calc( -1 * var(--scene-gap));
      background: #f3f4f6 !important;
      padding-left: 16px;
   }
   main.sa-seating-chart .panel-explore .sa-explore-heading {
      display: none;
   }
   main.sa-seating-chart .panel-explore .sa-explore-list-zones {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      gap: 12px;
      padding: 0;
      margin: 0;
      list-style: none;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
   }
   main.sa-seating-chart .panel-explore .sa-explore-list-zones::-webkit-scrollbar { display: none; }
   main.sa-seating-chart .panel-explore .sa-explore-tile {
      flex: 0 0 auto;
      min-width: 0;
      width: 168px;
      min-height: 0;
      padding: 14px 14px 12px;
      flex-direction: column;
      align-items: stretch;
      justify-content: space-between;
      gap: 10px;
      background: #fff;
      border: 1px solid var(--sa-border-soft, #e5e7eb);
      border-radius: 12px;
      box-shadow: 0 1px 3px rgba(0, 36, 72, 0.06);
      scroll-snap-align: start;
   }
   main.sa-seating-chart .panel-explore .sa-explore-tile:hover {
      border-color: var(--color-primary, #002448);
      box-shadow: 0 2px 8px rgba(7, 18, 41, 0.08);
   }
   /* Drop photos + secondary chrome from the slim mobile slider —
      Find a Section stays (primary entry point); hide only guide +
      see-more (utility/footer affordances). */
   main.sa-seating-chart .panel-explore .sa-explore-tile > img { display: none; }
   main.sa-seating-chart .panel-explore .sa-explore-tile-guide,
   main.sa-seating-chart .panel-explore .sa-explore-tile-more { display: none; }
   main.sa-seating-chart .panel-explore .sa-explore-tile-find-section .sa-explore-tile-title,
   main.sa-seating-chart .panel-explore .sa-explore-tile-zone .sa-explore-tile-title {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      line-clamp: 2;
      overflow: hidden;
      font-size: 14px;
      font-weight: 700;
      line-height: 1.25;
      color: var(--color-primary, #002448);
      margin: 0;
   }
   /* "from $X" — override the desktop's right-aligned floor; on mobile
      it reads cleaner as a left-aligned secondary line under the title. */
   main.sa-seating-chart .panel-explore .sa-explore-tile-zone .sa-explore-tile-price {
      align-self: flex-start;
      margin-left: 0;
      font-size: 13px;
      font-weight: 600;
      color: var(--color-70, rgba(0, 36, 72, 0.70));
   }
}
/* Hide the explore panel entirely on mobile when an event is selected
   (chart wrap stamps `.is-event-mode`). Widescreen stays visible — it
   sits in the left column always. */
@media (max-width: 879px) {
   body:has(.sc-map-wrap.is-event-mode) main.sa-seating-chart .panel-explore {
      display: none;
   }
}
.sa-explore-tile > img {
   position: absolute;
   left: 8px;
   top: 50%;
   transform: translateY(-50%);
   width: 56px;
   height: 56px;
   border-radius: 6px;
   object-fit: cover;
   background: var(--color-05, rgba(0, 36, 72, 0.04));
}
.sa-explore-tile-body {
   /* Vertical stack: name on top, date underneath. The body wraps both
      so the flex row remains [avatar][body][price?] without the date
      drifting to the far right via margin-left: auto. */
   display: flex;
   flex-direction: column;
   gap: 2px;
   min-width: 0;
   flex: 1 1 auto;
}
.sa-explore-tile-title {
   font-size: 16px;
   font-weight: 400;
   color: var(--color-primary, #002448);
   line-height: 1.2;
}
.sa-explore-tile-date {
   font-size: 12px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
}
/* "from $X" — appended by SeatingChartExploreCtrl.onTicketsLoaded when the
   filteredTickets pool has at least one ticket in any of the tile's
   data-zone-sections. Removed (not just blanked) when no match exists so
   the tile reads as plain. */
.sa-explore-tile-price {
   margin-left: auto;
   font-size: 13px;
   font-weight: 700;
   color: var(--color-primary, #002448);
}
.sa-explore-tile-zone .sa-explore-tile-title {
   /* Zone tiles let the title break to two lines if needed. */
   display: -webkit-box;
   -webkit-line-clamp: 2;
   -webkit-box-orient: vertical;
   overflow: hidden;
}
.sa-explore-tile-guide {
   /* Inherit the same border + padding + hover treatment as the other
      explore tiles. Earlier draft zeroed the border + padding here to
      let the inner <a> own them; result was a borderless guide tile
      that read as inconsistent next to its siblings. */
   padding: 0;
   min-height: 72px;
}
.sa-explore-tile-guide a {
   display: flex;
   align-items: center;
   gap: 12px;
   padding: 8px;
   padding-left: 80px;
   width: 100%;
   color: inherit;
   text-decoration: none;
   position: relative;
   min-height: 72px;
}
.sa-explore-tile-guide a img {
   position: absolute;
   left: 8px;
   top: 50%;
   transform: translateY(-50%);
   width: 56px;
   height: 56px;
   border-radius: 6px;
   object-fit: cover;
}
.sa-explore-tile-more {
   justify-content: center;
   padding-left: 8px;
   color: var(--color-primary-soft, #0067CE);
   font-weight: 600;
   font-size: 14px;
   min-height: 44px;
}
.sa-explore-tile-more > .sa-explore-tile-title {
   margin: 0;
}

/* ─────────────────────────────────────────────────────────────────────
   Explore-item content overlay (event-mode tile click target)
   Two shapes by breakpoint:
     - Mobile (<880px): pull-up bottom sheet. Starts at translateY(60vh)
       so ~40vh is visible; map peeks above. Drag the header (or scroll
       past zero in the body) to reveal more — translateY decreases to 0
       and the sheet fully covers the map.
     - Widescreen (≥880px): absolute-positioned takeover of `.panel-top`
       (panel-top is `position: relative` via lib-overrides). Fades in
       opaque white, occupying the full panel-top box.
   ─────────────────────────────────────────────────────────────────── */
.sa-explore-overlay {
   position: fixed;
   left: 0; right: 0; bottom: 0;
   height: 100dvh;
   background: #fff;
   z-index: 9000;
   transform: translateY(60vh);
   transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
   border-radius: 16px 16px 0 0;
   box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.15);
   display: flex;
   flex-direction: column;
   overflow: hidden;
   touch-action: none;
}
.sa-explore-overlay[hidden] { display: none; }
.sa-explore-overlay.is-dragging { transition: none; }
.sa-explore-overlay.is-expanded { transform: translateY(0); }

.sa-explore-overlay-header {
   flex-shrink: 0;
   padding: 8px 16px 14px;
   background: #fff;
   cursor: grab;
}
.sa-explore-overlay-header:active { cursor: grabbing; }
.sa-explore-overlay-drag {
   display: block;
   width: 36px; height: 4px;
   background: #d4d6db;
   border-radius: 2px;
   margin: 4px auto 12px;
}
.sa-explore-overlay-header-row {
   display: flex;
   align-items: flex-start;
   gap: 12px;
}
/* Back / info / close buttons offset 6px down from the row top —
   vertically centers on a 2-line header (title + subtitle) and reads
   cleanly on 3-line section headers (title + rating + subtitle) where
   strict vertical centering would push the buttons too low. */
.sa-explore-overlay-back,
.sa-explore-overlay-info,
.sa-explore-overlay-close {
   margin-top: 6px;
}
.sa-explore-overlay-meta {
   flex: 1; min-width: 0;
}
.sa-explore-overlay-title {
   font-size: 19px;
   font-weight: 700;
   margin: 0;
   color: var(--color-primary);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}
.sa-explore-overlay-subtitle {
   font-size: 13px;
   color: var(--color-70);
   margin: 2px 0 0;
}
.sa-explore-overlay-actions {
   display: flex; gap: 8px;
   flex-shrink: 0;
}
.sa-explore-overlay-info,
.sa-explore-overlay-close,
.sa-explore-overlay-back {
   width: 34px; height: 34px;
   border-radius: 50%;
   border: 1px solid #e2e4e8;
   background: #fff;
   color: var(--color-90);
   display: inline-flex;
   align-items: center;
   justify-content: center;
   cursor: pointer;
   text-decoration: none;
   padding: 0;
   flex-shrink: 0;
}
/* SVG icon children steal the hover unless we tell them not to —
   without this the cursor reverts to default the moment the user
   moves over the icon mid-button. */
.sa-explore-overlay-info > svg,
.sa-explore-overlay-close > svg,
.sa-explore-overlay-back > svg {
   pointer-events: none;
   display: block;
}
.sa-explore-overlay-back { margin-right: 4px; }
.sa-explore-overlay-back[hidden] { display: none; }
.sa-explore-overlay-info:hover,
.sa-explore-overlay-close:hover {
   background: #f6f7f9;
   border-color: #cbd0d8;
}
.sa-explore-overlay-info[hidden] { display: none; }

.sa-explore-overlay-body {
   flex: 1;
   overflow-y: auto;
   -webkit-overflow-scrolling: touch;
   padding: 16px;
   touch-action: pan-y;
}

/* Widescreen — panel takeover. The overlay sits directly inside the
   stage grid (sibling of panel-top / panel-bottom / map). Overlay-
   open state collapses panel-bot via a stage class (`main.has-explore-
   overlay`); overlay then occupies the panel-top grid cell at its
   natural content height. Map stays sticky/tall via its own existing
   rules (lib-overrides.css), so the right column always reads correctly
   regardless of overlay length. Sticky header lives inside the overlay
   body so the title row pins as the page scrolls. */
@media (min-width: 880px) {
   .sa-explore-overlay {
      position: relative;
      grid-column: 1;
      grid-row: 1;
      align-self: start;
      height: auto;
      transform: none;
      transition: opacity 0.18s ease;
      opacity: 0;
      pointer-events: none;
      border-radius: 0;
      box-shadow: 10px 0 10px -10px rgba(0, 0, 0, 0.10);
      touch-action: auto;
      z-index: 5;
      background: #fff;
      padding: 0 var(--sa-page-pad-desktop, 24px);
      height: 100%;
   }
   .sa-explore-overlay[hidden] { display: none; }
   .sa-explore-overlay.is-expanded {
      opacity: 1;
      pointer-events: auto;
   }
   .sa-explore-overlay-drag { display: none; }
   .sa-explore-overlay-header {
      cursor: default;
      padding: 16px 0;
      position: sticky;
      top: 0;
      background: #fff;
      z-index: 2;
   }
   .sa-explore-overlay-body {
      flex: 0 0 auto;
      overflow: visible;
      padding: 0 0 24px;
   }
   /* Stage-level "overlay is open" gate — collapse panel-bot so the
      grid row vanishes; the page scroll becomes the single scrollbar
      (no internal overlay scroll). Map keeps its `position: sticky`
      from lib-overrides so it stays viewport-tall on the right.  */
   main[data-show='panel+map'].has-explore-overlay [data-layout='panel'].panel-bottom,
   main[data-show='panel+map'].has-explore-overlay [data-layout='panel'].panel-explore {
      display: none;
   }
   main[data-show='panel+map'].has-explore-overlay [data-layout='stage'] {
      grid-template-areas: "panel-top map";
   }
   /* Hide the underlying panel-top contents while the overlay is open
      so the picker / explore tiles don't bleed through behind the
      overlay's content. */
   main[data-show='panel+map'].has-explore-overlay [data-layout='panel'].panel-top {
      visibility: hidden;
   }
}
/* Mobile: when the overlay is open as a sheet, hide the page's
   panel-explore so it doesn't peek out from under the overlay when
   the user scrolls past the sheet's bottom edge. (panel-top + panel-
   bottom remain in flow on mobile but are obscured by the fixed
   overlay; panel-explore lives between them in DOM and would otherwise
   show through.) */
@media (max-width: 879px) {
   main[data-show='panel+map'].has-explore-overlay [data-layout='panel'].panel-explore {
      display: none;
   }
}

/* ─────────────────────────────────────────────────────────────────────
   Explore overlay — body content (section + zone detail render)
   ─────────────────────────────────────────────────────────────────── */
.sa-explore-body-loading { display: grid; gap: 10px; }
.sa-explore-body-skeleton {
   height: 18px; background: #eef0f3; border-radius: 6px;
   animation: sa-explore-pulse 1.4s ease-in-out infinite;
}
@keyframes sa-explore-pulse {
   0%, 100% { opacity: 1; }
   50%      { opacity: 0.55; }
}
.sa-explore-section { padding: 0; }
.sa-explore-section-h {
   font-size: 14px; font-weight: 700; letter-spacing: 0.02em;
   color: var(--color-90); margin: 0 0 10px;
}

/* SeatScore tile (insights below it reuse the design-system
   `.sa-keyinfo-*` styling — see `views/key-insights.php`). */
.sa-explore-score {
   display: inline-flex; align-items: baseline; gap: 8px;
   padding: 8px 12px; margin: 0 0 10px;
   background: var(--color-05); border-radius: 8px;
}
.sa-explore-score-num { font-size: 24px; font-weight: 700; color: var(--color-primary); }
.sa-explore-score-cat { font-size: 12px; color: var(--color-70); text-transform: uppercase; letter-spacing: 0.06em; }

/* Sections list (renders inside the overlay body when the user hits
   "Find a Section" or the All Sections list endpoint). */
.sa-explore-section-list {
   list-style: none;
   padding: 0;
   margin: 0;
   display: grid;
   gap: 6px;
}
.sa-explore-section-list-btn {
   display: block;
   width: 100%;
   text-align: left;
   padding: 16px 18px;
   background: #fff;
   border-radius: 8px;
   cursor: pointer;
   font: inherit;
   color: var(--color-90);
}
.sa-explore-section-list-btn:hover {
   background: #fafbfc;
   border-color: var(--color-primary, #002448);
}
.sa-explore-empty {
   color: var(--color-70);
   font-size: 13px;
   margin: 0;
}

/* Cover photo / slider at top of section/zone overlay. The reused
   `.sa-seat-views` rules drive the visual treatment (rounded corners,
   object-fit, captions); these overlay-scoped overrides constrain the
   slot so a wide left panel doesn't produce a 500-700px-tall hero.
   ~280px max keeps the cover inviting without dominating the surface. */
.sa-explore-overlay .sa-seat-views .sa-sv-photo,
.sa-explore-overlay .sa-seat-views .sa-sv-slider {
   height: clamp(180px, 26vw, 260px);
   max-height: 260px;
   margin-bottom: 12px;
   aspect-ratio: auto;   
}
.sa-explore-cover-slider {
   display: block;
}

/* Explore-overlay only — selected-event card sits as the first item
   inside the tickets panel. Negative top margin pulls it flush against
   the tab bar; bottom border + scene-gap separate it from the toggle/
   list below. */
.sa-explore-overlay .sa-cp-selected {
   width: 100%;
   padding: 16px;
   border-bottom: 1px solid #e5e5e5;
   margin-top: -16px;
   margin-bottom: var(--scene-gap);
}

/* Explore-overlay footer "All {Name} Details" pill. Widescreen pins it
   to the overlay container's bottom-180px so it doesn't scroll with
   the body content. Narrow screens (the mobile sheet) render it in-flow
   at the end of the content — pinning it would float the pill over the
   scrolling content and read confusingly. */
@media (min-width: 880px) {
   .sa-explore-overlay .sa-explore-content-footer {
      position: absolute;
      bottom: 180px;
      padding: 16px;
      width: 100%;
      left: 0;
   }
}

/* Tickets panel — wraps `.sa-hero-sel-available` so it inherits the
   existing toggle / list / pagination styling from the full sec/zone
   pages. New additions: an event-card block (name + date + hint) right
   under the title. */
.sa-hero-sel-available-evcard {
   display: flex; align-items: center; gap: 12px;
   padding: 12px; margin: 0 0 10px;
   background: var(--color-05);
   border-radius: 6px;
}
.sa-hero-sel-available-evcard-text {
   flex: 1 1 auto; min-width: 0;
   display: flex; flex-direction: column; gap: 2px;
}
.sa-hero-sel-available-evcard-name {
   font-size: 14px; font-weight: 600; color: var(--color-primary);
}
.sa-hero-sel-available-evcard-when {
   font-size: 12px; color: var(--color-70);
}
.sa-hero-sel-available-evcard-hint {
   font-size: 12px; color: var(--color-70);
   font-style: italic; margin-top: 4px;
}
.sa-hero-sel-available-empty {
   color: var(--color-70); font-size: 13px; margin: 0;
}
/* No-event placeholder — replaces the available-tickets list when the
   user clears the event while the overlay is open. CTA opens the
   picker; once an event is picked, `_renderTicketsPanel` re-fires and
   the panel fills back in. */
.sa-explore-no-event {
   display: flex;
   flex-direction: column;
   align-items: flex-start;
   gap: 10px;
   padding: 14px;
   background: #fbfbfb;
   border-radius: 8px;
}
.sa-explore-no-event-msg {
   margin: 0;
   font-size: 14px;
   color: var(--color-90);
   line-height: 1.4;
}

/* Media + reviews sliders */
.sa-explore-media-slide img {
   display: block; width: 100%; aspect-ratio: 1.43;
   object-fit: cover; border-radius: 8px;
}
.sa-explore-zone-review {
   font-size: 14px; color: var(--color-90); line-height: 1.5;
   display: -webkit-box; -webkit-line-clamp: 6; line-clamp: 6;
   -webkit-box-orient: vertical; overflow: hidden;
   margin: 0;
}
.sa-explore-zone-readmore {
   margin-top: 6px;
   font-size: 14px;
   font-weight: 600;
   color: var(--color-primary);
   background: transparent;
   border: 0;
   padding: 0;
   cursor: pointer;
}
.sa-explore-zone-readmore:hover { text-decoration: underline; }
.sa-explore-review-card {
   padding: 12px; background: #fff; border: 1px solid #ececec;
   border-radius: 8px; height: 100%;
}
.sa-explore-review-rating {
   font-size: 12px; font-weight: 600; color: #d97706; margin-bottom: 6px;
}
.sa-explore-review-body {
   font-size: 13px; color: var(--color-90); margin: 0 0 6px; line-height: 1.4;
}
.sa-explore-review-author {
   font-size: 11px; color: var(--color-70); margin: 0;
}

/* Footer "All {name} Details" — full-width white pill. Same visual
   treatment as the Other Events tile on the seating-chart landing
   (white bg, primary-color text, soft border, pill radius). No arrow. */
.sa-explore-content-seeall {
   display: flex;
   align-items: center;
   justify-content: center;
   width: 100%;
   min-height: 48px;
   padding: 12px 16px;
   background: #fff;
   color: var(--color-primary, #002448);
   border: 1px solid #CCC;
   border-radius: 24px;
   text-align: center;
   text-decoration: none;
   font-weight: 600;
   font-size: 14px;
   transition: background-color 0.15s ease;
}
.sa-explore-content-seeall:hover {
   background: var(--color-05, rgba(0, 36, 72, 0.04));
   text-decoration: none;
}
.sa-explore-content-seeall > i[data-is="icon"] {
   margin-left: 8px;
   width: 14px;
   height: 14px;
}
/* "Open in new window" icon — registered here (overlay-scoped) since
   no other place currently uses it. Same `[data-is="icon"]` mask pattern
   the design-system base rule consumes. */
[data-is="icon"][data-icon="external-link"] {
   --icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m16 8.4l-8.9 8.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7L14.6 7H7q-.425 0-.712-.288T6 6t.288-.712T7 5h10q.425 0 .713.288T18 6v10q0 .425-.288.713T17 17t-.712-.288T16 16z'/%3E%3C/svg%3E");
}
/* Mobile only — push the "All {Name} Details" pill down so it visually
   separates from the cp-selected strip + body content above. Widescreen
   uses absolute positioning so no offset needed there. */
@media (max-width: 879px) {
   .sa-explore-overlay .sa-explore-content-footer {
      margin-top: calc(var(--scene-gap) * 2);
   }
}

/* Section-only rating meta line under the title — "3.1 ★★★ - Good Seats".
   Populated by `_renderHeaderMeta`; hidden on zones and on sections with
   no resolved score for the locked event type. */
.sa-explore-overlay-rating {
   margin: 4px 0 0;
   font-size: 13px;
   line-height: 1.3;
   color: var(--color-primary, #002448);
   display: flex;
   align-items: center;
   gap: 6px;
   flex-wrap: wrap;
}
.sa-explore-overlay-rating[hidden] { display: none; }
.sa-explore-rating-score {
   font-weight: 700;
}
.sa-explore-rating-stars {
   color: #f6b73c;
   letter-spacing: 1px;
}
.sa-explore-rating-cat {
   color: var(--color-70, rgba(0, 36, 72, 0.70));
}

/* Insights chips — header-less variant lives above the photos slider
   in the overlay. The shared `.sa-keyinfo-grid` rule already styles the
   chips themselves; just trim the top spacing the standalone scene
   would normally bring. */
.sa-explore-insights {
   margin: 0 0 14px;
}
/* Overlay-only insight tiles get a tinted background + tighter padding
   so they read as a distinct "at-a-glance" strip above the photos. */
.sa-explore-overlay .sa-keyinfo-tile {
   background: #f1f5fc;
   padding: 12px;
}

/* Tabs — Tickets / Reviews. Underline-active style; full-width row
   sitting under the photos slider. */
.sa-explore-tabs {
   display: flex;
   gap: 0;
   margin: 18px 0 14px;
   border-bottom: 1px solid var(--sa-border-soft, #e5e7eb);
}
.sa-explore-tab {
   flex: 1 1 0;
   padding: 12px 8px;
   background: none;
   border: none;
   border-bottom: 2px solid transparent;
   margin-bottom: -1px;
   font-size: 14px;
   font-weight: 600;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
   cursor: pointer;
   transition: color 0.15s ease, border-color 0.15s ease;
}
.sa-explore-tab:hover {
   color: var(--color-primary, #002448);
}
.sa-explore-tab.is-active {
   color: var(--color-primary, #002448);
   border-bottom-color: var(--color-primary, #002448);
}
.sa-explore-tab-panel[hidden] { display: none; }
.sa-explore-tab-panel { min-width: 0; }

/* Stacked reviews / questions inside the Reviews tab. Container caps
   width to the panel so long copy can't push children past the overlay
   edge (the `[data-rr="fan-item"]` cards came from the section-page
   slider where they sized to a slide width). */
.sa-explore-reviews-list,
.sa-explore-questions-list {
   margin: 16px 0 0;
   min-width: 0;
}
.sa-explore-reviews-stack,
.sa-explore-questions-stack {
   list-style: none;
   margin: 8px 0 0;
   padding: 0;
   display: flex;
   flex-direction: column;
   gap: 10px;
}
.sa-explore-review-item,
.sa-explore-question-item {
   max-width: 100%;
   min-width: 0;
}
.sa-explore-review-item > [data-rr="fan-item"],
.sa-explore-question-item > [data-qa="card"] {
   width: 100%;
   max-width: 100%;
   box-sizing: border-box;
}

/* Postmap — main static chart image */
.sa-seating-chart-static {
   margin-block-start: clamp(20px, 3vw, 32px);
}
.sa-seating-chart-static h2 {
   margin: 0 0 12px;
}
.sa-seating-chart-static-link {
   display: block;
   margin: 0 0 16px;
}
.sa-seating-chart-static-link img {
   display: block;
   width: 100%;
   max-width: 720px;
   height: auto;
   border-radius: 8px;
   border: 1px solid var(--sa-border-soft, #e5e7eb);
}
/* Concert paragraph — plain body copy with an embedded CTA. NOT a
   disclaimer (no italics, no muted color). Keeps the legacy class
   `.sa-seating-chart-disclaimer` for now so other consumers don't
   break; treatment matches the rest of the page's body text. */
.sa-seating-chart-disclaimer {
   margin: 0 0 20px;
   max-width: 720px;
   font-size: 15px;
   line-height: 1.55;
   color: var(--text-default);
}

/* Other Seating Charts — ti.2 parity: 90×72 thumbnail row with overlaid
   label, inline-flex so multiple charts wrap naturally on narrow space. */
.sa-seating-chart-other-heading {
   margin: 24px 0 12px;
}
.sa-seating-chart-other {
   list-style: none;
   padding: 0;
   margin: 0;
   display: flex;
   flex-wrap: wrap;
   gap: 16px;
}
.sa-seating-chart-other-item {
   width: 90px;
   height: 72px;
   position: relative;
   border-radius: 8px;
   overflow: hidden;
   transition: opacity 0.15s ease;
}
.sa-seating-chart-other-item:hover {
   opacity: 0.85;
   cursor: pointer;
}
.sa-seating-chart-other-item a {
   display: block;
   width: 100%;
   height: 100%;
   text-decoration: none;
   color: inherit;
}
.sa-seating-chart-other-item img {
   display: block;
   width: 100%;
   height: 100%;
   object-fit: cover;
   border-radius: 8px;
}
.sa-seating-chart-other-label {
   position: absolute;
   left: 0;
   right: 0;
   bottom: 0;
   padding: 3px 4px;
   background: rgba(255, 255, 255, 0.90);
   font-size: 10px;
   font-weight: 600;
   color: var(--text-default);
   line-height: 1.15;
   text-align: center;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

/* Upcoming Shows (concert/theater) */
.sa-seating-chart-upcoming {
   margin-block-start: clamp(20px, 3vw, 32px);
}
.sa-seating-chart-upcoming h2 {
   margin: 0 0 12px;
}
/* Collapsed-card pattern — header always visible; image + footer revealed
   when `.is-expanded` is added on header click (toggle in scripts-ready.js).
   Matches ti.2's `#section-seating-charts-upcoming` interaction. */
.sa-upcoming-card {
   border-top: 1px solid var(--sa-border-soft, #e5e7eb);
   padding: 10px 0;
   position: relative;
}
.sa-upcoming-card:last-child {
   border-bottom: 1px solid var(--sa-border-soft, #e5e7eb);
}
.sa-upcoming-card:not(.is-expanded):hover {
   background: var(--item-hover-bg, rgba(0, 0, 0, 0.03));
   cursor: pointer;
}
.sa-upcoming-header {
   padding: 5px 30px 5px 10px;
   cursor: pointer;
   position: relative;
}
.sa-upcoming-toggle {
   position: absolute;
   right: 8px;
   top: 50%;
   transform: translateY(-50%);
   font-size: 16px;
   color: var(--text-default);
}
.sa-upcoming-date {
   display: block;
   font-size: 11px;
   text-transform: uppercase;
   margin-bottom: 5px;
   color: var(--color-70, rgba(0, 36, 72, 0.70));
}
.sa-upcoming-name {
   margin: 0;
   font-size: 15px;
   line-height: 1.3;
}
.sa-upcoming-image,
.sa-upcoming-footer {
   display: none;
}
.sa-upcoming-card.is-expanded .sa-upcoming-image {
   display: block;
   width: 100%;
   height: auto;
   margin: 15px 0 15px;
}
.sa-upcoming-card.is-expanded .sa-upcoming-footer {
   display: block;
   padding: 10px;
}
.sa-upcoming-footer .btn-primary {
   width: 100%;
}

/* Team info paragraph */
.sa-seating-chart-team-info {
   margin-block-start: clamp(20px, 3vw, 32px);
}
.sa-seating-chart-team-info h2 {
   margin: 0 0 10px;
}
.sa-seating-chart-team-info p {
   margin: 0;
   max-width: 720px;
   font-size: 14px;
   line-height: 1.55;
   color: var(--text-default);
}
