/*
 * Fallbacks only. The real values are printed onto the container by the
 * shortcode from the saved settings; these must stay in step with
 * tbt_world_map_default_settings() so a page rendered before settings are
 * saved does not flash a different palette.
 */
.tbt-world-map {
	--tbt-base-color: #E6E1D7;
	--tbt-highlight-color: #6B1A2B;
	--tbt-pin-color: #111827;
	--tbt-ocean-color: #1B5A82;
	--tbt-hover-color: #2F4858;
	--tbt-border-color: #FFFFFF;
	--tbt-label-color: #4A5560;
	--tbt-map-height: 520px;

	/*
	 * Surface tiles. Generated, not downloaded -- these are the only "images"
	 * the plugin has and they cost nothing to serve, which matters on a host
	 * that already refuses to serve .svg out of the plugins folder.
	 *
	 * stitchTiles="stitch" is load-bearing: without it the turbulence does not
	 * line up at tile edges and a visible grid appears across the map.
	 *
	 * paper and canvas differ from grain by feDiffuseLighting -- the noise is
	 * treated as a height field and lit from an angle, which is what produces
	 * highlights and shadows rather than speckle. canvas stretches the noise
	 * along one axis and crosses two lit layers, which is what turns pulp into
	 * woven fibre.
	 */
	--tbt-tex-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
	--tbt-tex-paper: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.045' numOctaves='5' stitchTiles='stitch' result='n'/%3E%3CfeDiffuseLighting in='n' lighting-color='white' surfaceScale='2.4'%3E%3CfeDistantLight azimuth='45' elevation='58'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='320' height='320' filter='url(%23p)'/%3E%3C/svg%3E");
	--tbt-tex-canvas: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='c'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75 0.03' numOctaves='3' stitchTiles='stitch' result='a'/%3E%3CfeDiffuseLighting in='a' lighting-color='white' surfaceScale='1.8'%3E%3CfeDistantLight azimuth='70' elevation='62'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Cfilter id='d'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.03 0.75' numOctaves='3' stitchTiles='stitch' result='b'/%3E%3CfeDiffuseLighting in='b' lighting-color='white' surfaceScale='1.8'%3E%3CfeDistantLight azimuth='160' elevation='62'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='320' height='320' filter='url(%23c)'/%3E%3Crect width='320' height='320' filter='url(%23d)' opacity='0.55'/%3E%3C/svg%3E");

	position: relative;
	width: 100%;
	max-width: 100%;
}

/*
 * `hidden` is enforced by a browser (user-agent) rule, and author styles beat
 * user-agent styles outright -- specificity never enters into it. So any rule
 * in this file that sets `display` on an element cancels its own `hidden`
 * attribute, which is what .tbt-world-map__focus (`display: flex`) was doing.
 *
 * The focus bar therefore showed on every view from page load: an opaque bar
 * at z-index 3 across the bottom of the map, swallowing clicks on whatever sat
 * underneath (the click handler deliberately ignores anything inside
 * .tbt-world-map__focus). Countries near the bottom edge stopped responding,
 * and the permanently live "Back to continent" button reset the zoom.
 *
 * !important so this keeps winning against any `display` added later without
 * this trap in mind.
 */
.tbt-world-map [hidden] {
	display: none !important;
}

.tbt-world-map__stage {
	position: relative;
	width: 100%;
	height: var(--tbt-map-height);
	overflow: hidden;
	/* Each map keeps its own aspect ratio, so it letterboxes inside the stage.
	   Tinting the stage means the spare space reads as more ocean rather than
	   as a gap -- continent crops vary a lot in shape. */
	background: var(--tbt-ocean-color);
	/* Let a one-finger swipe scroll the page as normal -- trapping vertical
	   drags inside a full-width map makes the page feel broken on a phone.
	   Two-finger pinch still zooms the map. */
	touch-action: pan-y;
}

/*
 * Depth overlays (1.12.0): vignette and surface texture.
 *
 * These sit on the stage, above the SVG but under every control, and never
 * inside the map. That placement is the whole design. Anything defined in the
 * map's own coordinate space -- an SVG <pattern>, a filter on the countries --
 * scales with the viewBox, so zooming in would magnify fine grain into blobs.
 * Real paper does not zoom with the map. A stage-level layer is independent of
 * the viewBox, and being static it rasterises once rather than per frame.
 *
 * z-index 1 puts them above the panels (auto) and below the zoom buttons (2),
 * the back button (2) and the focus bar (3). pointer-events: none so nothing
 * they cover stops being clickable -- the focus bar already taught us what an
 * invisible full-width layer does to a click handler.
 *
 * Both default to fully off, so an install that never picks a theme renders
 * exactly as it did before this existed.
 */
