/* ============================================================================
   Seating Chart · Map Slot
   ============================================================================
   Drop-in map layer. Depends on lib/base CSS variables (loaded by the host):
      --color-primary, --color-brand, --text-default, --text-low, --text-medium,
      --outline-color, --outline-color-light, --bg-light-blue,
      --border-radius-sm/-m, --font-family, --font-size-*
   plus lib/interactive-map base styles for SVG polygons.

   Self-contained; no `.sc-shell` / `.sc-sidebar` references. Host page only
   needs to mount a container and pass it to the SeatingChart class.
   ========================================================================= */

/* ── Local tokens (only what lib/base doesn't already give us) ─────────── */
:root {
   --sc-marquee-pink: #ef356c;
   --sc-warm:         #f8b94a;
   --sc-hot:          #e84747;
}

/* ── Map surface ──────────────────────────────────────────────────────── */
.sc-map-wrap {
   position: absolute;
   inset: 0;
   font-family: var(--font-family);
   color: var(--text-default);
}
.sc-map {
   width: 100%;
   height: 100%;
   overflow: hidden;
   position: relative;
   /* Map text (section labels, flag prices, debug pills) should never be
      selectable — drag-to-select fights the pan gesture and looks like a
      bug on mobile. */
   user-select: none;
   -webkit-user-select: none;
   -webkit-touch-callout: none;
}
.sc-map > svg {
   width: 100%;
   height: 100%;
   display: block;
   touch-action: none;
}

/* ── Polygons (host can swap fill via color schemes) ──────────────────── */
.sc-map {
   --poly-fill:  #E5E1F2;
   --poly-label: #d4cee8;
}
/* `:not([data-dyn='1'])` keeps dynamic polygons (lib renders these with an
   API-supplied per-polygon fill — see interactive-map.js:237-243) safe from
   our overrides. Reserved stage/ring polys also keep their lib-defined fills.
   When adding new override rules to this file, ALWAYS chain
   `:not([data-dyn='1'])` so dynamic geometry stays untouched. */
.sc-map polygon[data-id]:not([data-dyn='1']):not([data-id="static_stage"]):not([data-id="b_stage"]):not([data-id="fighting_ring"]) {
   fill: var(--poly-fill);
   stroke: var(--outline-color);
   stroke-width: 0.6;
   transition: fill 200ms ease;
   /* Polygons are not click targets — the cursor stays default so users
      don't read "clickable" affordance on the section itself. (The
      lib's base CSS sets `cursor: pointer` on every polygon.) */
   cursor: default;
}
.sc-map text.im-section-label {
   fill: var(--poly-label);
   font-weight: 700;
}
/* Zone-matching section labels get a darker shade so they read clearly
   against the elevated `#d2c7f6` zone fill. JS stamps `data-zone-section`
   on both the polygon AND its sibling label `<text data-id>` (see
   `seating-chart.js` paintColoredSectionsForMultiSectionZone). Applies
   to full-section AND row-scoped (partial) matches. */
.sc-map text.im-section-label[data-zone-section] {
   fill: #bfb2e8;
}

/* Sections without tickets in the current mode get muted — JS stamps
   `data-has-tickets="1"` on the polygon AND its <text data-id> sibling for
   every section that has inventory. The reserved stage/ring polys are
   excluded so they keep their lib-defined black. Dynamic polys
   (`data-dyn='1'`) are also excluded so the API-set fill stays. */
.sc-map polygon[data-id]:not([data-dyn='1']):not([data-has-tickets]):not([data-id="static_stage"]):not([data-id="b_stage"]):not([data-id="fighting_ring"]) {
   fill:   #fbfbfb !important;
   stroke: #f5f5f5;
}
.sc-map text[data-id]:not([data-dyn]):not([data-has-tickets]) {
   fill: #e5e5e5;
}
/* Polygon color schemes removed — locked in on the default lavender. */

/* Heatmap off → override inline style.fill set by JS. Constrained to
   sections that HAVE tickets so the no-ticket mute rule below still wins
   for empty sections. Dynamic polys (`data-dyn='1'`) excluded so the
   lib's per-polygon API fill is preserved. */
.sc-map-wrap[data-hide-heatmap] .sc-map polygon[data-id][data-has-tickets]:not([data-dyn='1']):not([data-id="static_stage"]):not([data-id="b_stage"]):not([data-id="fighting_ring"]) {
   fill: var(--poly-fill) !important;
   fill-opacity: 1 !important;
}

/* ── Multi-section zone page: focus-zone section group ────────────────────
   `applyZoneSectionStyling()` stamps `data-zone-section="1"` on every
   section in the focus zone. The group reads as one unit: a distinct
   color fill (when it has inventory) + a PROMINENT stroke that persists
   regardless of inventory (overrides the faint no-ticket mute stroke).
   The fill still follows the normal has-tickets/no-tickets mute — colored
   when there's inventory, washed to #fbfbfb when not — so a filtered-out
   section in the zone still shows its outline but loses its color. */
/* Zone-matching sections OR section-page focus section: darker-lavender
   outline signals "in your context" + elevated fill when there are
   tickets. `data-zone-section` covers zone pages; `data-page-section`
   covers section pages (stamped on the page's focus section by
   markSectionsWithTickets). Both treated as full matches — partial
   (row-scoped) variant below keeps its own treatment. */
