world-map { display: contents; } /* transparent wrapper — layout sees the inner <svg> directly */

#map-container { position: fixed !important; top: var(--page-header-h, var(--csb-h, 8rem)); left: 0; right: 0; z-index: 100; padding-left: var(--vert-gutter) !important; padding-right: var(--vert-gutter) !important; display: flex; justify-content: center; align-items: flex-start; background: var(--fixed-element-bg); transition: top 0.4s ease; }
@media (max-width: 500px) {
  #map-container { padding: 0 !important; margin: 0 !important;}
  /* #map-footer (index.html) stays the same single flex container, no DOM change — just
     reflowed onto 2 lines here. flex-wrap:wrap is what allows a 2nd line to exist at all (the
     base rule is a single nowrap row); #legend at width:100% is what forces it onto a line by
     itself (nothing else can share a line with a 100%-wide item, before or after). order:-1
     pulls #legend's line ahead of the rest despite it being LAST in DOM order (it has to stay
     last there — z-index/stacking and #legend-filter-device's own
     position:absolute-against-#legend-relative wiring, js/map-container.js's wireLegend(), don't
     care about DOM order, but nothing here needed changing that just to also flip the visual
     order). Everything else (#map-controls, #map-grip)
     wraps onto line 2 together, in their own existing DOM order, at the default order:0 — no
     wrapper element needed for that grouping, plain flex-wrap already does it once line 1 is
     full.
     justify-content:flex-start (overriding the base rule's space-between, which would otherwise
     spread line 2's own items across the full row width, stranding #map-grip and
     #map-controls far apart instead of side by side) + gap keeps them readably grouped.
     Both !important overrides here are load-bearing, not defensive: #map-footer's own
     space-between comes from its justify-content-between HTML class, a Bootstrap utility (always
     !important) — a plain declaration here would lose to it regardless of source order. #legend's
     own width:40% (below, unconditional) sits *later* in this file than this media query block,
     so at equal specificity a plain width here would also lose on source order alone. */
  #map-footer { flex-wrap: wrap; justify-content: flex-start !important; gap: .5rem; }
  #legend { width: 100% !important; order: -1; }
  /* #map-grip's own centering (position:absolute; left/top:50%; translate(-50%,-50%), below)
     is intentionally left untouched here, on purpose, not by oversight: it's a direct child of
     #map-footer, and per spec an absolutely-positioned flex child isn't a flex item at all —
     wrap/order have zero effect on it, so left:50% still centers it on #map-footer's own FULL
     width exactly as before, regardless of how many lines its (real, in-flow) siblings wrap
     into. (An earlier version of this wrapped #map-grip inside a dedicated flex:1 sibling of
     #legend, meaning to give it a stable per-line box to center on — that fixed the vertical
     axis but broke the horizontal one: the wrapper is narrower than #map-footer on desktop
     [only the space left of #legend's own 40%], so left:50% centered it on the wrong, smaller
     box. Reverted.)
     top:50% is the one piece that's still wrong here, though — it centers vertically across the
     *whole*, now 2-line-tall, #map-footer, landing in the gap between the lines rather than on
     either one. There's no pure-CSS anchor for "line 2's own vertical center" (flex lines aren't
     addressable boxes), so js/index.js's _syncMapGripTop() measures #legend's own real
     rendered height at this breakpoint and sets an explicit top in px — see that function's own
     comment. */
  /* #legend's own margin (base rule: 1rem both sides, below — just enough to keep a grip from
     clipping past #map-footer's own edge, see #legend-filter-device's own comment) needs to be
     bigger here specifically: #map-container's own padding is stripped to 0 above at this
     breakpoint, and #legend is 100% wide, so #map-footer's own edges ARE the window's own
     edges now — a grip sitting right at that boundary, margin's the bare 1rem clipping minimum,
     is flush against the actual screen edge, which is a real touch-target problem (hard to grab
     reliably, plus it competes with the browser's own edge-swipe gestures). 2rem here — 1rem of
     that is still the clipping floor, the other 1rem is genuinely extra clearance from the
     window edge specifically, not from #map-footer's own (here: same thing). No matching
     #legend-filter-device override needed: its own inset stays exactly 1rem always, since that
     number is about the grip-to-content gap, a completely different concern from this one. */
  #legend { margin: 0 2rem !important; }
}