.tbt-world-map__stage::before,
.tbt-world-map__stage::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
}

/* Cheapest depth there is: a plain radial gradient, no filter, no per-frame
   cost. Alpha 0 when the setting is 0, so the layer is simply invisible. */
.tbt-world-map__stage::before {
	background: radial-gradient( ellipse at 50% 45%,
		rgba( 0, 0, 0, 0 ) 42%, rgba( 0, 0, 0, var( --tbt-vignette, 0 ) ) 100% );
}

/*
 * Surface texture. Sized in CSS pixels, not map units, for the reason above.
 *
 * The three tiles are data URIs declared below. `grain` is flat noise; `paper`
 * and `canvas` run that noise through feDiffuseLighting, which treats it as a
 * height field and lights it from an angle. That lighting is what makes a
 * surface read as material -- flat noise at a tasteful opacity is invisible and
 * at a visible one looks like a bad TV signal, with nothing useful in between.
 */
.tbt-world-map__stage::after {
	background-image: var( --tbt-tex, none );
	background-size: 320px 320px;
	opacity: var( --tbt-tex-opacity, 0 );
	mix-blend-mode: var( --tbt-tex-blend, normal );
}

.tbt-world-map__panel svg {
	cursor: grab;
}

.tbt-world-map.is-panning,
.tbt-world-map.is-panning * {
	cursor: grabbing !important;
}

.tbt-world-map__zoom {
	position: absolute;
	top: 12px;
	right: 12px;
	z-index: 2;
	display: flex;
	flex-direction: column;
	gap: 4px;
}

/*
 * The on-map controls: both zoom buttons, the reset button and the two back
 * buttons. They are one visual family and are coloured as one (1.13.0).
 *
 * They used to take --tbt-highlight-color with hardcoded white text, which tied
 * the buttons to the *country highlight* colour for no reason beyond both being
 * "the accent". A deep red reads well as a highlighted country and poorly as a
 * button, and the two cannot be tuned independently while they share a value.
 *
 * The fallback chain is what keeps the upgrade silent: an unset control colour
 * resolves to the highlight colour, exactly as before, so a site that never
 * touches these settings renders identically. That only works while the
 * variable is genuinely *absent* -- see tbt_world_map_css_vars(), which omits
 * the declaration rather than emitting an empty one, because `--x: ;` is a
 * valid empty value and would win over the fallback rather than fall through.
 */
.tbt-world-map__zoom button,
.tbt-world-map__back,
.tbt-world-map__focus-clear,
.tbt-world-map__focus-link {
	background: var(--tbt-control-bg, var(--tbt-highlight-color));
	color: var(--tbt-control-text, #fff);
	border: none;
	border-radius: 4px;
	cursor: pointer;
	transition: opacity 0.15s ease;
}

.tbt-world-map__zoom button:hover,
.tbt-world-map__back:hover,
.tbt-world-map__focus-clear:hover,
.tbt-world-map__focus-link:hover {
	opacity: 0.85;
}

.tbt-world-map__zoom button {
	width: 30px;
	height: 30px;
	padding: 0;
	font-size: 16px;
	line-height: 1;
}

/* The reset control is only meaningful once the view has actually moved. */
.tbt-world-map__zoom button[data-zoom="reset"] {
	display: none;
}

.tbt-world-map[data-zoomed="true"] .tbt-world-map__zoom button[data-zoom="reset"] {
	display: block;
}

.tbt-world-map__panel {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.25s ease;
}

.tbt-world-map__panel svg {
	width: 100%;
	height: 100%;
	display: block;
}

.tbt-world-map__panel--world {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
}

.tbt-world-map[data-view="continent"] .tbt-world-map__panel--world {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

.tbt-world-map[data-view="continent"] .tbt-world-map__panel--continent {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
}

.tbt-world-map__loading {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	color: var(--tbt-base-color);
	font-size: 14px;
	opacity: 0.8;
}

#background {
	fill: var(--tbt-ocean-color);
}

#aq {
	display: none;
}

