/**
 * Airport Transport Map — mobile-first.
 *
 * The map is a single `<svg>` that embeds the clean base raster as
 * `<image>` and then draws every marker + callout on top. Because the
 * viewBox is shared, cropping to mobile (via JS toggling `viewBox` at
 * ≤ 560 / 900 px widths) zooms BOTH the image and the markers as one.
 *
 * Legend is HTML below the map so it reflows + translates cleanly.
 *
 * Motion:
 *   - Pulse glow on quais hints at "live data here". `prefers-
 *     reduced-motion` disables the animation entirely.
 *
 * Touch targets stay ≥ 44 px via `.lux-map-hot__hit`, sized in SVG
 * units that end up > 44 CSS-px at the smallest supported frame width.
 */

.lux-airport-map {
	position: relative; /* popover anchor — JS positions relative to this */
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	margin: 1rem 0 1.5rem;
}

/* The map used to be `position: sticky` on desktop so the spatial
   answer stayed visible while scrolling the timetable below. In
   practice that never worked: a `overflow-x: hidden` rule on the
   theme's `#primary` ancestor implicitly turned it into a scroll
   container, which silently disabled sticky. Once we corrected
   that ancestor (`overflow-x: clip` in `style.css`), sticky DID
   start working — but the map at its natural ~700px height ate
   ~80% of the viewport, leaving the schedule body almost no room
   below the obstruction band. Rather than ship a sticky band that
   hides the actual answer the user came for, we drop sticky here
   and let the page scroll naturally. The schedule's own
   focus-line scroll (in `bus-schedules.js`) now lands cleanly
   below the site-header, with full body visibility. */

.lux-airport-map__frame {
	position: relative;
	/* Matches the exported raster (1024×486 isometric render). On
	   narrow viewports the viewBox zooms into the terminal area, but
	   the frame's own aspect stays 1024/486 so neighbouring blocks
	   reflow predictably. */
	aspect-ratio: 1024 / 486;
	background: #f2f4f7;
	border-radius: 12px;
	overflow: hidden;
	container-type: inline-size;
}

/* No raster base exported yet — paint a subtle grid so the frame
   reads as a schematic rather than a broken image. */
.lux-airport-map__frame[data-has-bg="no"] {
	background-color: #f2f4f7;
	background-image:
		linear-gradient(to right,  rgba(31, 111, 235, 0.08) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(31, 111, 235, 0.08) 1px, transparent 1px);
	background-size: 48px 48px;
}

.lux-airport-map__canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

/* On narrow viewports the terminal area zooms, and the cropped
   portrait aspect makes the map feel tall. Let the frame's aspect
   follow whichever crop JS picked, so the visible region fills the
   frame with no vertical letterboxing around the zoomed image. */
.lux-airport-map[data-crop="mobile"] .lux-airport-map__frame {
	aspect-ratio: 600 / 320;
}
.lux-airport-map[data-crop="tablet"] .lux-airport-map__frame {
	aspect-ratio: 944 / 420;
}

/* ---------- Ground zones ----------------------------------- */

/* Soft coloured patches painted on the ground under each static
   pin so the extent of each zone (private coaches, taxi, shuttle,
   …) reads at a glance. Uses the same palette as the pin circle
   above, at low opacity so the underlying raster still shows. */
/* Zone rectangles are filled with a `<pattern>` (solid colour +
   diagonal white stripes) rather than a flat colour, so each patch
   reads as hatched paint on the pavement. `opacity` controls the
   whole element — pattern included — which is simpler than trying
   to tint the pattern children individually. The pin colour is
   also exposed as `color` so the border stroke can inherit via
   `currentColor` without hard-coding each swatch twice. */