/* Ctrl-M / #map-toggle-bar (js/index.js) — a real Bootstrap Collapse
   (#map-collapse) now owns the show/hide animation and #bottomTabContent stays in
   sync via #map-container's own live height (see _syncPaddingTop), same as any other
   resize. This bar itself never collapses — mirrors .csb-toggle (control-sidebar.css)
   but horizontal (full width, top of the map) instead of vertical (side of the
   sidebar): width:100% instead of align-self:stretch, since it's a column child here
   rather than a row sibling. */
#map-toggle-bar {
  width: 100%; height: 16px; min-height: 16px; padding: 0;
  background: var(--bg-hover);
  border: none; appearance: none;
  cursor: pointer; color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  font-size: 11px; line-height: 1;
  user-select: none; -webkit-user-select: none;
}
#map-toggle-bar:hover { color: #333; }

/* map */
/* Wraps just <world-map>+#zoom-hint (not #map-footer) — the positioning context
   #zoom-hint anchors to below, and its own clip-path crops the hint to exactly #map's
   rendered height (whatever that is: aspect-ratio auto, or the #map-footer
   drag-resize's inline px override — js/index.js) with no JS needed to measure
   it. A percentage height on #zoom-hint itself couldn't do this instead: this wrapper's
   own CSS height is 'auto' (content-driven), and percentage heights against an
   auto-height containing block resolve to nothing per spec — the same restriction
   #map-collapse's own height:100% below works around by getting an explicit height.
   clip-path, not overflow-y:hidden (with overflow-x:visible to spare the horizontal
   axis) — #zoom-hint's own left:100% deliberately renders it entirely outside this
   frame's right edge, in #map-container's own right gutter (its own padding-right:
   var(--vert-gutter), above), same as it always has, and per spec a `visible`/`hidden`
   overflow-x/y pair computes the visible side to `auto` instead — still a clipping
   scroll container, silently clipping the hint right back. clip-path has no such
   pairing rule: inset(top right bottom left), so 0 on every side but right (pushed
   off by -100vw) clips vertically flush with the box while leaving the right side
   effectively unbounded. */
#map-frame { position: relative; clip-path: inset(0 -100vw 0 0); }
#map { display: block; width: 100%; height: auto; touch-action: none; background-color: var(--fixed-element-bg); overflow: hidden; padding-bottom: 0.5px; background-color: rgba(180, 195, 196, 0.667);}
.country { cursor: default; transition: opacity .12s; }
.country:hover { opacity: .7; }
body.dim-active #map, body.dim-active #map * { cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><line x1='4' y1='4' x2='16' y2='16' stroke='%23555' stroke-width='2.5' stroke-linecap='round'/><line x1='16' y1='4' x2='4' y2='16' stroke='%23555' stroke-width='2.5' stroke-linecap='round'/></svg>") 10 10, auto !important; }
body.dim-active #map [data-dim-visible] { cursor: pointer !important; }
/* left:100%/bottom:0 (relative to #map-frame, which wraps exactly #map) replace what
   used to be js/index.js's _syncMapHeight computing the same two offsets every
   resize/collapse/drag tick via getBoundingClientRect — pure layout now, always live,
   no recompute trigger needed. One behavior change: without a JS-measured max-height,
   #zoom-hint's own text-overflow:ellipsis never actually engages (nothing makes IT
   overflow) — on a very short dragged-down map, #map-frame's overflow:hidden still
   crops the hint at the right height, just as a hard cut instead of an ellipsis. */