.tbt-continent,
.tbt-country {
	fill: var(--tbt-base-color);
	cursor: pointer;
}

/*
 * Country borders. This rule is written twice over and neither half is
 * redundant -- until 1.11.7 it was one selector and it never applied at all.
 *
 * The class is repeated to raise specificity. Every map file carries its own
 * <style> block from the upstream source, including `.landxx { stroke-width:
 * 0.5 }` and `.coastxx { stroke-width: 0.2 }`. Inlining an SVG puts that block
 * in the body -- after this file -- so a single class ties on specificity and
 * loses on source order, and `stroke-width: 1` was silently discarded.
 *
 * The children are listed because `vector-effect` is *not* an inherited
 * property. A country is sometimes a bare <path> and sometimes a <g> of them
 * (the same split documented against getBBox in build-maps.ps1), and declaring
 * the effect on the <g> alone leaves every child path scaling its stroke with
 * the viewBox.
 *
 * Together those made the border on a <g> country 0.5 *user units*, which at
 * world-view scale (~0.25) is 0.12 CSS px -- no border. Hover then filled the
 * country with --tbt-hover-color, which sits at 1.3:1 against the default
 * ocean, and with no outline left to draw the coast the country appeared to
 * dissolve into the sea; zooming in scaled the stroke back into view, which is
 * why it "came back". Reported against Brazil, it affected every coastal <g>
 * country -- Australia, Greenland, the UK, Madagascar, Indonesia, Japan.
 *
 * `:not(text)` guards labels, matching the fill rules below. No label is
 * currently a descendant of a country, so it is defensive only.
 */
.tbt-continent.tbt-continent,
.tbt-continent *:not(text),
.tbt-country.tbt-country,
.tbt-country *:not(text) {
	stroke: var(--tbt-border-color);
	stroke-width: 1;
	/* The world viewBox is ~4x wider than a continent crop, so a scaled
	   stroke would render sub-pixel there. Keep borders 1px in every view. */
	vector-effect: non-scaling-stroke;
}

.tbt-continent.has-continent-fill,
.tbt-continent.has-continent-fill *:not(text) {
	fill: var(--tbt-country-color, var(--tbt-base-color));
}

.tbt-continent:hover,
.tbt-continent:hover *:not(text),
.tbt-country:hover,
.tbt-country:hover *:not(text) {
	fill: var(--tbt-hover-color);
}

/*
 * Hover outline (1.12.1). The fill swap above cannot carry the hover on its
 * own, because --tbt-hover-color is a single value being asked to stand out
 * against eight different backgrounds at once. Measured against the defaults it
 * only manages three of them: 1.29 against the ocean #1B5A82, 1.55 against
 * North America's fill, 1.76 against Europe's, 2.26 against South America's.
 *
 * A big compact country survives that -- Brazil hovers as a dark blob and you
 * still read the blob -- which is why 1.11.7's border fix looked like the end
 * of the "hover and it disappears" bug. The United States is not compact.
 * Florida, the Gulf and Atlantic seaboard, Cape Cod and the Great Lakes shore
 * are all thin geometry, and a 1px edge is enough to separate two land fills
 * but not enough to hold a 10px-wide peninsula against water of nearly the
 * same value. So the USA kept losing its coastline on hover after every other
 * country had stopped: same bug, but the border alone was never going to be
 * the whole fix for a country shaped like this one.
 *
 * Thickening the border rather than retuning the hover colour is the point.
 * The outline is palette-independent, so it fixes every site that already has
 * a hover colour saved -- and settings live in the database, so a better
 * default would only ever reach a fresh install, or someone who presses "Reset
 * colours to default" and gives up their whole palette to get it.
 *
 * Same doubled-selector shape as the border rule above, for the same two
 * reasons: the class is repeated so this beats .landxx and .coastxx from the
 * map file's own <style> block, and the children are listed because a <g>
 * paints nothing itself -- a country that is a group of paths needs the width
 * on the paths.
 */
.tbt-continent.tbt-continent:hover,
.tbt-continent:hover *:not(text),
.tbt-country.tbt-country:hover,
.tbt-country:hover *:not(text) {
	stroke-width: 2.5;
}