.lux-airport-map__zone {
	opacity: 0.55;
	stroke: currentColor;
	stroke-opacity: 0.9;
	stroke-width: 1.4;
	pointer-events: none;
	transition: opacity 160ms ease;
}
.lux-airport-map.is-legend-focus .lux-airport-map__zone { opacity: 0.18; }
.lux-airport-map.is-legend-focus .lux-airport-map__zone[data-zone].is-focus {
	opacity: 1;
	stroke-width: 2;
	animation: lux-map-zone-flash 900ms ease-out 1;
}
/* Animate opacity only — the zone rect carries its own
   `transform="rotate(...)"` from SSR, so any keyframe transform here
   would clobber the rotation and make the patch jump on click. */
@keyframes lux-map-zone-flash {
	0%   { opacity: 0.35; }
	40%  { opacity: 1;    }
	100% { opacity: 1;    }
}
@media (prefers-reduced-motion: reduce) {
	.lux-airport-map.is-legend-focus .lux-airport-map__zone[data-zone].is-focus {
		animation: none;
	}
}

/* ---------- Callouts (map-internal labels) ----------------- */

.lux-map-callout {
	fill: #4a525e;
	font: 700 11px/1 var(--arhs-font, sans-serif);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	pointer-events: none;
	user-select: none;
}

/* ---------- Pin markers (quais + static pins) ------------- */

.lux-map-hot {
	cursor: pointer;
	outline: none;
}

/* Teardrop tail that anchors the pin to the map. Rendered just
   below the marker so the visible pin reads as a proper
   Google-Maps-style pin whose tip sits on the exact coordinate.
   Uses the same colored fill as the marker (applied inline) +
   a shared stroke/shadow for crispness on the busy base map. */
.lux-map-hot__tail {
	stroke: #ffffff;
	stroke-width: 1.5;
	filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.25));
	transition: transform 160ms ease;
	transform-origin: center top;
	transform-box: fill-box;
}
.lux-map-hot:hover .lux-map-hot__tail,
.lux-map-hot:focus-visible .lux-map-hot__tail,
.lux-map-hot--active .lux-map-hot__tail {
	transform: scale(1.12);
}

/* Glossy pin badge. No stroke by default — the pulse ring handles
   the "live" hint on quais, and the coloured fill already reads
   against the desaturated base map. */
.lux-map-hot__marker {
	stroke: #ffffff;
	stroke-width: 2.5;
	filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.25));
	transition: transform 160ms ease;
	transform-origin: center;
	transform-box: fill-box;
}
.lux-map-hot:hover .lux-map-hot__marker,
.lux-map-hot:focus-visible .lux-map-hot__marker,
.lux-map-hot--active .lux-map-hot__marker {
	transform: scale(1.12);
}

.lux-map-hot__glyph {
	fill: #ffffff;
	font: 700 14px/1 var(--arhs-font, sans-serif);
	pointer-events: none;
	user-select: none;
}
.lux-map-hot__glyph--quai {
	font-size: 14px;
	letter-spacing: 0.01em;
}

.lux-map-hot__marker--bus {
	stroke-width: 2;
}

/* Mode icon centred inside the marker (tram, taxi, shuttle …).
   Kept non-interactive so the surrounding hit target still catches
   the tap cleanly. */
.lux-map-hot__icon {
	pointer-events: none;
}

/* Wiggle — applied by JS to every pin that matches a
   hovered/focused legend row. Purely decorative; purpose is to
   guide the eye from the legend to the pin on the map. */
@keyframes lux-map-wiggle {
	0%, 100% { transform: translate(0, 0) rotate(0); }
	25%      { transform: translate(0, -1.5px) rotate(-4deg); }
	50%      { transform: translate(0, 0) rotate(0); }
	75%      { transform: translate(0, -1.5px) rotate(4deg); }
}
/* Mirror of `lux-map-wiggle` for pins whose circle hangs BELOW the
   anchor (`data-direction="down"`): the tail points UP, so the pivot
   belongs at the top of the pin and the nudge should go downward —
   otherwise the pin visually detaches from its anchor on every tick. */