.sc-map polygon[data-zone-section]:not([data-dyn='1']),
.sc-map polygon[data-page-section]:not([data-dyn='1']) {
   stroke: var(--zone-section-stroke, #6b5fa3) !important;
   stroke-width: 1.8 !important;
}
.sc-map polygon[data-zone-section][data-has-tickets]:not([data-dyn='1']),
.sc-map polygon[data-page-section][data-has-tickets]:not([data-dyn='1']),
.sc-map-wrap[data-hide-heatmap] .sc-map polygon[data-zone-section][data-has-tickets]:not([data-dyn='1']),
.sc-map-wrap[data-hide-heatmap] .sc-map polygon[data-page-section][data-has-tickets]:not([data-dyn='1']) {
   fill: #d2c7f6 !important;
   fill-opacity: 1 !important;
}
/* Row-scoped zone sections: same outline color, plus dashed pattern as
   the partial-scope visual cue. No elevated fill — partial scope shades
   by inventory like any other section. */
.sc-map polygon[data-zone-section-partial]:not([data-dyn='1']) {
   stroke: var(--zone-section-stroke, #6b5fa3) !important;
   stroke-width: 1.8 !important;
   stroke-dasharray: 4 3 !important;
}

/* ── Event-mode SVG zone labels ───────────────────────────────────────── */
/* Two-line label rendered as inline SVG <text> (vs. the HTML chrome flag).
   White stroke + colored fill via `paint-order: stroke` provides a halo
   over polygon fills without a drop shadow. Layer sits under markers/
   flags/prices but above polygons.
   `pointer-events: bounding-box` makes the whole bbox of each label group
   hoverable (default for SVG text would only hit painted glyphs). */
.sc-event-zone-labels { pointer-events: none; }
.sc-event-zone-labels .sc-zone-label-svg {
   pointer-events: bounding-box;
   cursor: pointer;
}
/* The lib sets `text:not([data-dyn]) { pointer-events: none }`, which kills
   :hover on the SVG zone-label text. Override on our zone-label text + tspans
   so hovering the actual glyphs fires :hover (specificity (0,3,1) beats the
   lib's (0,1,1)). Belt-and-suspenders with bounding-box on the group. */
.sc-event-zone-labels .sc-zone-label-svg text,
.sc-event-zone-labels .sc-zone-label-svg tspan {
   pointer-events: all;
}
.sc-event-zone-labels text {
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   fill: #5869b2;
   stroke: #ffffff;
   /* em-based so the halo stays a fixed fraction of glyph height at every
      zoom level. Fixed user-unit strokes turn into letter-eating blobs at
      deep zoom (where `_scaleLabelsByZoom` shrinks the SVG font-size). */
   stroke-width: 0.18em;
   paint-order: stroke fill;
   text-anchor: middle;
   font-weight: 700;
   transition: fill 120ms ease;
}
.sc-event-zone-labels .sc-zls-from {
   font-weight: 500;
   fill: #5869b2;
}
/* Hover: color shifts to link-blue. */
.sc-event-zone-labels .sc-zone-label-svg:hover text,
.sc-event-zone-labels .sc-zone-label-svg:hover .sc-zls-from {
   fill: #0067ce;
}
.sc-event-zone-labels .sc-zone-label-svg:active {
   opacity: 0.85;
}

/* Popped state — host calls `popZoneLabel(zoneId)` (e.g. on SA zone-tile
   hover) and we briefly emphasize the label so the user can locate it.
   SVG label gets the same color shift + bold weight as :hover, plus a
   drop-shadow halo for at-a-glance pop. No CSS `transform` here — the
   group's `transform` attribute already encodes its translate; a CSS
   transform rule would replace it and move the label to (0,0). */
.sc-event-zone-labels .sc-zone-label-svg.is-popped {
   filter: drop-shadow(0 0 6px rgba(0, 103, 206, 0.55));
   transition: filter 0.18s ease;
}
.sc-event-zone-labels .sc-zone-label-svg.is-popped text,
.sc-event-zone-labels .sc-zone-label-svg.is-popped .sc-zls-from {
   fill: #0067ce;
   font-weight: 700;
}
/* HTML zone-flag popped state — used for the `.sc-event-zone-flag` HTML
   variant (price + amenities chrome). Scale + box-shadow accent. */
.sc-zone-flag.is-popped {
   transform: scale(1.15);
   transform-origin: center bottom;
   transition: transform 0.18s ease, box-shadow 0.18s ease;
   box-shadow: 0 4px 14px rgba(0, 103, 206, 0.35);
   z-index: 50;
}

/* Host-driven section hover flag — same chrome as the sections-mode
   polygon-hover flag, just positioned at the section centroid by JS
   (`showSectionHoverFlag`). Pointer-events off so the host's hover
   tracking on its own UI isn't broken by this overlay. */
.sc-host-hover-flag {
   pointer-events: none;
}

/* Focus-zone label (zone page) — bolder than a normal zone label and
   carries a "Check Availability" CTA line instead of "from $X". Rendered
   by `placeFocusZoneLabel`, persists through ticket filtering. */
.sc-event-zone-labels .sc-zone-focus-label .sc-zls-name {
   font-weight: 700;
}
.sc-event-zone-labels .sc-zone-focus-label .sc-zls-cta {
   fill: #0067ce;
   font-weight: 700;
}

/* ── SVG zone-label hover CLONE ───────────────────────────────────────────
   Spawned by `spawnZoneLabelClone` in scripts.js on mouseenter of any
   `.sc-zone-label-svg`. Lives in `.sc-overlay-root` at a very high z-index
   so it visually paints ABOVE every other map element (marker flags, dots,
   other labels). Pointer-events: none — the underlying SVG label still
   owns hover coordination; the clone is purely visual. JS sets `left`,
   `top` (relative to `.sc-overlay-root`, which fills `.sc-map-wrap`), and
   `font-size` (matched to the SVG name text). */
.sc-zone-label-clone {
   position: absolute;
   transform: translate(-50%, -50%);
   pointer-events: none;
   z-index: 99999;
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   color: #0067ce;
   font-weight: 700;
   line-height: 1.05;
   white-space: nowrap;
   text-align: center;
   /* Eight-direction white halo mirrors the SVG `paint-order: stroke fill`
      look. Stroke width scales loosely with font-size so it doesn't
      under/over-paint at extreme zooms. */
   text-shadow:
      -2px -2px 0 #fff, 2px -2px 0 #fff,
      -2px  2px 0 #fff, 2px  2px 0 #fff,
       0   -2px 0 #fff, 0    2px 0 #fff,
      -2px  0   0 #fff, 2px  0   0 #fff;
}
.sc-zone-label-clone .sc-zlc-name  { font-size: 1em; }
.sc-zone-label-clone .sc-zlc-row   { font-size: 1em; font-weight: 500; margin-top: 0.05em; }
.sc-zone-label-clone .sc-zlc-from  { font-size: 0.833em; }
.sc-zone-label-clone .sc-zlc-price { font-size: 1em; }

/* ── Browse mode (no event selected) ───────────────────────────────────
   Focus marker + inline section name + zone labels are SVG; the CTA
   gradient flag + low-price flag + best-seatscore flag + per-section
   flags are HTML overlays in the scaled overlay layer. */

.sc-browse-marker,
.sc-browse-labels { pointer-events: none; }

/* Focus section marker — mirrors the event-mode `placeBluePointer`
   shape (white outer ring + blue inner dot). Fills/strokes are inline
   on the two child circles, not on the group. */

/* Section-name + dates label — HTML overlay, anchored to the right of
   the marker. White halo via text-shadow gives a readable border over
   the polygon fills (matches the SVG paint-order:stroke effect we
   used before). Lives in the same z-tier as the CTA flag. */
.sc-browse-focus-label {
   color: var(--color-primary, #002448);
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   pointer-events: auto;          /* needed so hover registers */
   cursor: pointer;
   white-space: nowrap;
   text-shadow:
      -1.5px -1.5px 0 #fff, 1.5px -1.5px 0 #fff,
      -1.5px  1.5px 0 #fff, 1.5px  1.5px 0 #fff,
       0    -1.5px 0 #fff, 0     1.5px 0 #fff,
      -1.5px  0    0 #fff, 1.5px  0    0 #fff;
   z-index: 100 !important;
   line-height: 1.0;
   transition: color 120ms ease;
}
/* Name + sub read `--sc-flag-fs` directly via calc(). Calibrated against
   desktop's --sc-flag-fs ≈ 11.2px → name 15px / sub 12px. Mobile (clamped
   to 9px) scales proportionally to ~12.1 / 9.6. */
.sc-browse-focus-label .sc-bfl-name {
   font-size: calc(var(--sc-flag-fs, 11px) * 1.34);
   font-weight: 700;
}
.sc-browse-focus-label .sc-bfl-sub {
   font-size: calc(var(--sc-flag-fs, 11px) * 1.07);
   font-weight: 600;
   opacity: 0.92;
   margin-top: 1px;
}
/* Hover: color flip to #0067ce — same treatment as zone labels (DRY). */
.sc-browse-focus-label:hover .sc-bfl-name,
.sc-browse-focus-label:hover .sc-bfl-sub {
   color: #0067ce;
}

/* Zone labels — HTML overlay (was SVG). 2-line block, color #726FD8.
   White text-shadow halo gives legibility over polygon fills. Sits
   ABOVE the fallback dots (z=auto/20) but BELOW the CTA + section
   label (z=100) and the low-price + best-seat flags (z=80). */
.sc-browse-zone-label {
   color: #726FD8;
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   pointer-events: none;
   white-space: nowrap;
   text-align: center;
   line-height: 1.15;
   text-shadow:
      -1.5px -1.5px 0 #fff, 1.5px -1.5px 0 #fff,
      -1.5px  1.5px 0 #fff, 1.5px  1.5px 0 #fff,
       0    -1.5px 0 #fff, 0     1.5px 0 #fff,
      -1.5px  0    0 #fff, 1.5px  0    0 #fff;
   z-index: 30 !important;
}
.sc-browse-zone-label .sc-bzl-name  {
   font-weight: 700;
   font-size: var(--bzl-name-px, 14px);
   transition: color 120ms ease;
}
.sc-browse-zone-label .sc-bzl-price {
   font-weight: 500;
   font-size: var(--bzl-price-px, 13px);
   transition: color 120ms ease;
}
/* Hover: color flip to #0067ce + temporary z-index lift. Matches the
   event-mode zone-label hover (DRY pattern). pointer-events: auto so
   the hover registers. */
.sc-browse-zone-label {
   pointer-events: auto;
   cursor: pointer;
}
.sc-browse-zone-label:hover {
   z-index: 90 !important;   /* lifts above the per-section flags, below CTA */
}
.sc-browse-zone-label:hover .sc-bzl-name,
.sc-browse-zone-label:hover .sc-bzl-price {
   color: #002448;
}

/* Gradient CTA flag — "from $X" + "Choose a Date ›" */
/* CTA flag is a wrap that contains two children: the tail (rendered
   FIRST so it paints BELOW) and the gradient rect (rendered SECOND so
   it paints ON TOP and covers the seam). Both are positioned absolute
   relative to the wrap; the wrap itself has the layout footprint of
   the rect alone (we use the rect for the click target). */
/* Anchor font-size on --sc-flag-fs so the CTA tracks viewport-size the same
   way event-mode gradient flags do. Child sizes + padding all scale in em
   off this anchor (was fixed 16/18px on a 16px-ish base). */
.sc-browse-cta-flag {
   position: relative;
   color: var(--color-primary, #002448);
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   pointer-events: auto;
   cursor: pointer;
   font-variant-numeric: tabular-nums;
   white-space: nowrap;
   z-index: 100 !important;
   font-size: var(--sc-flag-fs, 11px);
}
.sc-browse-cta-flag .sc-cta-rect {
   position: relative;
   background: var(--gradient-flag-cta, linear-gradient(135deg, #5FFFBC 0%, #00D9FF 100%));
   border-radius: 1em;
   padding: 0.7em 1.15em 0.85em;
   box-shadow: 0 7px 22px rgba(0, 217, 255, 0.32);
   text-align: center;
   z-index: 2;
   transition: background 160ms ease, box-shadow 160ms ease;
}
/* Hover: gradient + tail both resolve to a uniform #5FFFBC. The rect
   uses a same-color linear-gradient (not a flat color) so the browser
   can smoothly interpolate between the two gradients — flat-to-gradient
   transitions snap abruptly and cause flicker. */
.sc-browse-cta-flag:hover .sc-cta-rect {
   background: linear-gradient(135deg, #5FFFBC 0%, #5FFFBC 100%);
   box-shadow: 0 7px 22px rgba(95, 255, 188, 0.45);
}
.sc-browse-cta-flag:hover .sc-cta-tail {
   background: #5FFFBC;
}
/* Tail sits BELOW the rect — its top half is covered by the rect's
   bottom edge, so only the bottom point shows. Solid color matches
   the gradient's bottom-right stop. */
.sc-browse-cta-flag .sc-cta-tail {
   position: absolute;
   bottom: -0.4em;
   left: 50%;
   width: 1.2em;
   height: 1.2em;
   background: #00D9FF;
   transform: translateX(-50%) rotate(45deg);
   z-index: 1;
   transition: background 160ms ease;
}
.sc-browse-cta-flag .sc-cta-from {
   font-size: 1em;
   font-weight: 600;
   margin-bottom: 0.15em;
   opacity: 0.92;
}
.sc-browse-cta-flag .sc-cta-from strong { font-weight: 700; }
.sc-browse-cta-flag .sc-cta-go {
   font-size: 1.15em;
   font-weight: 700;
   letter-spacing: 0.2px;
}
.sc-browse-cta-flag .sc-cta-chev {
   margin-left: 0.25em;
   font-weight: 700;
}

/* Low-price + best-seatscore flags — white pills with colored meta.
   Next-highest z-tier (just below the CTA + section-label package). */
.sc-browse-low-price-flag,
.sc-browse-best-seat-flag {
   font-size: var(--sc-flag-fs, 11px);
   padding: 0.42em 0.95em 0.5em;
   border-radius: 0.85em;
   background: #ffffff;
   border: 1px solid #d6dee9;
   box-shadow: 0 4px 12px rgba(7, 18, 41, 0.14);
   pointer-events: auto;
   z-index: 80 !important;
}
.sc-browse-low-price-flag .sc-dbf-price,
.sc-browse-best-seat-flag .sc-dbf-price {
   font-size: 1.35em;
   font-weight: 700;
   color: #1a1f29;
   font-variant-numeric: tabular-nums;
}
.sc-browse-low-price-flag .sc-dbf-debug.is-green {
   color: #1a7551;
   font-weight: 700;
   font-size: 0.95em;
   margin-top: 0.18em;
}
.sc-browse-best-seat-flag .sc-dbf-debug.is-orange {
   color: #FF6600;
   font-weight: 700;
   font-size: 1em;
   margin-top: 0.18em;
}
/* Hover invert — every season-explorer flag uses the same unified
   hover color (#002448, our primary) so the map reads as one system.
   Mirrors the `.sc-browse-section-flag` pattern across all three white
   browse-flag classes; tail recolors too so the chrome stays whole. */
.sc-browse-low-price-flag,
.sc-browse-best-seat-flag {
   transition: background 120ms ease, border-color 120ms ease;
}
.sc-browse-low-price-flag:hover,
.sc-browse-best-seat-flag:hover {
   background: #002448;
   border-color: #002448;
   cursor: pointer;
}
.sc-browse-low-price-flag:hover .sc-dbf-price,
.sc-browse-best-seat-flag:hover .sc-dbf-price { color: #fff; }
.sc-browse-low-price-flag:hover .sc-dbf-debug.is-green,
.sc-browse-best-seat-flag:hover .sc-dbf-debug.is-orange { color: #fff; }
.sc-browse-low-price-flag:hover .sc-dbf-tail,
.sc-browse-best-seat-flag:hover .sc-dbf-tail {
   background: #002448;
   border-right-color: #002448;
   border-bottom-color: #002448;
}

/* Per-section low-price flags — small blue-text pill */
.sc-browse-section-flag {
   padding: 2px 8px 2px;
   border-radius: 999px;
   background: #ffffff;
   border: 1px solid #d6dee9;
   box-shadow: 0 2px 6px rgba(7, 18, 41, 0.08);
   pointer-events: auto;
   transition: background 120ms ease, border-color 120ms ease;
}
.sc-browse-section-flag .sc-dbf-price {
   font-size: 11.5px;
   font-weight: 700;
   color: #0067ce;
   font-variant-numeric: tabular-nums;
   line-height: 1;
   transition: color 120ms ease;
}
/* Tighter tail offset for the white pill — the default `-0.45em` left a
   visible gap below the rect that read as extra padding. */
.sc-browse-section-flag .sc-dbf-tail {
   bottom: -0.3em;
}

/* Temp white-pill flag shown when a blocked rounded rect is hovered. The
   flag is non-interactive (pointer-events: none) so the cursor stays on
   the dot underneath — otherwise we'd get a mouseleave→mouseenter loop
   as the flag overlays the dot. */
.sc-browse-blocked-flag {
   pointer-events: none !important;
   z-index: 8 !important;       /* paint above the rounded rect (z=1) */
}
/* Hover invert + tail re-color so the chrome stays consistent.
   Unified browse-mode hover color is #002448 (primary). */
.sc-browse-section-flag:hover {
   background: #002448;
   border-color: #002448;
}
.sc-browse-section-flag:hover .sc-dbf-price {
   color: #ffffff;
}
.sc-browse-section-flag:hover .sc-dbf-tail {
   background: #002448;
   border-right-color: #002448;
   border-bottom-color: #002448;
}
/* Temp hover label uses the same chrome-less halo style as the focus
   label — slightly different class name so we can tweak independently. */
.sc-browse-hover-label {
   z-index: 95 !important;   /* sit just below CTA/focus-label (100) */
   /* Never capture the cursor. Without this, the label appears under the
      cursor as it spawns, flag.mouseleave fires → label removed → cursor
      back on flag → mouseenter → loop (visual strobe). */
   pointer-events: none !important;
}

/* Fallback marker for sections whose white pill flag was blocked. Reads as
   "there's a price here" without claiming flag-sized space. Default shape
   is a small rounded rectangle (matches the design-system pip used across
   the seating-areas page). */
.sc-browse-blocked-dot {
   width: 15px;
   height: 11px;
   border-radius: 5px;
   background: #ffffff;
   border: 1px solid #b5c1d2;
   box-shadow: 0 1px 3px rgba(7, 18, 41, 0.18);
   pointer-events: auto;
   cursor: pointer;
   /* Lowest z on the map overlay stack — every flag should paint over. */
   z-index: 1 !important;
}
/* Legacy circle variant — kept under a toggle for lab regression tests. */
.sc-map-wrap[data-show-browse-blocked-circles] .sc-browse-blocked-dot {
   width: 12px;
   height: 12px;
   border-radius: 50%;
}

/* ── Demand heatmap legend ────────────────────────────────────────────── */
.sc-map-legend {
   position: absolute;
   bottom: 14px;
   left: 14px;
   background: rgba(255,255,255,0.96);
   border: 1px solid var(--outline-color);
   border-radius: var(--border-radius-m);
   padding: 10px 14px;
   box-shadow: 0 4px 14px rgba(0,0,0,0.08);
   min-width: 180px;
   font-size: var(--font-size-tiny);
   color: var(--text-low);
}
.sc-legend-title {
   font-weight: 700;
   font-size: 11px;
   margin-bottom: 6px;
   letter-spacing: 0.3px;
   text-transform: uppercase;
   color: var(--text-default);
}
.sc-legend-strip {
   height: 8px;
   border-radius: 4px;
   background: linear-gradient(90deg,
      hsl(210, 38%, 82%) 0%,
      hsl(180, 32%, 78%) 25%,
      hsl(48,  62%, 76%) 60%,
      hsl(20,  68%, 68%) 85%,
      hsl(5,   72%, 60%) 100%);
}
.sc-legend-axis {
   display: flex;
   justify-content: space-between;
   margin-top: 4px;
}

/* ── Map controls (zoom + reset, working indicator, zoom readout) ─────── */
.sc-map-controls {
   position: absolute;
   top: 12px;
   right: 12px;
   display: flex;
   flex-direction: column;
   gap: 6px;
   z-index: 6;
}
.sc-map-btn {
   width: 36px;
   height: 36px;
   border-radius: 50%;
   border: 1px solid var(--outline-color);
   background: #fff;
   cursor: pointer;
   display: flex;
   align-items: center;
   justify-content: center;
   box-shadow: 0 2px 6px rgba(0,0,0,0.08);
   color: var(--text-default);
   padding: 0;
}
/* Hover treatment matches te.1 (`.map-controls button:hover`): color flip
   + soft glow, NO background change. */
.sc-map-btn:hover:not([disabled]) {
   color: #0067ce;
   box-shadow: #0067ce 0px 0px 7px;
}
.sc-map-btn:active:not([disabled]) { transform: scale(0.96); }
/* Inner SVG icon shouldn't capture pointer events — let the button itself
   own the hit area so `cursor: pointer` shows everywhere inside the circle,
   not just on the empty border. */
.sc-map-btn > svg { pointer-events: none; display: block; }
.sc-map-btn > i[data-is="icon"] { pointer-events: none; }

/* Map-controls icons — registered via the design-system `data-is="icon"`
   pattern (CSS-mask + `currentColor` fill). Mask URLs live here so the
   icons are scoped to the chart and don't bloat the base icons.css.
   Style identical to `lib/base/styles/src/icons.css`'s base `i[data-is="icon"]`
   rule (already on the page), which provides display/mask-size/repeat/etc. */
[data-is="icon"][data-icon="zoom-in"] {
   --icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z'/%3E%3C/svg%3E");
}
[data-is="icon"][data-icon="zoom-out"] {
   --icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M19 13H5v-2h14v2z'/%3E%3C/svg%3E");
}
[data-is="icon"][data-icon="recenter"] {
   --icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M5 15H3v4c0 1.1.9 2 2 2h4v-2H5v-4zm0-10h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zM12 9c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z'/%3E%3C/svg%3E");
}
[data-is="icon"][data-icon="layers"] {
   --icon-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M11.99 18.54L4.62 12.81 3 14.07l9 7 9-7-1.63-1.27-7.38 5.74zM12 16l7.36-5.73L21 9l-9-7-9 7 1.63 1.27L12 16z'/%3E%3C/svg%3E");
}
[data-is="icon"][data-icon="layers-outline"] {
   --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='m12 21.05l-9-7l1.65-1.25L12 18.5l7.35-5.7L21 14.05zM12 16L3 9l9-7l9 7zm0-2.55L17.75 9L12 4.55L6.25 9z'/%3E%3C/svg%3E");
}
.sc-map-btn[disabled] {
   opacity: 0.4;
   cursor: not-allowed;
   pointer-events: none;
}
/* Contextual visibility:
   - zoom-in:  always visible (you can always zoom in further)
   - zoom-out: always visible too, but DISABLED at scale ~1.0 so the user
               sees a stable control rail instead of buttons popping in/out
   - reset:    only surfaced when the user has moved (zoomed or panned away
               from home); otherwise it'd be a no-op affordance        */
.sc-map-controls:not(.is-moved) .sc-reset-btn { display: none; }
/* Touch-only viewports get pinch-to-zoom — hide the ± buttons but keep
   the reset button so users can undo a zoom/pan back to home. The class
   is set by renderMapControls() based on (pointer: coarse) && !(pointer:
   fine). */
.sc-map-controls.is-touch-only .sc-zoom-in-btn,
.sc-map-controls.is-touch-only .sc-zoom-out-btn { display: none; }
/* Layers (sections-mode) button — visible only when an event is
   selected. The host signals event-mode by stamping `.is-event-mode`
   on `.sc-map-wrap` (chart already toggles equivalent state). When ON,
   the button gets the accent fill so the user sees the toggle is
   armed. */
/* Layers control sits at the bottom-right of the map space — separated
   from the top-right zoom/recenter cluster (vertically) so the "switch
   layer" action reads as distinct from view controls. */
.sc-layers-control {
   position: absolute;
   bottom: 12px;
   right: 12px;
   z-index: 6;
}
.sc-layers-btn { display: none; }
.sc-map-wrap.is-event-mode .sc-layers-btn { display: inline-flex; }
.sc-map-wrap.is-sections-mode .sc-layers-btn {
   background: var(--accent-color, #002448);
   color: #fff;
}
/* Layers popover — drops UP from the bottom-right button, aligned RIGHT
   so it doesn't go off-screen on narrow viewports. Two-item menu
   (Tickets / Sections). */
.sc-layers-menu {
   position: absolute;
   bottom: 100%;
   right: 0;
   margin-bottom: 6px;
   min-width: 140px;
   background: #fff;
   border: 1px solid var(--outline-color, #e2e4e8);
   border-radius: 8px;
   box-shadow: 0 4px 14px rgba(0,0,0,0.12);
   padding: 4px;
   z-index: 30;
   font: 13px/1.2 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.sc-layers-menu-item {
   display: flex; align-items: center; gap: 10px;
   width: 100%; padding: 8px 12px;
   border: 0; background: transparent;
   border-radius: 6px;
   cursor: pointer;
   color: var(--accent-color, #002448);
   font: inherit; text-align: left;
}
.sc-layers-menu-item:hover { background: #f4f5f7; }
.sc-layers-menu-item.is-active {
   background: var(--accent-color, #002448);
   color: #fff;
}
.sc-layers-menu-glyph {
   display: inline-flex; width: 18px; justify-content: center;
   font-size: 14px;
}
/* Sections mode — hide every ticket marker / flag / dot so the polygons
   are the unambiguous click target. Zone labels stay visible (Keith's
   spec: "keep the zone labels on the map as well"). */
.sc-map-wrap.is-sections-mode .sc-dot-layer,
.sc-map-wrap.is-sections-mode g[data-role="ticket-group"],
.sc-map-wrap.is-sections-mode .sc-marker-flag,
.sc-map-wrap.is-sections-mode .sc-team-flag,
.sc-map-wrap.is-sections-mode .sc-browse-low-price-flag,
.sc-map-wrap.is-sections-mode .sc-browse-best-seat-flag,
.sc-map-wrap.is-sections-mode .sc-browse-section-flag,
.sc-map-wrap.is-sections-mode .sc-browse-cta-flag,
.sc-map-wrap.is-sections-mode .sc-browse-focus-marker,
.sc-map-wrap.is-sections-mode .sc-pointer-layer,
.sc-map-wrap.is-sections-mode .sc-section-halo,
.sc-map-wrap.is-sections-mode .sc-focus-card { display: none !important; }
/* Make polygons obviously interactive — hand cursor + a hover fill
   bump. Pointer-events on polygons are usually disabled in the base
   chart; re-enable in sections mode only. */
/* `:not([data-dyn='1'])` matches the interactive-map base rule's pattern
   exactly so dyn polys (benches, dugouts, sidelines, dynamic floor layout
   placeholders) are skipped. Stage / ring ids stamped by the lib also
   excluded — these have static ids the lib reserves. */
.sc-map-wrap.is-sections-mode .sc-map svg polygon[data-id]:not([data-dyn='1']):not([data-id='static_stage']):not([data-id='b_stage']):not([data-id='fighting_ring']) {
   pointer-events: all;
   cursor: pointer;
   transition: fill 0.15s ease, fill-opacity 0.15s ease;
}
.sc-map-wrap.is-sections-mode .sc-map svg polygon[data-id]:not([data-dyn='1']):not([data-id='static_stage']):not([data-id='b_stage']):not([data-id='fighting_ring']):hover {
   fill: var(--accent-color, #6b5fa3);
   fill-opacity: 0.45;
}
/* Stage / ring polygons get `cursor: pointer` from the base interactive-
   map.css rule (`polygon:not([data-dyn='1'])`) because they don't carry
   data-dyn. Force `cursor: default` on them so they don't read as
   interactive in sections mode. Pointer-events stays off so no hover fill
   or click either. */
.sc-map-wrap.is-sections-mode .sc-map svg polygon[data-id='static_stage'],
.sc-map-wrap.is-sections-mode .sc-map svg polygon[data-id='b_stage'],
.sc-map-wrap.is-sections-mode .sc-map svg polygon[data-id='fighting_ring'] {
   cursor: default;
   pointer-events: none;
}
/* Hover flag — small floating section-name pill at cursor in sections
   mode. JS positions it inside `.sc-map-wrap` via absolute coords. */
.sc-sections-hover-flag {
   position: absolute;
   display: none;
   padding: 4px 8px;
   background: rgba(0, 36, 72, 0.92);
   color: #fff;
   font-size: 12px;
   font-weight: 600;
   border-radius: 4px;
   pointer-events: none;
   white-space: nowrap;
   transform: translateX(-50%);
   z-index: 50;
}
/* Active section / zone — focus styling for polygons whose detail
   overlay is currently open. Same darker-lavender stroke + raised
   fill the existing focus-section work uses, applied via the
   `data-active-section` / `data-active-zone` attributes the host sets
   via `chart.setActiveSection()` / `setActiveZone()`. */
.sc-map svg polygon[data-active-section],
.sc-map svg polygon[data-active-zone] {
   stroke: var(--accent-color, #6b5fa3);
   stroke-width: 2.2;
   fill: #d2c7f6;
   fill-opacity: 0.65;
}
.sc-zoom-level {
   position: absolute;
   top: 12px;
   right: 56px;
   background: rgba(255,255,255,0.96);
   border: 1px solid var(--outline-color);
   border-radius: 999px;
   padding: 2px 10px;
   font-size: 11px;
   font-weight: 700;
   color: var(--text-default);
   font-variant-numeric: tabular-nums;
   box-shadow: 0 2px 6px rgba(0,0,0,0.08);
   z-index: 6;
   pointer-events: none;
}
/* Debug qty filter strip — toggled visible while an event is selected. */
.sc-qty-filter {
   position: absolute;
   top: 60px;
   left: 50%;
   transform: translateX(-50%);
   background: rgba(255,255,255,0.96);
   border: 1px solid var(--outline-color);
   border-radius: 999px;
   padding: 4px 10px;
   font-size: 11px;
   font-weight: 600;
   color: var(--text-low);
   box-shadow: 0 4px 14px rgba(0,0,0,0.08);
   z-index: 11;
   display: flex;
   align-items: center;
   gap: 4px;
}
.sc-qty-label {
   text-transform: uppercase;
   letter-spacing: 0.4px;
   margin-right: 4px;
}
.sc-qty-btn {
   appearance: none;
   border: 1px solid transparent;
   background: transparent;
   padding: 3px 8px;
   border-radius: 999px;
   font: inherit;
   font-weight: 700;
   color: var(--text-default);
   cursor: pointer;
   min-width: 22px;
}
.sc-qty-btn:hover { background: var(--bg-light-blue, #f4f7fb); }
.sc-qty-btn.is-active {
   background: var(--color-primary);
   color: #fff;
   border-color: var(--color-primary);
}
.sc-qty-count {
   margin-left: 6px;
   font-weight: 600;
   color: var(--text-low);
   font-variant-numeric: tabular-nums;
}

/* Working indicator — mirrors lib/interactive-map's `.im-working` pattern:
   white pill at top-center with three #0067CE dots blinking on a 1.4s loop. */
.sc-working {
   position: absolute;
   top: 32px;
   left: 50%;
   transform: translateX(-50%);
   background: #fff;
   border-radius: 20px;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
   padding: 12px 20px;
   display: flex;
   align-items: center;
   justify-content: center;
   z-index: 1000;
   pointer-events: none;
}
/* `hidden` attribute MUST win over `.sc-working { display: flex }`. */
.sc-working[hidden] {
   display: none !important;
}
.sc-working-dots {
   display: flex;
   gap: 4px;
}
.sc-working-dots div {
   width: 8px;
   height: 8px;
   background: #0067CE;
   border-radius: 50%;
   animation: sc-working-blink 1.4s infinite both;
}
.sc-working-dots div:nth-child(1) { animation-delay: 0s; }
.sc-working-dots div:nth-child(2) { animation-delay: 0.2s; }
.sc-working-dots div:nth-child(3) { animation-delay: 0.4s; }
@keyframes sc-working-blink {
   0%, 80%, 100% { opacity: 0.3; transform: scale(1);   }
   40%           { opacity: 1;   transform: scale(1.3); }
}

/* ── Overlay root ──────────────────────────────────────────────────────
   Overlays are positioned individually in screen-px. The positioning
   pass runs SYNCHRONOUSLY inside the patched `applyTransform` (see JS),
   so HTML overlays update in the same tick as the SVG content — no
   rAF gap, no catch-up. */
.sc-overlay-root {
   position: absolute;
   inset: 0;
   pointer-events: none;
   z-index: 5;
}
.sc-overlay-root > * {
   position: absolute;
   top: 0;
   left: 0;
   will-change: transform;
}
/* Any interactive flag/marker needs to receive clicks even though the
   parent overlay-root is pointer-events: none. */
.sc-zone-flag,
.sc-marker-flag,
.sc-debug-flag,
.sc-section-flag,
.sc-event-flag,
.sc-dates-flag,
.sc-team-flag,
.sc-focus-card { pointer-events: auto; }

/* Hand-cursor for every clickable map element — replaces a stack of inline
   `style.cursor = 'pointer'` assignments in JS. */
[data-role='marker'],
.sc-debug-dot,
.sc-marker-flag,
.sc-zone-flag,
.sc-debug-flag,
.sc-section-flag,
.sc-event-flag,
.sc-dates-flag { cursor: pointer; }

/* Debug rect layers (used by gap-fill + flag-rect viz) */
.sc-flag-debug-layer,
.sc-browse-flag-debug-layer {
   position: absolute;
   inset: 0;
   pointer-events: none;
   z-index: 20;
}

/* ── Pulse halo on active section ─────────────────────────────────────── */
/* Purple to match the lavender in-scope treatment used on page-match
   sections (`data-zone-section` / `data-page-section`). Applies to both
   section pages and single-section zone pages (both render this halo
   via `placeSectionHalo`). */
.sc-section-halo {
   fill: #d2c7f6;
   fill-opacity: 0.35;
   stroke: var(--zone-section-stroke, #6b5fa3);
   stroke-opacity: 0.7;
   stroke-width: 2;
   pointer-events: none;
   transform-origin: center;
   transform-box: fill-box;
   animation: sc-section-halo-pulse 2.2s ease-in-out infinite;
}
/* JS adds `.sc-section-halo-static` 10s after placement to stop the
   pulse but keep the static ring visible. */
.sc-section-halo.sc-section-halo-static {
   animation: none;
   transform: none;
   opacity: 1;
}
@keyframes sc-section-halo-pulse {
   0%, 100% { transform: scale(1);    opacity: 1;    }
   50%      { transform: scale(1.10); opacity: 0.65; }
}

/* Deep-zoom (>2×): hide the focus ring + location-marker dots since the
   user has already drilled in and these orienting affordances now just
   overlap ticket markers. Toggled by `updateMapControlsState` via the
   `.is-deep-zoom` class on `.sc-map-wrap`. Applies to both section and
   zone contexts — zone pages don't render these elements anyway, so the
   rule is a no-op there. */
.sc-map-wrap.is-deep-zoom .sc-section-halo,
.sc-map-wrap.is-deep-zoom .sc-browse-focus-marker,
.sc-map-wrap.is-deep-zoom .sc-pointer-layer {
   display: none;
}

/* 3× deep zoom ON EVENT MODE ONLY (not season explorer): hide the page's
   section labels since the user has drilled into per-seat detail and the
   labels overlap ticket markers. Browse / season-explorer mode keeps the
   label visible — it's a clickable affordance there (opens the event
   picker). Gated on `[data-mode='event']` set by `selectEvent` /
   `clearEvent` on `.sc-map-wrap`. */
.sc-map-wrap[data-mode='event'].is-deep-zoom-3x .sc-browse-focus-label:not(.sc-browse-focus-zone-label):not(.sc-browse-hover-label) {
   display: none;
}

/* Zone pages: at low zoom the HTML focus-zone label
   (`.sc-browse-focus-zone-label`) carries the "Check Availability" CTA.
   The focus zone's normal click-to-filter SVG label is rendered alongside
   but hidden. At deep zoom (>2×) we swap them — the HTML overlay drops
   out and the SVG label takes over so the click-to-filter affordance is
   available where the user is now focused. */
.sc-map-wrap:not(.is-deep-zoom) .sc-zone-label-svg[data-is-focus-zone] {
   display: none;
}
.sc-map-wrap.is-deep-zoom .sc-browse-focus-zone-label {
   display: none;
}

/* ── Focus card (expanded + collapsed mini) ───────────────────────────── */
.sc-focus-card {
   position: absolute;
   z-index: 10;
   width: 260px;
   background: #fff;
   border-radius: 14px;
   box-shadow: 0 6px 22px rgba(7, 18, 41, 0.18);
   border: 1px solid var(--outline-color-light);
   overflow: hidden;
   pointer-events: auto;
}
.sc-fc-collapsed { display: none !important; }
.sc-focus-card.is-collapsed .sc-fc-expanded { display: none !important; }
.sc-focus-card.is-collapsed {
   width: auto !important;
   min-width: 140px;
   max-width: 220px;
   border-radius: 10px;
   border: 1px solid #d6dee9;
   box-shadow: 0 4px 12px rgba(7, 18, 41, 0.14);
   overflow: visible !important;
}
.sc-focus-head {
   padding: 12px 14px 8px;
   display: flex;
   align-items: flex-start;
   justify-content: space-between;
   gap: 8px;
   border-bottom: 1px solid var(--outline-color-light);
}
.sc-focus-title {
   font-size: var(--font-size-smaller);
   font-weight: 700;
   color: var(--text-default);
   line-height: 1.2;
}
.sc-focus-sub {
   font-size: var(--font-size-s);
   color: var(--text-low);
   margin-top: 2px;
   font-variant-numeric: tabular-nums;
}
.sc-focus-collapse {
   background: transparent;
   border: 0;
   width: 22px;
   height: 22px;
   border-radius: 50%;
   cursor: pointer;
   color: var(--text-low);
   display: flex;
   align-items: center;
   justify-content: center;
   flex-shrink: 0;
}
.sc-focus-collapse:hover { background: var(--bg-light-blue); color: var(--text-default); }
.sc-focus-body { padding: 8px 14px 10px; }
.sc-focus-event-row {
   display: flex;
   align-items: center;
   justify-content: space-between;
   padding: 6px 0;
   border-bottom: 1px dashed var(--outline-color-light);
   font-size: var(--font-size-s);
}
.sc-focus-event-row:last-child { border-bottom: 0; }
.sc-focus-event-name {
   color: var(--text-default);
   font-weight: 600;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
   margin-right: 8px;
}
.sc-focus-event-when {
   color: var(--text-low);
   font-size: 11px;
   white-space: nowrap;
}
.sc-focus-check { color: #22a06b; margin-left: 6px; }
.sc-focus-action { padding: 0 14px 14px; }
.sc-focus-btn {
   width: 100%;
   background: var(--color-brand);
   color: #fff;
   border: 0;
   padding: 10px 14px;
   border-radius: var(--border-radius-m);
   font-size: var(--font-size-smaller);
   font-weight: 700;
   cursor: pointer;
   letter-spacing: 0.2px;
}
.sc-focus-btn:hover { background: #0058b0; }

/* ── Zone flag (white card, 2-line) ───────────────────────────────────── */
.sc-zone-flag {
   background: #fff;
   border: 1px solid #d6dee9;
   border-radius: 10px;
   padding: 7px 10px 8px;
   box-shadow: 0 4px 12px rgba(7, 18, 41, 0.14);
   min-width: 92px;
   max-width: 180px;
   text-align: center;
   font-size: 11.5px;
   line-height: 1.25;
   z-index: 3;
}
.sc-marker-flag                                { z-index: 6 !important; }
.sc-marker-flag.sc-marker-flag-marquee         { z-index: 9 !important; }
.sc-zone-flag .sc-zf-body,
.sc-fc-collapsed .sc-zf-body { text-align: left; }
/* Zone label typography. JS stamps `--zf-base-px` on each .sc-zone-flag
   element. Anchor is the dynamic `--sc-zone-fs` (flagBase × 1.25, screen-
   rect derived) with proportional shrinkage for long names. Name + price
   track --zf-base-px; "from" sits ~83% of base. Color #5869b2 throughout.
   See `zoneLabelBasePx()` in scripts.js. */
.sc-zone-flag .sc-zf-name,
.sc-fc-collapsed .sc-zf-name {
   font-weight: 700;
   color: #5869b2;
   font-size: var(--zf-base-px, 12px);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}
.sc-zone-flag .sc-zf-row,
.sc-fc-collapsed .sc-zf-row {
   display: flex;
   align-items: center;
   justify-content: flex-start;
   gap: 5px;
   margin-top: 2px;
}
.sc-zone-flag .sc-zf-from,
.sc-fc-collapsed .sc-zf-from {
   font-size: calc(var(--zf-base-px, 12px) * 0.83);
   color: #5869b2;
   font-weight: 500;
   letter-spacing: 0.2px;
}
.sc-zone-flag .sc-zf-price,
.sc-fc-collapsed .sc-zf-price {
   color: #5869b2;
   font-weight: 700;
   font-variant-numeric: tabular-nums;
   font-size: var(--zf-base-px, 12px);
}
.sc-zone-flag .sc-zf-icons,
.sc-fc-collapsed .sc-zf-icons {
   display: inline-flex;
   gap: 3px;
   align-items: center;
   color: #7a8aa0;
   margin-left: 2px;
}
.sc-zone-flag .sc-zf-tail,
.sc-fc-collapsed .sc-zf-tail {
   position: absolute;
   bottom: -6px;
   left: 50%;
   transform: translateX(-50%) rotate(45deg);
   width: 10px;
   height: 10px;
   background: #fff;
   border-right: 1px solid #d6dee9;
   border-bottom: 1px solid #d6dee9;
}

/* Dark zone flag variant */
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag {
   background: var(--color-primary);
   border-color: var(--color-primary);
   box-shadow: 0 4px 14px rgba(0, 36, 72, 0.32);
}
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag .sc-zf-name,
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag .sc-zf-price { color: #fff; }
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag .sc-zf-from  { color: rgba(255,255,255,0.65); }
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag .sc-zf-icons { color: rgba(255,255,255,0.85); }
.sc-map-wrap[data-show-dark-flags] .sc-zone-flag .sc-zf-tail {
   background: var(--color-primary);
   border-right-color: var(--color-primary);
   border-bottom-color: var(--color-primary);
}

/* Text-only zone flags (no flag chrome, just text with white stroke) */
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag {
   background: transparent !important;
   border: 0 !important;
   box-shadow: none !important;
   padding: 0 !important;
   color: #5869b2;
   text-shadow:
      -1px -1px 0 #fff, 1px -1px 0 #fff,
      -1px  1px 0 #fff, 1px  1px 0 #fff,
       0   -1px 0 #fff, 0    1px 0 #fff,
      -1px  0   0 #fff, 1px  0   0 #fff;
}
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag .sc-zf-tail { display: none !important; }
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag .sc-zf-name,
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag .sc-zf-price {
   line-height: 1.05;
   /* color + font-size inherit the --zf-base-px-driven rules above */
}
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag .sc-zf-from {
   line-height: 1.05;
   /* color + font-size inherit the --zf-base-px-driven rules above */
}
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag .sc-zf-row {
   margin-top: 0;
   gap: 2px;
}
.sc-map-wrap[data-show-zone-flags-textonly] .sc-zone-flag:hover {
   background: transparent !important;
   border-color: transparent !important;
   box-shadow: none !important;
}

/* ── Section / debug-ticket flag (compact pill) ───────────────────────── */
.sc-section-flag {
   background: #fff;
   border: 1px solid #d6dee9;
   border-radius: 999px;
   padding: 3px 8px;
   font-size: 10.5px;
   font-weight: 700;
   color: var(--text-default);
   font-variant-numeric: tabular-nums;
   box-shadow: 0 2px 5px rgba(7, 18, 41, 0.10);
   pointer-events: auto;
   white-space: nowrap;
}

/* ── Generic "debug-style" white flag (price + optional colored meta) ──
   Base font-size is set per-map via --sc-flag-fs (recomputed on resize
   from the SVG's _labelBaseFs). All children + padding scale in em off
   this anchor so the whole flag scales together. */
.sc-debug-flag {
   background: #fff;
   border: 1px solid #d6dee9;
   border-radius: var(--border-radius);
   padding: 0.36em 0.91em 0.45em;
   box-shadow: 0 2px 6px rgba(7, 18, 41, 0.10);
   font-size: var(--sc-flag-fs, 11px);
   line-height: 1.15;
   text-align: center;
   cursor: pointer;
   pointer-events: auto;
   z-index: 6;
}
.sc-debug-flag .sc-dbf-price {
   font-weight: 700;
   color: var(--text-default);
   font-variant-numeric: tabular-nums;
   font-size: 1.09em;
}
.sc-debug-flag .sc-dbf-debug {
   font-size: 0.82em;
   color: #dc2626;
   font-weight: 700;
   line-height: 1.1;
   margin-top: 0.27em;
   letter-spacing: 0.3px;
   white-space: nowrap;
}
/* Marquee gets even bigger price + annotation than baseline flags. */
.sc-marker-flag.sc-marquee-flag .sc-dbf-price { font-size: 1.27em; }
.sc-marker-flag.sc-marquee-flag .sc-dbf-debug { font-size: 0.96em; }
.sc-marker-flag.sc-marquee-flag .sc-mf-spark   { width: 1em; height: 1em; }
.sc-debug-flag .sc-dbf-debug.is-green   { color: #15803d; }
.sc-debug-flag .sc-dbf-debug.is-orange  { color: #FF6600; }
.sc-debug-flag .sc-dbf-debug.is-blue    { color: var(--color-brand); }
.sc-debug-flag .sc-dbf-debug.is-purple  { color: #7c3aed; }
.sc-debug-flag .sc-dbf-debug.is-pink    { color: var(--sc-marquee-pink); }
.sc-debug-flag .sc-dbf-tail {
   position: absolute;
   left: 50%;
   bottom: -0.45em;
   width: 0.73em;
   height: 0.73em;
   background: #fff;
   transform: translateX(-50%) rotate(45deg);
   border-right: 1px solid #d6dee9;
   border-bottom: 1px solid #d6dee9;
}

/* ── Marquee flag (pink accents) + style variants ─────────────────────── */
/* Sparkle inherits its parent's text color (currentColor on the icon mask)
   so it always matches the price/editorial — no special pink tint. */
.sc-mf-spark[data-is="icon"] {
   width: 1.09em;
   height: 1.09em;
   margin-right: 0.36em;
   vertical-align: -1px;
}

.sc-map-wrap[data-marquee-style="invert"] .sc-marquee-flag {
   background: var(--sc-marquee-pink) !important;
   border-color: var(--sc-marquee-pink) !important;
   box-shadow: 0 4px 12px rgba(239, 53, 108, 0.34) !important;
}
.sc-map-wrap[data-marquee-style="invert"] .sc-marquee-flag .sc-dbf-price { color: #fff !important; }
.sc-map-wrap[data-marquee-style="invert"] .sc-marquee-flag .sc-dbf-debug,
.sc-map-wrap[data-marquee-style="invert"] .sc-marquee-flag .sc-mf-spark { color: #fff !important; }
.sc-map-wrap[data-marquee-style="invert"] .sc-marquee-flag .sc-dbf-tail {
   background: var(--sc-marquee-pink) !important;
   border-right-color: var(--sc-marquee-pink) !important;
   border-bottom-color: var(--sc-marquee-pink) !important;
}
.sc-map-wrap[data-marquee-style="outline"] .sc-marquee-flag {
   background: #fff !important;
   border-color: var(--sc-marquee-pink) !important;
   border-width: 1.5px !important;
}
.sc-map-wrap[data-marquee-style="outline"] .sc-marquee-flag .sc-dbf-tail {
   background: #fff !important;
   border-right-color: var(--sc-marquee-pink) !important;
   border-bottom-color: var(--sc-marquee-pink) !important;
}

/* ── Event-mode "next-5 games" flag (split white/colored, dot-anchored) */
.sc-event-flag {
   --opp: var(--opp-color, var(--color-primary));
   background: #fff;
   border: 1px solid var(--opp);
   border-radius: var(--border-radius-m);
   box-shadow: 0 4px 12px rgba(7, 18, 41, 0.16);
   display: flex;
   align-items: stretch;
   font-size: 11px;
   line-height: 1.2;
   pointer-events: auto;
   cursor: pointer;
   z-index: 7;
}
.sc-event-flag .sc-ef-left {
   padding: 6px 8px;
   background: #fff;
   color: var(--text-default);
   border-radius: 7px 0 0 7px;
}
.sc-event-flag .sc-ef-date {
   font-size: 9.5px;
   color: var(--text-low);
   white-space: nowrap;
}
.sc-event-flag .sc-ef-cal { font-size: 9px; margin-right: 2px; }
.sc-event-flag .sc-ef-teams {
   font-weight: 700;
   font-size: 11.5px;
   margin-top: 1px;
   white-space: nowrap;
}
.sc-event-flag .sc-ef-right {
   padding: 6px 9px;
   background: var(--opp);
   color: #fff;
   text-align: center;
   min-width: 56px;
   border-radius: 0 7px 7px 0;
}
.sc-event-flag .sc-ef-price {
   font-weight: 700;
   font-size: 12px;
   line-height: 1.1;
   font-variant-numeric: tabular-nums;
}
.sc-event-flag .sc-ef-deal {
   font-size: 9px;
   opacity: 0.92;
   white-space: nowrap;
}
.sc-event-flag .sc-ef-tail {
   position: absolute;
   left: 50%;
   bottom: -6px;
   width: 10px;
   height: 10px;
   background: var(--opp);
   transform: translateX(-50%) rotate(45deg);
   border-right: 1px solid var(--opp);
   border-bottom: 1px solid var(--opp);
}

/* Compact "+X dates / from $X" companion flag for next-5 cards */
.sc-dates-flag {
   background: #fff;
   border: 1px solid #d6dee9;
   border-radius: var(--border-radius);
   box-shadow: 0 3px 8px rgba(7, 18, 41, 0.12);
   padding: 3px 6px;
   font-size: 10px;
   line-height: 1.15;
   text-align: left;
   pointer-events: auto;
   cursor: pointer;
   z-index: 7;
}
.sc-dates-flag .sc-df-dates {
   color: var(--color-brand);
   font-weight: 700;
   font-size: 9.5px;
   white-space: nowrap;
}
.sc-dates-flag .sc-df-from {
   color: var(--text-low);
   font-size: 9px;
   white-space: nowrap;
}
.sc-dates-flag .sc-df-from strong {
   color: var(--text-default);
   font-weight: 700;
   font-variant-numeric: tabular-nums;
}
.sc-dates-flag .sc-df-tail {
   position: absolute;
   left: -5px;
   top: 50%;
   width: 8px;
   height: 8px;
   background: #fff;
   transform: translateY(-50%) rotate(45deg);
   border-left: 1px solid #d6dee9;
   border-bottom: 1px solid #d6dee9;
}

/* ── Team flag (3-letter abbrev pill) ─────────────────────────────────── */
.sc-team-flag { width: 56px; pointer-events: auto; }
.sc-team-flag .sc-tf-price {
   position: absolute;
   right: -10px;
   top: -16px;
   background: #fff;
   border: 1px solid #d6dee9;
   border-radius: var(--border-radius-sm);
   padding: 1px 6px;
   font-size: 10px;
   font-weight: 700;
   color: var(--text-default);
   font-variant-numeric: tabular-nums;
   box-shadow: 0 1px 4px rgba(7, 18, 41, 0.14);
   white-space: nowrap;
}
.sc-team-flag .sc-tf-body {
   color: #fff;
   font-weight: 700;
   font-size: 11px;
   padding: 4px 8px;
   border-radius: var(--border-radius-sm);
   text-align: center;
   letter-spacing: 0.5px;
   line-height: 1.1;
   box-shadow: 0 2px 6px rgba(7, 18, 41, 0.18);
}
.sc-team-flag .sc-tf-tail {
   width: 8px;
   height: 8px;
   margin: 0 auto;
   transform: translateY(-3px) rotate(45deg);
}

/* ── Layer hide states (host toggles via data-hide-X / data-show-X) ────── */
.sc-map-wrap[data-hide-dots]                .sc-dot-layer       { display: none; }
.sc-map-wrap[data-hide-team-flags]          .sc-team-flag       { display: none !important; }
.sc-map-wrap[data-hide-section-flags]       .sc-section-flag    { display: none !important; }
.sc-map-wrap[data-hide-debug-ticket-flags]  .sc-debug-dot-layer { display: none; }
.sc-map-wrap[data-hide-debug-ticket-flags]  .sc-debug-flag:not(.sc-debug-section-flag):not(.sc-marquee-flag) {
   display: none !important;
}
.sc-map-wrap[data-hide-grid-section-flags]  .sc-debug-section-flag { display: none !important; }
.sc-map-wrap[data-hide-zone-flags]          .sc-zone-flag:not(.sc-focus-mini) { display: none !important; }
.sc-map-wrap[data-hide-event-cards]         .sc-event-dots-layer  { display: none; }
.sc-map-wrap[data-hide-event-cards]         .sc-event-flag,
.sc-map-wrap[data-hide-event-cards]         .sc-dates-flag        { display: none !important; }
.sc-map-wrap[data-hide-marquee-flags]       .sc-marquee-flag      { display: none !important; }
.sc-map-wrap[data-hide-heatmap]             .sc-map-legend        { display: none; }

/* Gap-fill debug rings + flag rect debug layers */
.sc-map-wrap:not([data-show-block-rings]) .sc-marker-blocking-rings { display: none; }
/* Two independent debug toggles split the rects by shape. The browse
   debug layer follows the main flag-debug toggle as before. */
.sc-map-wrap:not([data-show-flag-debug]) .sc-browse-flag-debug-layer { display: none; }
/* Hide non-price flag-debug rects when the main toggle is off. */
.sc-map-wrap:not([data-show-flag-debug]) .sc-flag-debug-rect:not([data-shape="price-only"]) { display: none; }
/* Hide price-only flag-debug rects when the price-tag toggle is off. */
.sc-map-wrap:not([data-show-flag-price-debug]) .sc-flag-debug-rect[data-shape="price-only"] { display: none; }
/* Base rect styling — dashed outline, semi-transparent fill, no pointer
   events so debug overlay doesn't eat clicks. Default color is orange
   (chrome flags); the price-only override below swaps in blue. Dot
   blocking circles are SVG with inline red stroke (`drawMarker` ring),
   so the three layers each get a distinct color when ?debug=true is on. */
.sc-flag-debug-rect {
   position: absolute;
   pointer-events: none;
   box-sizing: border-box;
   border: 1px dashed #f97316;
   background: rgba(249, 115, 22, 0.08);
}
/* Price-tag rects render in blue to distinguish them from chrome rects. */
.sc-flag-debug-rect[data-shape="price-only"] {
   border-color: #2563eb;
   background: rgba(37, 99, 235, 0.06);
}

/* Blow-up inset (hidden by default; toggled by host) */
.sc-map-wrap:not([data-show-blowup]) .sc-blowup { display: none !important; }
.sc-blowup {
   position: absolute;
   top: 14px;
   left: 14px;
   background: rgba(255, 255, 255, 0.97);
   border: 1px solid var(--outline-color);
   border-radius: 14px;
   padding: 10px 12px 12px;
   box-shadow: 0 6px 22px rgba(7, 18, 41, 0.16);
   z-index: 6;
   pointer-events: none;
   max-width: 260px;
}
.sc-blowup-head {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   margin-bottom: 6px;
   gap: 10px;
}
.sc-blowup-title {
   font-size: var(--font-size-smaller);
   font-weight: 700;
   color: var(--text-default);
   line-height: 1.2;
}
.sc-blowup-sub {
   font-size: 11px;
   color: var(--text-low);
   font-variant-numeric: tabular-nums;
}
.sc-blowup-svg-wrap {
   background: var(--bg-light-blue-lighter, #fbfcfe);
   border-radius: 10px;
   padding: 8px;
   border: 1px solid var(--outline-color-light);
}

/* ── Price label (text sibling inside a ticket group) ─────────────────── */
/* SVG <text> appended inside the same `<g data-role="ticket-group">` as
   the dot. Smaller, less prominent than a chrome flag. The white halo
   (stroke under the fill, via paint-order) reads cleanly over polygon
   colors. */
/* `text[...]` prefix bumps specificity to (0,1,1) so we override the lib's
   `text:not([data-dyn]) { pointer-events: none }` rule in
   interactive-map.css. Without the `text` prefix the lib rule wins on
   specificity, the label is unhoverable, and only the dot triggers hover. */
text[data-role='price-label'] {
   --label-base: 1em;            /* 1× wrapper font-size at zoom 1 */
   fill: var(--sc-plain-price-color, var(--text-default));
   font-size: var(--label-base);
   font-weight: 700;
   text-anchor: middle;
   font-family: var(--font-family);
   paint-order: stroke;
   stroke: #fff;
   stroke-width: 0.25em;
   stroke-linejoin: round;
   /* `bounding-box` (vs `auto`) makes the whole bbox hoverable — `auto`
      on SVG text only fires on the painted glyphs, so the cursor falls
      through to the dot below in the spaces between characters. */
   pointer-events: bounding-box;
   cursor: pointer;
}
/* Deal-tier price labels bump 15% / 25% over base AND match the deal
   dot color. `data-deal-tier` is stamped by `appendPlainPrice`. */
[data-role='price-label'][data-deal-tier="70"] { fill: #015446; --label-base: 1.15em; }
[data-role='price-label'][data-deal-tier="90"] { fill: #0B8C67; --label-base: 1.25em; }
/* Hover label (self) OR a ticket-group flagged .is-hover (set by the
   coordinator when hovering the dot or paired flag) → 125% of the
   tier base + black fill. */
[data-role='price-label']:hover,
[data-role='ticket-group'].is-hover [data-role='price-label'] {
   font-size: calc(var(--label-base) * 1.25);
   fill: #000;
}

/* ── Dark marker flag variant (global) ────────────────────────────────── */
/* Invert .sc-marker-flag (non-marquee) to a dark navy bg with white text.
   Marquee flags keep their pink identity via their own style toggles. */
/* Dark-marker-flag toggle: invert ONLY the plain white flags (non-marquee,
   non-deal). Deal-tier flags + marquee flags keep their colored identities. */
.sc-map-wrap[data-show-dark-marker-flags] .sc-marker-flag:not(.sc-marker-flag-marquee):not(.sc-deal-90):not(.sc-deal-70) {
   background: var(--color-primary) !important;
   border-color: var(--color-primary) !important;
   box-shadow: 0 4px 14px rgba(0, 36, 72, 0.32) !important;
}
.sc-map-wrap[data-show-dark-marker-flags] .sc-marker-flag:not(.sc-marker-flag-marquee):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-price {
   color: #fff;
}
.sc-map-wrap[data-show-dark-marker-flags] .sc-marker-flag:not(.sc-marker-flag-marquee):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-debug {
   color: rgba(255, 255, 255, 0.92) !important;
}
.sc-map-wrap[data-show-dark-marker-flags] .sc-marker-flag:not(.sc-marker-flag-marquee):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-tail {
   background: var(--color-primary) !important;
   border-right-color: var(--color-primary) !important;
   border-bottom-color: var(--color-primary) !important;
}

/* ── Deal-tier flag colorways ─────────────────────────────────────────── */
/* ds ≥ 90 → solid green, white text. The whole flag (price + meta + tail)
   recolors so it reads at a glance as a top deal. */
.sc-marker-flag.sc-deal-90 {
   background: #0B8C67;
   border-color: #0B8C67;
   box-shadow: 0 4px 12px rgba(11, 140, 103, 0.32);
}
.sc-marker-flag.sc-deal-90 .sc-dbf-price,
.sc-marker-flag.sc-deal-90 .sc-dbf-debug { color: #fff; }
.sc-marker-flag.sc-deal-90 .sc-dbf-tail {
   background: #0B8C67;
   border-right-color: #0B8C67;
   border-bottom-color: #0B8C67;
}
/* ds ≥ 70 → solid dark green, white text. */
.sc-marker-flag.sc-deal-70 {
   background: #015446;
   border-color: #015446;
   box-shadow: 0 4px 12px rgba(1, 84, 70, 0.32);
}
.sc-marker-flag.sc-deal-70 .sc-dbf-price,
.sc-marker-flag.sc-deal-70 .sc-dbf-debug { color: #fff; }
.sc-marker-flag.sc-deal-70 .sc-dbf-tail {
   background: #015446;
   border-right-color: #015446;
   border-bottom-color: #015446;
}

/* ── Top-3 Marquee — diagonal gradient + navy text ────────────────────── */
.sc-marker-flag.sc-marquee-top3 {
   background: var(--gradient-flag-cta, linear-gradient(135deg, #5FFFBC 0%, #00D9FF 100%));
   border: 0;
   box-shadow: 0 4px 14px rgba(0, 217, 255, 0.30);
   padding: 0.36em 0.6em 0.45em;
}
.sc-marker-flag.sc-marquee-top3 .sc-dbf-price,
.sc-marker-flag.sc-marquee-top3 .sc-dbf-debug,
.sc-marker-flag.sc-marquee-top3 .sc-mf-spark { color: var(--color-primary) !important; }
/* Tail picks up the right side of the gradient (a single color
   approximating the gradient's bottom-right corner). */
.sc-marker-flag.sc-marquee-top3 .sc-dbf-tail {
   background: #00D9FF;
   border-right-color: #00D9FF;
   border-bottom-color: #00D9FF;
}

/* Non-top-3 marquee on plain white bg: editorial in navy, sparkle inherits
   the same navy color (currentColor on the mask icon). */
.sc-marker-flag.sc-marquee-flag:not(.sc-marquee-top3):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-debug,
.sc-marker-flag.sc-marquee-flag:not(.sc-marquee-top3):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-price {
   color: var(--color-primary);
}

/* ── Visual diet for non-gradient flags ──────────────────────────────────
   Top-3 marquee (gradient) keep their full size — they're the headline
   pickrs. Every OTHER marker flag (non-gradient marquee + deal-tier +
   plain marker flags) gets a slightly tighter padding + smaller fonts so
   the gradient flags read as primary. */
.sc-marker-flag:not(.sc-marquee-top3) {
   padding: 0.27em 0.5em 0.36em;
}
.sc-marker-flag:not(.sc-marquee-top3) .sc-dbf-price {
   font-size: 1.18em;
}
.sc-marker-flag:not(.sc-marquee-top3) .sc-dbf-debug {
   font-size: 0.82em;
}
/* Non-gradient marquee variant (still has the slightly larger base) gets
   trimmed too — overriding the .sc-marquee-flag bumps above. */
.sc-marker-flag.sc-marquee-flag:not(.sc-marquee-top3) .sc-dbf-price { font-size: 1.27em; }
.sc-marker-flag.sc-marquee-flag:not(.sc-marquee-top3) .sc-dbf-debug { font-size: 0.91em; }
.sc-marker-flag.sc-marquee-flag:not(.sc-marquee-top3) .sc-mf-spark { width: 0.8em; height: 0.8em; }

/* White flags (non-gradient, non-deal-tier) keep the same diet padding
   as other non-gradient flags. Earlier `2px 7px 3px` cut was too tight. */
.sc-marker-flag:not(.sc-marquee-top3):not(.sc-deal-90):not(.sc-deal-70) {
   padding: 0.27em 0.5em 0.36em;
}
/* Non-marquee white flags get a tighter price font (1em vs 1.18em) so
   they read as the lowest visual tier on the map. Padding L/R and the
   gap between price + meta also tightened by a bit. */
.sc-marker-flag:not(.sc-marquee-flag):not(.sc-deal-90):not(.sc-deal-70) {
   padding: 0.27em 0.5em 0.36em;
}
.sc-marker-flag:not(.sc-marquee-flag):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-price {
   font-size: 1em;
}
.sc-marker-flag:not(.sc-marquee-flag):not(.sc-deal-90):not(.sc-deal-70) .sc-dbf-debug {
   margin-top: 0.18em;
}

/* Sparkle on the price line (next to the dollar amount). */
.sc-dbf-price .sc-mf-spark { margin-right: 0.36em; vertical-align: -1px; }

/* ── Ticket dots (markers) — em-based sizing inherits from the SVG
   ROOT font-size, which `InteractiveMap` maintains on every zoom
   (`_scaleLabelsByZoom` → `svg.style.fontSize`). One source of truth.
   Our em coefficients below resolve against that root value. */
[data-role='marker'] {
   r: 0.4em;
   stroke-width: 0.2em;
   stroke: #ffffff;
   fill: var(--sc-dot-color, #324d6d);
   paint-order: stroke;   /* stroke paints behind fill → outer halo, full-color dot */
   transform-origin: center;
   transform-box: fill-box;
   transition: transform 120ms ease, fill 120ms ease;
}
[data-role='marker'][data-tier='deal']       { r: 0.56em; fill: #015446; }
[data-role='marker'][data-tier='super-deal'] { r: 0.64em; fill: #0B8C67; }

/* Page-match affordance — ticket falls inside the user's current section
   or zone scope. Two children are stamped inside the `<g data-zone-match>`:
   an outer ring BEHIND the dot (darker-lavender, slightly larger than the
   biggest tier's marker) + a star glyph ON TOP of the dot (white, sized
   to fit inside even the smallest base-tier marker). Both em-anchored so
   they scale with zoom. Pointer-events: none on both → they don't
   intercept hover / clicks on the underlying marker. */
[data-role='marker-match-ring'] {
   r: 0.9em;
   fill: none;
   stroke: #6b5fa3;
   stroke-width: 0.1em;
   opacity: 0.9;
}
[data-role='marker-match-star'] {
   fill: #ffffff;
   font-size: 0.7em;
   font-family: 'Geist', system-ui, -apple-system, sans-serif;
   font-weight: 700;
   /* Opt out of OS emoji rendering — keep ★ as a fillable text glyph
      instead of the colored emoji variant on macOS / iOS. */
   font-variant-emoji: text;
}

/* Dot hover (self OR via group .is-hover from coordinator) — scale lift
   + uniform black fill, regardless of tier. Stroke (white halo) stays.
   Base-tier dots get an extra ~20% scale so their hovered size lands
   close to the deal-tier hover, evening out the visual feedback across
   tiers. */
[data-role='marker']:hover,
[data-role='ticket-group'].is-hover [data-role='marker'] {
   transform: scale(1.55);
   fill: #000 !important;
}
[data-role='marker'][data-tier='base']:hover,
[data-role='ticket-group'].is-hover [data-role='marker'][data-tier='base'] {
   transform: scale(1.86);
}

.sc-marker-flag,
.sc-marker-flag-marquee {
   transition: background 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
}
/* Unified flag hover — ANY flag variant (white, deal-tier, marquee,
   top-3 gradient) goes BLACK BG + WHITE elements on hover. Box-shadow
   lift preserved (kept from prior tier rules). Both `:hover` and
   `.is-hover` (set by the JS hover coordinator when the dot or label
   is the hover origin) trigger the same state. */
.sc-marker-flag:hover,
.sc-marker-flag.is-hover {
   background: #000 !important;
   border-color: #000 !important;
   box-shadow: 0 10px 26px rgba(0, 0, 0, 0.32) !important;
   z-index: 60 !important;
   cursor: pointer;
}
.sc-marker-flag:hover .sc-dbf-price,
.sc-marker-flag.is-hover .sc-dbf-price,
.sc-marker-flag:hover .sc-dbf-debug,
.sc-marker-flag.is-hover .sc-dbf-debug,
.sc-marker-flag:hover .sc-mf-spark,
.sc-marker-flag.is-hover .sc-mf-spark {
   color: #fff !important;
}
.sc-marker-flag:hover .sc-dbf-tail,
.sc-marker-flag.is-hover .sc-dbf-tail {
   background: #000 !important;
   border-right-color: #000 !important;
   border-bottom-color: #000 !important;
}

/* NOTE: do NOT transition `transform` on `.sc-zone-flag` — the overlay
   positioning pass re-applies `transform` every frame during pan/zoom,
   and transitioning it makes labels visibly bounce as the map moves.
   The hover lift is applied to an inner span below so it animates
   independently of the outer overlay's positioning transform. */
.sc-zone-flag {
   transition: color 120ms ease;
}
.sc-zone-flag .sc-zf-body {
   transition: transform 140ms ease;
}
.sc-zone-flag:hover {
   z-index: 40 !important;
}
.sc-zone-flag:hover .sc-zf-body {
   transform: translateY(-2px);
}
.sc-zone-flag:hover,
.sc-zone-flag:hover .sc-zf-name,
.sc-zone-flag:hover .sc-zf-price,
.sc-zone-flag:hover .sc-zf-from,
.sc-zone-flag:hover .sc-zf-icons { color: #0067ce !important; }

/* ── Loading affordance ──────────────────────────────────────────────── */
.sc-loading {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   color: var(--text-low);
   font-size: var(--font-size-smaller);
}