.tbt-continent.is-highlighted,
.tbt-continent.is-highlighted *:not(text),
.tbt-country.is-highlighted,
.tbt-country.is-highlighted *:not(text) {
	fill: var(--tbt-country-color, var(--tbt-highlight-color));
}

/*
 * Natural fill (1.12.0). A separate class rather than reusing
 * .has-continent-fill, because that one is only ever set by the world view --
 * terrain has to paint continent views too, where an ordinary country carries
 * no fill class at all and would otherwise stay on --tbt-base-color.
 *
 * Two classes deep so it beats .landxx from the map file's own stylesheet, and
 * declared after .has-continent-fill so it wins where both apply. Never set on
 * .is-highlighted, so a country the user coloured keeps its colour.
 */
.tbt-continent.has-terrain,
.tbt-continent.has-terrain *:not(text),
.tbt-country.has-terrain,
.tbt-country.has-terrain *:not(text) {
	fill: var(--tbt-country-color, var(--tbt-base-color));
}

.tbt-continent.is-inactive {
	pointer-events: none;
	opacity: 0.35;
}

/*
 * Country name labels. These sit directly on top of the country fill, so they
 * need their own colour rather than borrowing the border tint -- a hairline
 * colour that reads well as a border between two countries is often invisible
 * printed on top of one. Falls back to the border colour so settings saved
 * before this existed keep their old appearance.
 */
.tbt-map__label {
	fill: var(--tbt-label-color, var(--tbt-border-color));
	pointer-events: none;
}

.tbt-world-map__panel--world .tbt-map__label {
	display: none;
}

/*
 * Graticule (1.12.0): the faint lat/long grid that makes the ocean read as a
 * map rather than a coloured background. Built by map.js in the full
 * 2754x1398 space on every map, continent crops included, and simply clipped
 * by the viewBox -- which works only because the six continent files are crops
 * of that same space rather than reprojections.
 *
 * non-scaling-stroke for the same reason the borders need it: a scaled hairline
 * is sub-pixel at world zoom and a slab at country zoom.
 */
.tbt-graticule {
	pointer-events: none;
}

/*
 * Parallels are <line>s and meridians are <path>s, because this map's
 * meridians are curves rather than verticals -- see the projection note in
 * map.js. `fill: none` is doing real work on the path half: a meridian is an
 * open path, and an unfilled-by-default SVG path is filled black, so leaving
 * it out would paint eighteen black wedges across the ocean.
 */
.tbt-graticule line,
.tbt-graticule path {
	stroke: var(--tbt-graticule-color, transparent);
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
	fill: none;
}

/*
 * One strip for every back control, top-left.
 *
 * "Back to world" and "Back to continent" are both live at the third level --
 * framing a country leaves the view on data-view="continent" -- so positioning
 * each absolutely put one on top of the other. A flex strip lays them out
 * side by side and wraps them on a narrow map.
 *
 * pointer-events is the load-bearing part. This is a transparent box sitting
 * over the map, which is precisely what the old focus bar was, and that bar ate
 * every click on the countries underneath it (see the [hidden] note above).
 * The strip itself is inert and only its buttons take the pointer.
 */
.tbt-world-map__controls {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 3;
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: 8px;
	pointer-events: none;
}

.tbt-world-map__controls > *,
.tbt-world-map__focus > * {
	pointer-events: auto;
}

.tbt-world-map__back {
	padding: 6px 14px;
	font-size: 14px;
	display: none;
}

.tbt-world-map[data-view="continent"] .tbt-world-map__back {
	display: inline-block;
}

/*
 * A pin is a <g> of two circles: .tbt-pin__hit is the invisible tap target and
 * .tbt-pin__dot is the dot you see. The dot's size follows the width of the map
 * -- around 20px across on a desktop but only ~7px on a phone, which no finger
 * can hit, so taps were landing on the country underneath. map.js sizes the hit
 * circle; see MIN_PIN_HIT_PX there.
 */
.tbt-pin {
	cursor: pointer;
}

/*
 * pointer-events:all hit-tests an element whatever it paints. The default
 * (visiblePainted) would not hit an unfilled circle at all, and fill:transparent
 * is not treated consistently across engines.
 */
.tbt-pin__hit {
	fill: none;
	stroke: none;
	pointer-events: all;
}