@keyframes lux-map-wiggle-down {
	0%, 100% { transform: translate(0, 0) rotate(0); }
	25%      { transform: translate(0, 1.5px) rotate(-4deg); }
	50%      { transform: translate(0, 0) rotate(0); }
	75%      { transform: translate(0, 1.5px) rotate(4deg); }
}
.lux-map-hot.is-wiggle {
	animation: lux-map-wiggle 520ms ease-in-out 2;
	transform-origin: center bottom;
	transform-box: fill-box;
}
.lux-map-hot[data-direction="down"].is-wiggle {
	animation-name: lux-map-wiggle-down;
	transform-origin: center top;
}
@media (prefers-reduced-motion: reduce) {
	.lux-map-hot.is-wiggle { animation: none; }
}

/* Invisible hit target — absorbs the tap/click so small pins remain
   ≥ 44 CSS-pixels regardless of the frame's displayed size. */
.lux-map-hot__hit {
	fill: transparent;
}
.lux-map-hot__hit--bus {
	rx: 8;
	ry: 8;
}
.lux-map-hot:focus-visible .lux-map-hot__hit {
	stroke: #1f6feb;
	stroke-width: 3;
}
.lux-map-hot--active .lux-map-hot__hit {
	stroke: #1f1f1f;
	stroke-width: 3;
}

/* Cross-widget focus: the schedule emits `lbs:focusLine` whenever a
   line is opened (or a popover pill is tapped). We highlight every quai
   pin that serves that line so the user immediately spots where to
   board. The wiggle animation gives the same hint a beat earlier; this
   class persists the visual cue afterwards. */
.lux-map-hot--focus .lux-map-hot__marker {
	stroke: #1f6feb;
	stroke-width: 3.2;
	transform: scale(1.15);
}
.lux-map-hot--focus .lux-map-hot__pulse {
	fill: #1f6feb;
	fill-opacity: 0.35;
}

/* Live-severity pulse ring under each HAFAS-backed pin. Tinted by
   `data-severity` to mirror the widget's chip-dot palette. Ring
   sits behind the marker at low opacity so the pin stays readable. */
