/* sbr2-map — the social-proof beacon map.
 *
 * Everything visual lives here: the container, the beacon anatomy (core dot +
 * two breathing rings), the glass counter chip, and the no-key fallback. The
 * beacon colour is one custom property (--sbr2map-beacon) so the admin colour
 * picker restyles every layer at once.
 */

.sbr2-map {
	position: relative;
	width: 100%;
	height: var(--sbr2map-h, 560px);
	overflow: hidden;
	border-radius: 0; /* hero-friendly; wrap it yourself if you want corners */
	background: #0b1626;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.sbr2-map[data-theme="light"] { background: #eef3f8; }

/* Silhouette mode is a cutout: the container itself stays fully transparent
 * so the page's own hero background shows around Sweden. */
.sbr2-map--silhouette,
.sbr2-map--silhouette[data-theme="light"] { background: transparent; }
.sbr2-map--silhouette .sbr2-map__veil { display: none; }

.sbr2-map__canvas { position: absolute; inset: 0; }

/* ── Silhouette stage: Sweden as inline SVG, beacons projected onto it ── */
.sbr2-map__stage {
	position: absolute;
	top: 0;
	left: 50%;
	height: 100%;
	transform: translateX(-50%);
}
/* Inner breathing room: the container clips (overflow: hidden), so without it
 * the southern tip and its beacon glow sit cut off on the bottom edge. Margin
 * (not top) because the JS sets inline top/left for the admin offsets. One
 * knob: --sbr2map-pad. */
.sbr2-map--silhouette .sbr2-map__stage {
	margin-top: var(--sbr2map-pad, 34px);
	height: calc(100% - 2 * var(--sbr2map-pad, 34px));
}
.sbr2-map__country { display: block; height: 100%; width: 100%; overflow: visible; }
.sbr2-map__country path {
	fill: var(--sbr2map-land, #16263f);
	stroke: rgba(120, 170, 220, 0.18);
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
}
.sbr2-map[data-theme="light"] .sbr2-map__country path {
	fill: var(--sbr2map-land, #dfe8f2);
	stroke: rgba(60, 100, 150, 0.22);
}
/* a whisper of ambient glow so the cutout sits in the hero, not on it */
.sbr2-map--silhouette .sbr2-map__country {
	filter: drop-shadow(0 0 30px color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 14%, transparent));
}

/* ── The ghost: Sweden, inline in the markup, before any data arrives ─────
 * Same geometry as the real stage (it carries the stage class), one step
 * quieter, breathing gently while the points are on their way. Three states:
 *   loading  — dim + slow breath (this rule)
 *   drawn    — faded out, the real stage is on top (.is-drawn)
 *   failed   — held still at a readable dim (.is-fallback); the map may be
 *              unreachable, but the page still shows a map.
 */
.sbr2-map__ghost {
	z-index: 0;
	opacity: 0.55;
	transition: opacity 500ms ease;
	animation: sbr2-ghost-breathe 2600ms ease-in-out infinite;
}
/* The ghost keeps the country's outline (inherited from .sbr2-map__country):
 * an outlined shape reads as a map at half opacity, a filled blob reads as a
 * smudge. Only the opacity separates it from the real thing. */
/* The real drawing has arrived — hand over. Kept in the DOM (not removed) so a
 * re-draw never flashes an empty container. */
.sbr2-map.is-drawn .sbr2-map__ghost { opacity: 0; animation: none; }
/* Nothing is coming: stop breathing and stand at full strength. This is no
 * longer a placeholder, it IS the map the visitor gets — just without lights. */
.sbr2-map.is-fallback .sbr2-map__ghost { opacity: 1; animation: none; }

@keyframes sbr2-ghost-breathe {
	0%, 100% { opacity: 0.48; }
	50%      { opacity: 0.72; }
}

/* The liveness stamp: proof the beacons are real, not a rendered image.
 * A tiny frosted pill (kin of the stats chip) so it reads on ANY background —
 * the silhouette mode floats over arbitrary hero photos. */
.sbr2-map__updated {
	position: absolute;
	right: 12px;
	bottom: 12px;
	font-size: 11px;
	line-height: 1;
	letter-spacing: 0.01em;
	color: #33475c;
	background: rgba(255, 255, 255, 0.78);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	padding: 6px 11px;
	border-radius: 999px;
	border: 1px solid rgba(20, 40, 60, 0.1);
	box-shadow: 0 1px 2px rgba(10, 25, 45, 0.12);
	pointer-events: none;
	z-index: 5;
	white-space: nowrap;
}
/* Silhouette: hang the pill centred directly under the shape — it lives in
 * the stage, so the admin offsets move them together. The bottom pad above
 * (--sbr2map-pad) is sized to give it room inside the clipped container. */
.sbr2-map__updated--under {
	right: auto;
	bottom: auto;
	top: 100%;
	left: 50%;
	transform: translate(-50%, 7px);
}

/* ── Mobile: the card must never sit ON the map. The silhouette gives up a
 * bottom band and the chip docks there, centred — overriding whatever
 * data-chip placement the desktop uses (!important beats the attribute
 * variants inside this media scope only). */
@media (max-width: 640px) {
	.sbr2-map--silhouette .sbr2-map__stage {
		margin-top: 12px;
		height: calc(100% - 208px); /* 12px top + a 196px reserved chip band */
	}
	.sbr2-map .sbr2-map__counter {
		left: 50% !important;
		right: auto !important;
		top: auto !important;
		bottom: 12px !important;
		width: min(320px, calc(100% - 32px));
		transform: translate(-50%, 8px) !important;
		/* compact anatomy so the card fits the band. The HEIGHT is set through the
		 * variable, not the property: the chipstyle rules below set `height` from
		 * the same variable at a higher specificity, so an override here would be
		 * ignored while an override of the variable is not. */
		padding: 10px 14px 11px;
		gap: 10px;
		--sbr2map-card-h: var(--sbr2map-card-h-sm, 112px);
	}
	.sbr2-map .sbr2-map__counter.is-in { transform: translate(-50%, 0) !important; }
	.sbr2-map .sbr2-map__counter { --sbr2map-num: 22px; --sbr2map-lab: 12px; --sbr2map-upd: 10px; }
	.sbr2-map .sbr2-map__counter-updated { padding-top: 6px; }
	.sbr2-map .sbr2-map__counter-dot { transform: scale(0.85); }
}

/* A whisper of vignette so beacons glow against the edges — decoration only. */
.sbr2-map__veil {
	position: absolute; inset: 0;
	pointer-events: none;
	background: radial-gradient(120% 90% at 50% 45%, transparent 55%, rgba(4, 10, 20, 0.45) 100%);
}
.sbr2-map[data-theme="light"] .sbr2-map__veil {
	background: radial-gradient(120% 90% at 50% 45%, transparent 60%, rgba(30, 50, 80, 0.12) 100%);
}
/* When the map is interactive the vignette must not eat the drag either —
 * pointer-events:none already guarantees that. */

/* ── Beacon ──────────────────────────────────────────────────────────── */
/* One beacon = core dot + halo + two pulse rings. Sized by --s (core px). */
.sbr2-map .sbr2-beacon {
	position: absolute;
	width: 0; height: 0;
	pointer-events: none;
}
/* Only Google mode moves the beacon itself (overlay draw sets a transform);
 * in the silhouette the wrapper never changes and a promoted layer per
 * beacon — a few hundred of them — is pure compositor weight. */
.sbr2-map--map .sbr2-beacon { will-change: transform; }
/* Single boats carry one ring, harbours two — see makeBeaconNode(). */
.sbr2-map .sbr2-beacon--small b::after { display: none; }
/* Whatever the beacons do stays inside the map box: the browser need not
 * re-check the rest of the page for every pulse. */
.sbr2-map { contain: layout paint style; }
/* Off screen or mid-scroll the beacons stand still — see watchScroll() and
 * watchVisibility() in map.js. Paused, not removed: they resume in place. */
.sbr2-map.is-offscreen .sbr2-beacon i,
.sbr2-map.is-offscreen .sbr2-beacon b,
.sbr2-map.is-offscreen .sbr2-beacon b::after,
.sbr2-map.is-scrolling .sbr2-beacon i,
.sbr2-map.is-scrolling .sbr2-beacon b,
.sbr2-map.is-scrolling .sbr2-beacon b::after {
	animation-play-state: paused;
}
.sbr2-map .sbr2-beacon i,
.sbr2-map .sbr2-beacon b,
.sbr2-map .sbr2-beacon b::after {
	content: "";
	display: block;
	position: absolute;
	left: 50%; top: 50%;
	border-radius: 50%;
	transform: translate(-50%, -50%);
}
/* the core */
.sbr2-map .sbr2-beacon i {
	width: var(--s, 8px); height: var(--s, 8px);
	background: var(--sbr2map-beacon, #38bdf8);
	/* plain-shadow fallback first: an unsupported color-mix() drops only the
	 * richer declaration below, never the glow itself */
	box-shadow: 0 0 calc(var(--s, 8px) * 1.6) 0 var(--sbr2map-beacon, #38bdf8);
	box-shadow:
		0 0 calc(var(--s, 8px) * 1.2) 0 var(--sbr2map-beacon, #38bdf8),
		0 0 calc(var(--s, 8px) * 3) 0 color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 35%, transparent);
	animation: sbr2-beacon-in 700ms cubic-bezier(0.2, 0.9, 0.3, 1.4) both;
	animation-delay: var(--d, 0ms);
}
/* the breathing rings */
.sbr2-map .sbr2-beacon b,
.sbr2-map .sbr2-beacon b::after {
	width: var(--s, 8px); height: var(--s, 8px);
	border: 1.5px solid var(--sbr2map-beacon, #38bdf8);
	opacity: 0;
	animation: sbr2-beacon-pulse 3200ms cubic-bezier(0.25, 0.6, 0.4, 1) infinite;
	animation-delay: calc(var(--d, 0ms) + var(--p, 0ms));
}
.sbr2-map .sbr2-beacon b::after { animation-delay: calc(var(--d, 0ms) + var(--p, 0ms) + 1600ms); }

@keyframes sbr2-beacon-in {
	from { transform: translate(-50%, -50%) scale(0); opacity: 0; }
	to   { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
@keyframes sbr2-beacon-pulse {
	0%   { transform: translate(-50%, -50%) scale(1);   opacity: 0.9; }
	70%  { transform: translate(-50%, -50%) scale(3.2); opacity: 0; }
	100% { transform: translate(-50%, -50%) scale(3.2); opacity: 0; }
}

/* ── Stats chip (rotates through the enabled brag-stats) ─────────────── */
.sbr2-map .sbr2-map__counter {
	position: absolute;
	left: 20px; bottom: 28px;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 12px;
	/* Fixed size: every fact card is the SAME box, whichever fact is showing.
	 * Width was fixed first (long labels wrap instead of growing sideways);
	 * height is fixed here too, because a card that grows downward moves its
	 * own bottom edge every five seconds. What gives instead is the type —
	 * fitChip() in map.js shrinks it through --sbr2map-fit until the longest
	 * fact fits the box. */
	width: min(280px, calc(100% - 40px));
	height: var(--sbr2map-card-h, 116px);
	box-sizing: border-box;
	overflow: hidden;
	align-content: center;
	padding: 12px 18px 13px;
	border-radius: 14px;
	background: rgba(8, 17, 32, 0.62);
	border: 1px solid rgba(255, 255, 255, 0.08);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
	opacity: 0;
	transform: translateY(8px);
	transition: opacity 600ms ease 200ms, transform 600ms ease 200ms;
	pointer-events: none;
}
.sbr2-map .sbr2-map__counter.is-in { opacity: 1; transform: translateY(0); }

/* The timestamp as the card's own footer — one composed object instead of a
 * second floating pill. A hairline separates it from the rotating fact. */
.sbr2-map__counter-updated {
	flex-basis: 100%;
	margin-top: 2px;
	padding-top: 8px;
	border-top: 1px solid rgba(255, 255, 255, 0.12);
	font-size: calc(var(--sbr2map-upd, 10.5px) * var(--sbr2map-fit, 1));
	letter-spacing: 0.02em;
	color: rgba(255, 255, 255, 0.5);
}
.sbr2-map[data-chipstyle="light"] .sbr2-map__counter-updated,
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-updated {
	border-top-color: rgba(31, 41, 51, 0.08);
	color: #80868b;
}
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-updated {
	border-top-color: rgba(23, 78, 166, 0.14);
	color: #5f7ea6;
	color: color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 22%, #5f6e80);
}

/* Chip placement (data-chip): bottom-left is the base above. */
.sbr2-map[data-chip="bottom-right"] .sbr2-map__counter { left: auto; right: 20px; }
.sbr2-map[data-chip="mid-left"] .sbr2-map__counter,
.sbr2-map[data-chip="mid-right"] .sbr2-map__counter {
	bottom: auto;
	top: 50%;
	transform: translateY(calc(-50% + 8px));
}
.sbr2-map[data-chip="mid-right"] .sbr2-map__counter { left: auto; right: 20px; }
.sbr2-map[data-chip="mid-left"] .sbr2-map__counter.is-in,
.sbr2-map[data-chip="mid-right"] .sbr2-map__counter.is-in { transform: translateY(-50%); }
.sbr2-map[data-theme="light"][data-chipstyle="glass"] .sbr2-map__counter {
	background: rgba(255, 255, 255, 0.78);
	border-color: rgba(15, 35, 60, 0.08);
	box-shadow: 0 8px 28px rgba(20, 40, 70, 0.16);
}

/* ── Chip styles (data-chipstyle; the glass above is data-chipstyle="glass") ── */
/* "light": the Google card — white surface, Material elevation, calm greys
 * (#202124 / #5f6368), medium-weight numerals, and the beacon as a quiet dot
 * inside a tonal circle instead of a neon glow. */
.sbr2-map[data-chipstyle="light"] .sbr2-map__counter,
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter {
	/* roomier padding + the 36px dot: the same fact needs a slightly taller box
	 * here than in the glass style. */
	height: var(--sbr2map-card-h, 124px);
	background: #fff;
	border: 1px solid #dadce0;
	border-radius: 16px;
	box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.30), 0 1px 3px 1px rgba(60, 64, 67, 0.15);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	padding: 14px 20px 15px;
	gap: 14px;
}
.sbr2-map[data-chipstyle="light"] .sbr2-map__counter-num,
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-num {
	color: #202124;
	font-weight: 500;
	letter-spacing: 0;
}
.sbr2-map[data-chipstyle="light"] .sbr2-map__counter-label,
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-label {
	color: #5f6368;
	font-weight: 400;
}
.sbr2-map[data-chipstyle="light"] .sbr2-map__counter-dot,
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-dot {
	width: 36px;
	height: 36px;
	box-shadow: none;
	/* dot-in-a-tonal-circle, one element: the gradient paints the inner dot */
	background:
		radial-gradient(circle at 50% 50%, var(--sbr2map-beacon, #38bdf8) 0 5px, transparent 5.5px),
		#e8f0fe;
	background:
		radial-gradient(circle at 50% 50%, var(--sbr2map-beacon, #38bdf8) 0 5px, transparent 5.5px),
		color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 12%, #fff);
}
/* "tonal": the whole card takes the beacon tint — Google's tonal chip. */
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter {
	background: #e8f0fe;
	background: color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 13%, #fff);
	border-color: transparent;
	box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.18);
}
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-num {
	color: #174ea6;
	color: color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 45%, #10243c);
}
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-label {
	color: #1a5da8;
	color: color-mix(in srgb, var(--sbr2map-beacon, #38bdf8) 32%, #33475c);
}
.sbr2-map[data-chipstyle="tonal"] .sbr2-map__counter-dot {
	background:
		radial-gradient(circle at 50% 50%, var(--sbr2map-beacon, #38bdf8) 0 5px, transparent 5.5px),
		rgba(255, 255, 255, 0.85);
}
.sbr2-map .sbr2-map__counter-text {
	display: flex;
	flex-direction: column;
	gap: 3px;
	opacity: 1;
	transform: translateY(0);
	transition: opacity 260ms ease, transform 260ms ease;
}
/* Tight mode (set by fitChip when the fact will not fit as-is): the decorative
 * dot steps aside so the text gets the card's full width. Only then does the
 * type shrink — a wider measure beats smaller letters. */
.sbr2-map .sbr2-map__counter.is-tight .sbr2-map__counter-dot { display: none; }
.sbr2-map .sbr2-map__counter.is-tight .sbr2-map__counter-text { flex-basis: 100%; }

.sbr2-map .sbr2-map__counter.is-swapping .sbr2-map__counter-text {
	opacity: 0;
	transform: translateY(6px);
}
.sbr2-map .sbr2-map__counter-num {
	/* × --sbr2map-fit: the shrink factor fitChip() lands on. Every text size in
	 * the card scales together, so a shrunken card keeps its proportions. */
	font-size: calc(var(--sbr2map-num, 28px) * var(--sbr2map-fit, 1));
	font-weight: 700;
	letter-spacing: -0.5px;
	line-height: 1;
	color: #fff;
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
}
.sbr2-map .sbr2-map__counter-label {
	font-size: calc(var(--sbr2map-lab, 13px) * var(--sbr2map-fit, 1));
	font-weight: 500;
	color: rgba(255, 255, 255, 0.72);
	letter-spacing: 0.1px;
	line-height: 1.35;
}
.sbr2-map[data-theme="light"][data-chipstyle="glass"] .sbr2-map__counter-num   { color: #0b1626; }
.sbr2-map[data-theme="light"][data-chipstyle="glass"] .sbr2-map__counter-label { color: rgba(11, 22, 38, 0.6); }
.sbr2-map .sbr2-map__counter-dot {
	align-self: center;
	width: 8px; height: 8px;
	border-radius: 50%;
	background: var(--sbr2map-beacon, #38bdf8);
	box-shadow: 0 0 10px var(--sbr2map-beacon, #38bdf8);
}

/* ── No-key / error fallback: quiet gradient + the counter still shows ──
 * Framed modes only. The silhouette is a CUTOUT over whatever hero the page
 * has, so painting a panel behind it would drop a coloured rectangle onto the
 * design — there the ghost shape alone carries the failure. */
.sbr2-map:not(.sbr2-map--silhouette).is-fallback .sbr2-map__canvas {
	background:
		radial-gradient(90% 70% at 70% 20%, rgba(56, 130, 200, 0.14), transparent 60%),
		linear-gradient(160deg, #0d1b30 0%, #0b1626 55%, #091120 100%);
}
.sbr2-map:not(.sbr2-map--silhouette)[data-theme="light"].is-fallback .sbr2-map__canvas {
	background:
		radial-gradient(90% 70% at 70% 20%, rgba(90, 150, 210, 0.18), transparent 60%),
		linear-gradient(160deg, #f2f6fa 0%, #e8eef5 100%);
}

/* Non-interactive mode: the map is a picture. */
.sbr2-map[data-interactive="0"] .sbr2-map__canvas { pointer-events: none; }

@media (max-width: 600px) {
	.sbr2-map .sbr2-map__counter { left: 12px; bottom: 16px; padding: 10px 14px; }
	.sbr2-map[data-chip="bottom-right"] .sbr2-map__counter,
	.sbr2-map[data-chip="mid-right"] .sbr2-map__counter { left: auto; right: 12px; }
	.sbr2-map .sbr2-map__counter { --sbr2map-num: 24px; --sbr2map-lab: 12.5px; }
}

@media (prefers-reduced-motion: reduce) {
	.sbr2-map .sbr2-beacon i { animation: none; }
	.sbr2-map .sbr2-beacon b, .sbr2-map .sbr2-beacon b::after { animation: none; opacity: 0; }
	.sbr2-map .sbr2-map__counter { transition: none; opacity: 1; transform: none; }
	.sbr2-map[data-chip="mid-left"] .sbr2-map__counter,
	.sbr2-map[data-chip="mid-right"] .sbr2-map__counter { transform: translateY(-50%); }
}