/*
 * The ring is not decoration: a single pin colour cannot out-contrast six
 * continent fills at once (gold measures 1.98 against teal and 2.04 against
 * green), and the ring is what makes the dot legible against any of them, and
 * against the ocean. It was hardcoded white until 1.12.0; it is now themeable,
 * because white is wrong on a dark palette. Falls back to white so a saved
 * setting from before this existed looks exactly as it did.
 */
.tbt-pin__dot {
	fill: var(--tbt-pin-color);
	stroke: var(--tbt-pin-ring, #fff);
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
	transition: transform 0.15s ease;
	transform-box: fill-box;
	transform-origin: center;
}

/*
 * Hovering anywhere in the tap target grows the dot, so the pin acknowledges
 * the pointer from the same distance at which it will accept the click.
 */
.tbt-pin:hover .tbt-pin__dot {
	transform: scale(1.35);
}

.tbt-world-map__tooltip {
	position: absolute;
	pointer-events: none;
	background: rgba(0, 0, 0, 0.85);
	color: #fff;
	padding: 6px 10px;
	border-radius: 4px;
	font-size: 13px;
	line-height: 1.4;
	max-width: 220px;
	z-index: 3;
	display: none;
}

/* Shown briefly when someone scrolls the page over the map, so the zoom
   gesture is discoverable without hijacking the scroll to advertise it. */
.tbt-world-map__hint {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	font-size: 15px;
	pointer-events: none;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.2s ease;
	z-index: 4;
}

.tbt-world-map.show-zoom-hint .tbt-world-map__hint {
	opacity: 1;
	visibility: visible;
}

.is-linked {
	cursor: pointer;
}

/*
 * The third drill-down level (rewritten 1.13.0).
 *
 * This was a full-width bar across the bottom of the map holding the country
 * name, its link and a clear button. It is two buttons in the back strip now:
 * the bar was out of proportion with every other control, and the name it
 * carried was already printed on the country underneath it.
 *
 * The link is still an anchor rather than a scripted button, so it is keyboard
 * reachable and shows its destination in the status bar. It has to live
 * somewhere: clicking the country is what zooms, so with country_zoom on the
 * shape's own click is spoken for and this is the only route to the URL.
 */
.tbt-world-map__focus {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: 8px;
}

.tbt-world-map__focus-clear,
.tbt-world-map__focus-link {
	padding: 6px 14px;
	font-size: 14px;
}

.tbt-world-map__focus-link {
	text-decoration: none;
	display: inline-block;
}

/* ---- Text index: the accessible + indexable version of the map ---- */

.tbt-world-map__index {
	margin-top: 20px;
	font-size: 15px;
}

/*
 * Hidden from sight but not from assistive technology or crawlers. Not
 * display:none, which would remove it from both. It comes back on keyboard
 * focus so tabbing into it does not strand the visitor somewhere invisible.
 */
.tbt-world-map__index--offscreen {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.tbt-world-map__index--offscreen:focus-within {
	position: static;
	width: auto;
	height: auto;
	margin-top: 20px;
	overflow: visible;
	clip: auto;
	clip-path: none;
	white-space: normal;
}

.tbt-world-map__index-title {
	font-size: 1.1em;
	margin: 0 0 10px;
}

.tbt-world-map__index-group {
	margin-bottom: 14px;
}

.tbt-world-map__index-group h3 {
	font-size: 1em;
	margin: 0 0 4px;
	display: flex;
	align-items: baseline;
	gap: 10px;
	flex-wrap: wrap;
}

.tbt-world-map__index-view {
	background: none;
	border: none;
	padding: 0;
	font-size: 0.85em;
	font-weight: normal;
	color: var(--tbt-highlight-color);
	text-decoration: underline;
	cursor: pointer;
}

.tbt-world-map__index-group ul {
	margin: 0;
	padding-left: 1.2em;
}

.tbt-world-map__index-group li {
	margin-bottom: 2px;
}

.tbt-world-map__index-note {
	color: #666;
	font-size: 0.9em;
}

.tbt-world-map__index-note::before {
	content: " — ";
}

/* Visible keyboard focus, since the index is the keyboard path into the map. */
.tbt-world-map__index a:focus-visible,
.tbt-world-map__index button:focus-visible,
.tbt-world-map__zoom button:focus-visible,
.tbt-world-map__back:focus-visible {
	outline: 2px solid var(--tbt-highlight-color);
	outline-offset: 2px;
}

.tbt-world-map__error {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	color: var(--tbt-base-color);
}