.lux-map-hot__pulse {
	fill: #1f6feb;
	fill-opacity: 0;
	transform-origin: center;
	transform-box: fill-box;
}
.lux-map-hot--quai[data-severity]:not([data-severity=""]) .lux-map-hot__pulse {
	fill-opacity: 0.22;
	animation: lux-map-pulse 2.2s ease-in-out infinite;
}
.lux-map-hot--quai[data-severity="green"]   .lux-map-hot__pulse { fill: #2da44e; }
.lux-map-hot--quai[data-severity="amber"]   .lux-map-hot__pulse { fill: #f4a100; }
.lux-map-hot--quai[data-severity="red"]     .lux-map-hot__pulse { fill: #c8102e; }
.lux-map-hot--quai[data-severity="neutral"] .lux-map-hot__pulse {
	fill: #6a737d;
	animation: none;
	fill-opacity: 0.15;
}

@keyframes lux-map-pulse {
	0%, 100% { transform: scale(0.85); opacity: 0.55; }
	50%      { transform: scale(1.30); opacity: 0.20; }
}

/* ---------- Legend ----------------------------------------- */

.lux-airport-map__legend {
	list-style: none;
	margin: 0;
	padding: 0.65rem;
	display: grid;
	grid-template-columns: 1fr;
	gap: 0.55rem;
	background: #f5f7fa;
	border-radius: 10px;
	font-size: 0.85rem;
	line-height: 1.3;
}
@media (min-width: 640px) {
	.lux-airport-map__legend {
		grid-template-columns: repeat(3, 1fr);
	}
}
.lux-airport-map__legend-group {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	min-width: 0;
	padding: 0.55rem;
	background: rgba(255, 255, 255, 0.82);
	border: 1px solid rgba(208, 215, 222, 0.9);
	border-radius: 9px;
	box-shadow: 0 1px 2px rgba(31, 35, 40, 0.04);
}
.lux-airport-map__legend-group-title {
	color: #57606a;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
}
.lux-airport-map__legend-group-desc {
	margin: -0.1rem 0 0.1rem;
	color: #57606a;
	font-size: 0.78rem;
	line-height: 1.35;
}
.lux-airport-map__legend-items {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem;
}
.lux-airport-map__legend-item {
	display: flex;
	align-items: center;
	max-width: 100%;
	min-width: 0;
}
/* Legend row button — interactive so hover/focus triggers a wiggle
   on the matching map pin (see `is-wiggle` above). Button styles
   are reset to stay visually flush with the surrounding list. */
.lux-airport-map__legend-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	max-width: 100%;
	min-width: 0;
	margin: 0;
	padding: 0.25rem 0.45rem 0.25rem 0.3rem;
	background: #f8fafc;
	border: 1px solid #d8dee4;
	border-radius: 999px;
	color: inherit;
	font: inherit;
	text-align: left;
	cursor: pointer;
	transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.lux-airport-map__legend-btn:hover,
.lux-airport-map__legend-btn:focus-visible {
	background: #ffffff;
	border-color: rgba(31, 111, 235, 0.35);
	box-shadow: 0 0 0 2px rgba(31, 111, 235, 0.08);
	outline: none;
}
.lux-airport-map__legend-swatch {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	box-shadow: 0 0 0 1.5px #fff, 0 1px 1.5px rgba(0, 0, 0, 0.2);
}
.lux-airport-map__legend-icon {
	display: block;
	width: 12px;
	height: 12px;
}
/* Per-quai swatch: number replaces the mode icon. Inherits fg color
   from the inline `style="color"` set in SSR so the glyph matches
   the SVG pin's `<text>` exactly. */
.lux-airport-map__legend-glyph {
	display: block;
	font-size: 11px;
	font-weight: 700;
	line-height: 1;
	color: inherit;
}
.lux-airport-map__legend-label {
	color: #1f1f1f;
	min-width: 0;
	overflow-wrap: anywhere;
	white-space: normal;
}

/* ---------- Popover ---------------------------------------- */

.lux-airport-map__popover {
	position: absolute;
	transform: translate(-50%, 8px);
	min-width: min(14rem, 100%);
	max-width: min(20rem, calc(100% - 16px));
	padding: 0.6rem 0.75rem;
	background: #fff;
	border-radius: 8px;
	box-shadow: 0 4px 18px rgba(0, 0, 0, 0.18);
	z-index: 3;
}
.lux-airport-map__popover[hidden] { display: none; }

/* Tiny × button anchored to the top-right of the popover. Pure
   affordance for touch users; outside-click + Esc close too. The
   popover bodies (`__popover-pin` / `__popover-quai`) reserve right
   padding so the title never collides with the button. */
.lux-airport-map__popover-close {
	position: absolute;
	top: 4px;
	right: 4px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.5rem;
	height: 1.5rem;
	padding: 0;
	margin: 0;
	background: transparent;
	border: 0;
	border-radius: 999px;
	color: #57606a;
	font-size: 1.1rem;
	line-height: 1;
	cursor: pointer;
	transition: background 140ms ease, color 140ms ease;
}
.lux-airport-map__popover-close:hover,
.lux-airport-map__popover-close:focus-visible {
	background: rgba(31, 111, 235, 0.12);
	color: #1f2544;
	outline: none;
}
.lux-airport-map__popover-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
}
.lux-airport-map__popover-row {
	display: grid;
	grid-template-columns: 10px 1fr auto;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.9rem;
}
.lux-airport-map__popover-dot {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: #6a737d;
}
.lux-airport-map__popover-row[data-live="green"]   .lux-airport-map__popover-dot { background: #2da44e; }
.lux-airport-map__popover-row[data-live="amber"]   .lux-airport-map__popover-dot { background: #f4a100; }
.lux-airport-map__popover-row[data-live="red"]     .lux-airport-map__popover-dot { background: #c8102e; }
.lux-airport-map__popover-row[data-live="neutral"] .lux-airport-map__popover-dot { background: #c5cbd3; }

/* "Live times unavailable" header shown when we only have structural
   info (bus-lines-config.php) and no `/week` payload. */
.lux-airport-map__popover-offline {
	font-size: 0.78rem;
	font-weight: 600;
	color: #6a737d;
	margin: 0 0 0.4rem;
	padding-bottom: 0.35rem;
	border-bottom: 1px dashed #d0d7de;
}

/* Minimal popover body for non-HAFAS pins (private coaches, taxi, etc.). */
.lux-airport-map__popover-pin {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	padding-right: 1.5rem;
	font-size: 0.88rem;
	line-height: 1.35;
	color: #1f1f1f;
	outline: none;
}
.lux-airport-map__popover-pin strong { font-weight: 600; }
.lux-airport-map__popover-desc {
	margin: 0;
	color: #4a525e;
}
.lux-airport-map__popover-link {
	align-self: flex-start;
	font-size: 0.8rem;
	font-weight: 600;
	color: #1f6feb;
	text-decoration: none;
}
.lux-airport-map__popover-link:hover,
.lux-airport-map__popover-link:focus-visible {
	text-decoration: underline;
}

/* ----- Slim quai popover -----------------------------------------
   Replaces the old 5-departures dump. The popover now answers ONLY the
   spatial question: "which lines leave from this quai, and how do I
   jump to their full timings?" Live times remain the schedule
   widget's job. */
.lux-airport-map__popover-quai {
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
	padding-right: 1.5rem;
	font-size: 0.88rem;
	line-height: 1.35;
	color: #1f1f1f;
	outline: none;
}
.lux-airport-map__popover-quai-title {
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #57606a;
}
/* Lines list — one row per line that boards from THIS quai. We use a
   stacked list (not a chip cloud) so the destination label can read
   in full ("Bus 850 → Walferdange-Bertrange") without truncation. */
.lux-airport-map__popover-lines {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
}
.lux-airport-map__popover-line {
	display: flex;
	align-items: baseline;
	width: 100%;
	min-height: 30px;
	margin: 0;
	padding: 0.3rem 0.55rem;
	background: #f1f5fa;
	border: 1px solid #cdd6e0;
	border-radius: 8px;
	color: #1f2544;
	font: inherit;
	font-size: 0.82rem;
	text-align: left;
	cursor: pointer;
	transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}
.lux-airport-map__popover-line:hover,
.lux-airport-map__popover-line:focus-visible {
	background: #1f6feb;
	border-color: #1f6feb;
	color: #ffffff;
	outline: none;
}
.lux-airport-map__popover-line-label {
	font-weight: 700;
	white-space: nowrap;
}
.lux-airport-map__popover-line-dest {
	margin-left: 0.3rem;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: inherit;
	opacity: 0.85;
}
.lux-airport-map__popover-cta {
	align-self: flex-start;
	margin: 0;
	padding: 0.25rem 0;
	background: transparent;
	border: 0;
	color: #1f6feb;
	font: inherit;
	font-size: 0.82rem;
	font-weight: 700;
	cursor: pointer;
	text-decoration: none;
}
.lux-airport-map__popover-cta:hover,
.lux-airport-map__popover-cta:focus-visible {
	text-decoration: underline;
	outline: none;
}

@container (max-width: 560px) {
	.lux-airport-map__popover { min-width: 12rem; }
	.lux-map-callout { font-size: 10px; }
}

@media (prefers-reduced-motion: reduce) {
	.lux-map-hot__pulse { animation: none; }
	.lux-map-hot__marker { transition: none; }
}