#zoom-hint { font-size: 9px; color: var(--text-muted); pointer-events: none; writing-mode: vertical-rl; white-space: nowrap; position: absolute; left: 100%; bottom: 0; overflow: hidden; text-overflow: ellipsis; }
/* #zoom-reset/#zoom-span are normal flex children of #map-controls (index.html,
   inside #map-footer) now, not JS-positioned floats — no more position:absolute/z-index,
   no more per-frame left/bottom writes (removed from js/index.js's _syncMapHeight).
   #scroll-top-btn is unrelated (lives in #bottom-panel, its own position/icon —
   css/index.css) but shares the same button chrome, so it stays in this shared list;
   it keeps its own position:absolute separately below. */
#zoom-reset, #zoom-span, #scroll-top-btn { cursor: pointer; border: 1px solid var(--border); border-radius: 6px; background: rgba(245,242,236,.4); color: var(--text-muted); line-height: 1; font-size: 14px; width: 30px; height: 30px; padding: 2px; display: flex; align-items: center; justify-content: center; }
#scroll-top-btn { position: absolute; z-index: 10; }
/* Sized down alongside their 20px (was 24px) icons, keeping the same 2px padding + 1px
   border margin around the icon that the shared 30px/24px pairing above had.
   #scroll-top-btn keeps the original 30px box (its own icon is an unrelated tiny inline
   chevron, not one of these two). */
#zoom-reset, #zoom-span { width: 26px; height: 26px; }
#scroll-top-btn { display: none; }
#scroll-top-btn.visible { display: flex; }
#zoom-reset:disabled, #zoom-span:disabled { opacity: 0.3; cursor: default; }
/* Never grows past one line: nowrap (cascades to #legend's text
   children) plus clipping instead of letting an overlong description push
   the row wider or wrap onto a second line. */
/* Vertical-only drag handle (js/index.js) — resizes #map's own height (not
   width: #map stays width:100%, only height gets an inline px override). row-resize
   signals the affordance; touch-action:none stops touch drags from scrolling the page
   instead. user-select:none mirrors #map-toggle-bar's own guard against accidental text
   selection while dragging. Buttons inside (#zoom-reset/#zoom-span) are excluded from
   the drag in JS so their own clicks/cursor keep working. */
#map-footer { overflow-x: hidden; white-space: nowrap; cursor: row-resize; touch-action: none; user-select: none; -webkit-user-select: none; position: relative; }
/* Purely decorative grab affordance for the drag-resize above — centered over the bar
   regardless of #map-controls/#legend's own flex widths on either side, so absolute
   positioning (not a flex child) is the only way to keep it centered as those widths
   change. pointer-events:none so it never steals the drag/click handling already wired
   to #map-footer and its real children. Opacity ~0.4 over the bar's own light
   background approximates var(--text-muted) (#999) without recoloring the (solid black
   fill) source SVG. width/height overrides the <img>'s own width="20" height="20" HTML
   attributes (index.html) with a wide-short box instead of its native square one —
   object-fit:cover then zooms the horizontal dot pattern (which only occupies a thin
   strip of its own square viewBox) to actually fill that box, the same treatment
   #left-grip/#right-grip's own img give the vertical dot pattern to fill their own
   narrow-tall box (css/map-container.css, the #legend-filter-device rules below) —
   without it the two icon families read as different visual weights (a full dot grid
   vs. a faint thin row) despite being the same glyph, just oriented for a different drag
   axis. */
#map-grip { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 2rem; height: 1rem; object-fit: cover; opacity: 0.4; pointer-events: none; }
#map-footer:hover #map-grip { opacity: 0.7; }
/* cursor:default overrides #map-footer's own row-resize (inherited otherwise) — #legend no
   longer participates in that drag (js/index.js's pointerdown handler now excludes it
   entirely, see that file's own comment), so the resize cursor over it would be misleading. */
/* width: 1/3 of #map-footer (2/3 of its own half — #map-footer's other flex children sit
   to its left, this is the last one) — #map-footer's own justify-content-between (index.
   html) already keeps the last flex child flush against the right edge regardless of its width,
   so no extra alignment rule is needed here, just the width itself. Percentage resolves cleanly
   against #map-footer's own definite width (w-100) since #legend is a direct flex item of it. */
/* padding/margin used to live as an inline style (index.html) with !important — moved here
   so the @media (max-width:500px) block below can actually override margin. Inline !important
   beats *any* external stylesheet rule regardless of specificity or !important, so as long as it
   stayed inline, no media query could ever touch it — which is exactly why the left grip kept
   re-clipping the leftmost tick label there: #legend-filter-device's own left inset could be
   tuned all day, but the .5rem of padding it's measured against was unreachable.
   padding-left/right and margin-left/right are deliberately equal on both sides now (an earlier
   version had .5rem/.75rem padding and margin-right only, no margin-left — accumulated one side
   at a time, never revisited as a whole, and it showed: the left grip's own clearance from
   #map-footer's edge wasn't engineered at all, just leftover free space from
   justify-content-between that happened to be enough — not guaranteed the way the right side's
   explicit margin was). One shared formula now drives both #legend's own values and
   #legend-filter-device's own inset (below) together — see that rule's own comment for the
   derivation; padding and inset are stated here since #legend's own rule is where they're
   consumed, even though the actual numbers come from that shared formula. */
#legend { font-size: 11px; color: var(--text-muted); position: relative; cursor: default; width: 40%; padding: .5rem .5rem 0 .5rem; margin: 0 1rem; }
#legend-countries { font-size: 11px; color: #bbb; }
#legend-countries::before { content: '←\2009#'; margin-right: 0.25em; }
/* index.html's #legend uses align-items-start (not Bootstrap's default -center) —
   its 3 children (negative-outlier-dot column, gradient-bar column, positive-outlier-dot
   column) each stack a fixed-height top row (dot or bar, both 10px) over a shorter/taller
   text row below (#legend-outlier-count's auto height from a 9px font vs #legend-ticks'
   own explicit 12px, needed for its absolutely-positioned children — see its own comment
   below). Centering columns of different total height shifts their top rows out of
   alignment by that difference/2, which is exactly the "tiny pixelesque" dot-vs-bar
   misalignment this replaced. */
/* Grows to fill whatever's left of #legend's own (now 33.3333%-of-#map-footer — see #legend's
   own rule above) width once the outlier column(s) beside it take their share — #legend-bar/
   #legend-ticks below both fill this at width:100%, rather than either sizing itself directly
   against #legend or #map-footer. min-width:0 overrides the flex default (min-width:auto,
   refuses to shrink below content), needed since #legend-ticks' own tick labels have a real
   intrinsic text width that would otherwise stop this column shrinking on a narrow viewport. */
#legend-bar-col { flex: 1 1 auto; min-width: 0; }
/* position:relative — js/map-container.js's updateRug() absolutely positions one tick per real
   country by percent (matching buildGradient()'s own gradient stop positions) directly on top
   of the gradient, so a viewer can see where the data actually clusters vs. where the smooth
   gradient is just interpolating through a real gap between two countries' own values. */
#legend-bar { height: 10px; width: 100%; position: relative; }
/* background is set inline per-tick (js/map-container.js's updateRug()/_tickColor()) — a
   darkened, semi-transparent shade of the gradient's own color at that exact spot, not a fixed
   tint here, so a tick reads as "this point on the gradient, marked" rather than a generic mark
   sitting on top of an unrelated color. translateX(-50%) centers the 1px mark on its own left:X%
   point instead of starting a hard edge exactly there. */
.legend-rug-tick { position: absolute; top: 1px; bottom: 1px; width: 1px; transform: translateX(-50%); pointer-events: none; }
#legend-ticks, #legend-outlier-count, #legend-outlier-count-pos { font-family: var(--bs-font-monospace); }
/* position:relative + explicit height — js/index.js's _updateLegendTicks() absolutely
   positions each <span> by percent (matching #legend-bar's own gradient stop positions), so
   this container needs to establish both the positioning context and its own height (nothing
   in normal flow left to size it once children are taken out of flow). */
#legend-ticks { position: relative; width: 100%; height: 12px; font-size: 9px; color: var(--text-muted); margin-top: 3px; }
/* Range filter device (js/map-container.js's wireLegend()) — covers the whole #legend
   (positioned absolutely against #legend's own position:relative above), extended left/right so
   a grip parked at a domain extreme (no filtering on that side) rests beside #legend's own
   content instead of overlapping it. A flex row of 5 same-height children, left to right: the
   excluded/dimmed span before the selection, the left grip, the fully-transparent included span,
   the right grip, the excluded/dimmed span after — #left-excluded/#right-excluded grow and
   shrink (their JS-set width is how a drag actually filters anything) while #center-included
   just soaks up whatever width is left (flex:1), no width math needed for it.
   The inset extension is solved exactly, not eyeballed, from two requirements, and — unlike an
   earlier version of this rule — the SAME formula now drives both sides, because there's no
   actual reason for the two sides to work differently: each grip is 1rem wide (#left-grip/
   #right-grip below) and sits flush against this device's own edge (since #left-excluded/
   #right-excluded are 0-width at rest); and the target gap between a grip's inner edge and the
   thing it's supposed to clear — the gradient bar on the left (#legend-bar-col sits flush against
   #legend's own left padding, since #legend-outlier-neg-wrap is display:none — OUTLIER_IDS_NEG is
   empty, see its own comment), France's own outlier dot on the right (#legend-outlier-pos-wrap
   sits flush against #legend's own right padding) — is exactly .5rem on both:
     gap = padding + inset − gripWidth = .5rem target, with padding = .5rem (#legend's own rule,
     now equal on both sides) and gripWidth = 1rem → inset = 1rem, both sides.
   This depends on #legend's own left/right padding staying equal (.5rem each, see its own rule) —
   re-derive if either changes. #legend's own margin (also equal both sides now, see its own rule)
   needs to be at least this same 1rem so a grip's own far edge lands at or before
   #map-footer's own clipped boundary (overflow-x:hidden) instead of past it; the @media
   (max-width:500px) block below pushes #legend's margin further out for a real touch-target
   requirement (grips at least 1rem clear of the window edge, not just clear of clipping), but
   this inset stays exactly 1rem everywhere — nothing about the margin bump changes what it
   needs to be. inset's 2-value form (top/bottom, left/right) — deliberately not the 1-value form
   (all four sides) even though left and right now share the same number: top/bottom need to stay
   0 (flush with #legend's own height, unchanged since this device was first added), and the
   1-value shorthand would silently apply -1rem there too — which briefly happened, making the
   whole device (and #left-grip/#right-grip, height:100% of it, below) 2rem taller than #legend
   itself. Harmless-looking to the layout (nothing else depends on the device's own height beyond
   the grips), but #left-grip/#right-grip's own img is object-fit:cover, which crops differently
   against a taller box — the grip glyph itself visibly distorted. */
#legend-filter-device { position: absolute; inset: 0 -1rem; display: flex; }
#legend-filter-device > span { height: 100%; flex-shrink: 0; }
#left-excluded, #right-excluded{ width: 0; background: rgba(250,249,246,.8); }
#center-included { flex: 1 1 auto; background: transparent; }
/* .5rem wide (matching the device's own side margins above) so a grip parked at rest sits
   fully in that margin — cursor:grab/:active mirrors #map-grip's own drag affordance.
   The vertical grip glyph (images/grip-vertical-svgrepo-com.svg) is the transposed twin of
   #map-grip's horizontal one — same dot pattern, rotated 90°, for the same reason: this
   handle moves horizontally (left/right, filtering by value) rather than vertically like the
   map-height resize grip does, so the *grip* itself reads as a vertical bar of dots — the
   usual affordance for a horizontally-draggable handle. */
#left-grip, #right-grip {
  width: 1rem; background: rgba(250,249,246,.8);
  display: flex; align-items: center; justify-content: center;
  cursor: ew-resize; touch-action: none;
  padding: 0 2px; 
}
/* No object-position override needed (plain object-fit:cover, default 50% center) — an earlier
   version of this compensated here for grip-vertical-svgrepo-com.svg's own off-center content
   (its stock 16x16 viewBox wasn't centered on the actual dot pattern, which a narrow crop like
   this box's — 12px/34.5px — turned into a visibly clipped dot on one side). Fixed at the source
   instead: that SVG's own viewBox is now tightly (and correctly) centered on its content, so the
   default center crop is already correct — see that file's own comment. */
#left-grip img, #right-grip img { width: 100%; height: 100%; object-fit: cover; opacity: 0.4; pointer-events: none; }
#left-grip:hover img, #right-grip:hover img, #left-grip:active img, #right-grip:active img { opacity: 0.7; }
@media (max-width: 767.98px) {
  /* No more fixed max-width/width override here for #legend-bar/#legend-ticks — both are
     width:100% of #legend-bar-col now (a flex-grow column inside #legend's own explicit
     percentage width, above), so they already shrink to fit whatever room is actually available
     on a narrow viewport. A leftover fixed 90px cap here fought that: #legend's own share of
     #map-footer can easily still be well over 90px even under this breakpoint, so the bar
     rendered artificially short with dead space after it instead of actually filling its column
     (the "still not taking the full available width" bug this replaced). font-size shrinks the
     tick labels only — a real narrow-screen readability tweak, unrelated to the width bug. */
  #legend-ticks { font-size: 8px; }
  /* index.html's pt-1 is a Bootstrap spacing utility (!important) — needs
     matching !important to actually override it here. Without this, the gap
     above #legend reads as if it weren't top-aligned at all. */
  #map-footer { padding-top: 0 !important; }
}

@media (max-height: 500px) and (orientation: landscape) {
  mundial-auth-bar { display: none !important; }
  #map-container {
    top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important;
    z-index: 500 !important;
    padding: 0 !important;
    align-items: center !important;
    justify-content: center !important;
  }
  /* #map-collapse (the Bootstrap Collapse wrapper) sits between #map-container and #map —
     without its own height, #map's height:100% below has nothing resolvable to size
     against (percentage heights against an auto-height ancestor are ignored per spec) and
     silently falls back to #map's intrinsic aspect-ratio height instead, leaving #map
     shorter than #map-container. #map-container's own justify-content:center (above) then
     splits that leftover vertical space equally above/below #map — visible in DevTools'
     flex overlay as violet padding-looking bands, though it's flex free-space, not padding. */
  #map-collapse { height: 100%; }
  /* Same reasoning as #map-collapse just above — #map-frame is another auto-height
     wrapper between #map-collapse and #map, and #map's own height:100% needs it to
     have an explicit height to resolve against. */
  #map-frame { height: 100%; }
  #map { width: 100% !important; height: 100% !important; }
  #map-footer { display: none !important; }
  #page-header { z-index: 600 !important; background: transparent !important; pointer-events: none; margin-top: 0 !important; top: 0 !important;}
  #page-quotes { display: none !important; }
  #control-sidebar { pointer-events: auto; }
  /* Landscape mobile is always immersive-map — no room to show #bottomTabContent instead, so
     there's no toggle control at all here (js/index.js also force-expands #map-collapse
     whenever this mode becomes active, in case it was left collapsed from portrait). */
  #map-toggle-bar { display: none; }
}
