/*
 * ERD Directory — component styles (base spec §10). Hand-written, no build step.
 * Theming is via custom properties only (§10.1); never document selector overrides.
 * Map / pin / cluster / loader rules are appended in Stage B3.
 */

/* -------------------------------------------------------------------------
 * Tokens (§10.3). Declared on .erd. Typography inherits the host theme.
 * ------------------------------------------------------------------------- */
.erd {
	/* Palette */
	--erd-ink: #0e2332;
	--erd-ink-muted: #5b6b78;
	--erd-surface: #ffffff;
	--erd-surface-muted: #f3f5f7;
	--erd-border: #dce3e9;
	--erd-chip-solid-bg: #0e2332;
	--erd-chip-solid-ink: #ffffff;
	--erd-chip-muted-bg: #eef1f4;
	--erd-chip-muted-ink: #0e2332;
	--erd-accent: #ff6422;
	--erd-focus: #1a73e8;

	/* Geometry */
	--erd-gap: 1rem;
	--erd-radius: 6px;
	--erd-radius-pill: 999px;
	--erd-pad: 1.25rem;
	--erd-media-ratio: 16 / 10;
	--erd-section-max: 1280px;
	--erd-section-pad: 2rem;

	/* Type */
	--erd-font: inherit;
	--erd-size-title: 1.125rem;
	--erd-size-body: 1rem;
	--erd-size-small: 0.8125rem;

	/* Map (addendum A4.4) */
	--erd-map-pin: #071927;
	--erd-map-pin-ink: #ffffff;
	--erd-map-pin-active: #ff6422;
	--erd-map-pin-size: 28px;
	--erd-map-pin-size-active: 36px;
	--erd-map-height: 500px;
	--erd-map-loader-bg: none; /* set inline per-instance from the section template */

	/* How far below the top of the viewport the cards land when JS scrolls to
	   them. Sized for a sticky host header; raise it if the theme's is taller. */
	--erd-scroll-offset: 5rem;

	/* Overlay stacking. Both overlays are portaled to <body>, so these compete in
	   the ROOT stacking context — against the host theme's sticky header and
	   against third-party widgets, which park themselves in the low billions
	   (tawk.to uses 2000000000). z-index is a 32-bit integer, so 2147483647 is
	   the real ceiling and any higher number a stylesheet asks for is clamped to
	   it — a hand-written 9999999999 IS this value. Take the ceiling and stop
	   guessing whether the next widget outbids us. The post list sits on the top
	   step because it opens from the map and must cover it.

	   To override, set the token, not the rule: the component's own `z-index`
	   declarations are specificity-boosted (§10.1) and will beat a plain
	   `.erd-modal { z-index: … }` in Additional CSS. This works:
	       .erd-modal { --erd-z-modal: 500; } */
	--erd-z-map: 2147483646;
	--erd-z-modal: 2147483647;
}

/* -------------------------------------------------------------------------
 * Reset (§10.2). Zero-specificity via :where() so the host theme keeps
 * control where it legitimately has it; component rules still land.
 * ------------------------------------------------------------------------- */
:where(.erd),
:where(.erd) * {
	box-sizing: border-box;
}
:where(.erd) h2,
:where(.erd) h3,
:where(.erd) p,
:where(.erd) ul,
:where(.erd) figure {
	margin: 0;
	padding: 0;
}
:where(.erd) ul {
	list-style: none;
}
:where(.erd) img {
	max-width: 100%;
	height: auto;
	display: block;
}
:where(.erd) button {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	cursor: pointer;
}
:where(.erd) a {
	color: inherit;
}

/* -------------------------------------------------------------------------
 * Specificity boost (§10.1). Every component rule below is nested inside a
 * wrapper worth two ID selectors, so each one lands at (2,x,0): enough to beat
 * unlayered host CSS like WooCommerce's `.woocommerce-js button.button` (0,2,1)
 * or an Astra child's `#main button:hover` (1,2,1) WITHOUT `!important`.
 *
 * `html` is the real match target — an id can't be used in the markup because a
 * page may hold two directory sections and ids must stay unique (§9.1). The
 * `#erd-directory#erd-directory` arm never matches anything; it exists only to
 * set `:is()`'s specificity, which is that of its most specific argument.
 *
 * The boost is UNIFORM, so every relationship between our own rules is
 * unchanged — read the nested selectors as if the wrapper weren't there.
 * Deliberately left outside: the token custom properties (so a site can still
 * override them per §10.1) and the `:where()` reset (zero-specificity by
 * design, §10.2).
 * ------------------------------------------------------------------------- */
:is(#erd-directory#erd-directory, html) {
	& .erd {
		font-family: var(--erd-font);
		color: var(--erd-ink);
		container: erd-root / inline-size;

		/* Contain + pad the whole section (box-sizing:border-box from the reset). */
		max-width: var(--erd-section-max);
		margin-left: auto;
		margin-right: auto;
		padding: var(--erd-section-pad);
	}

	/* Neutralize two known host-theme leaks (Astra confirmed) at normal specificity. */
	& .erd button {
		border-bottom: 0;
	}
	& .erd p {
		margin-bottom: 0;
	}

	/* -------------------------------------------------------------------------
	 * Header + filters.
	 * ------------------------------------------------------------------------- */
	& .erd__header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--erd-gap);
		margin-bottom: calc(var(--erd-gap) * 1.5);
		flex-wrap: wrap;
	}
	/* Scoped with .erd (0,2,0) so the theme's `.entry-content h2` (0,1,1) can't
	   re-margin it and break vertical alignment with the Back pill. */
	& .erd .erd__heading {
		font-size: 1.5rem;
		font-weight: 700;
		line-height: 1.3;
		margin: 0;
	}
	& .erd__filters {
		display: flex;
		gap: 0.5rem;
		flex-wrap: wrap;
	}

	/* Header left cluster: Back pill (shown while drilled) + heading. */
	& .erd__header-left {
		display: flex;
		align-items: center;
		gap: 1rem;
		min-width: 0;
	}
	/* .erd-scoped (0,2,0) so the border-bottom neutralizer can't strip the pill. */
	& .erd .erd__back {
		display: inline-flex;
		align-items: center;
		gap: 0.375rem;
		min-height: 40px;
		padding: 0.5rem 1rem;
		border: 1px solid var(--erd-border);
		border-radius: var(--erd-radius-pill);
		font-weight: 600;
		white-space: nowrap;
	}
	& .erd__back[hidden] {
		display: none;
	}
	& .erd__back-arrow {
		width: 0.5rem;
		height: 0.5rem;
		border-left: 2px solid currentColor;
		border-bottom: 2px solid currentColor;
		transform: rotate(45deg);
	}

	& .erd-filter {
		position: relative;
	}
	/* .erd-scoped (0,2,0) so the `.erd button { border-bottom: 0 }` host-leak
	   neutralizer (0,1,1) can't strip this button's bottom border. */
	& .erd .erd-filter__toggle {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		min-height: 44px;
		padding: 0.5rem 1rem;
		border: 1px solid var(--erd-border);
		border-radius: var(--erd-radius);
		background: var(--erd-surface);
	}
	& .erd-filter__caret {
		width: 0.5rem;
		height: 0.5rem;
		border-right: 2px solid currentColor;
		border-bottom: 2px solid currentColor;
		transform: rotate(45deg);
		margin-top: -0.25rem;
		transition: transform 0.2s ease;
	}
	& .erd-filter__toggle[aria-expanded="true"] .erd-filter__caret {
		transform: rotate(-135deg);
		margin-top: 0.125rem;
	}
	& .erd-filter__panel {
		position: absolute;
		z-index: 20;
		top: calc(100% + 0.25rem);
		left: 0;
		min-width: 220px;
		max-width: 90vw;
		padding: 0.75rem;
		background: var(--erd-surface);
		border: 1px solid var(--erd-border);
		border-radius: var(--erd-radius);
		box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
	}
	& .erd-filter__panel[hidden] {
		display: none;
	}
	/* Explicit background/padding/radius here even though this is already inside
	   the ID-grade boost (§10.1): specificity only wins a property this rule
	   actually declares. Leaving them undeclared let the host theme's bare
	   `button { padding: 15px 30px; background-color: … }` (Astra's Additional
	   CSS) fill the gap unopposed — a real button-shaped CTA where the design
	   wants a plain text link. */
	& .erd-filter__clear {
		display: inline-block;
		font-size: var(--erd-size-small);
		font-weight: 600;
		color: var(--erd-accent);
		margin-bottom: 0.5rem;
		padding: 0.25rem 0.5rem;
		background: transparent;
		border-radius: var(--erd-radius);
	}
	& .erd-filter__group {
		border: 0;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
	}
	& .erd-filter__option-label {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		min-height: 36px;
		cursor: pointer;
	}

	/* -------------------------------------------------------------------------
	 * Carousel container = the cards region. Container queries key off ITS width,
	 * not the viewport (§10.4 / A7), so a narrow column steps columns down even
	 * when the viewport is wide.
	 * ------------------------------------------------------------------------- */
	& .erd__carousel {
		container: erd-cards / inline-size;
		position: relative;
		/* The cards are the scroll target when JS brings them back into view
		   (a filter change, the mobile map closing). Keep the first row clear of
		   whatever the host theme sticks to the top of the viewport. */
		scroll-margin-top: var(--erd-scroll-offset);
	}
	& .erd__track {
		overflow: hidden;
	}

	/* Pre-hydration / no-JS / no-Splide: grid (§10.5). No layout shift on hydrate. */
	& .erd__list {
		display: grid;
		grid-template-columns: repeat(1, 1fr);
		gap: var(--erd-gap);
		transition: opacity 0.18s ease;
	}
	/* Brief dim while filtering — signals the change, masks the Splide reflow. */
	& .erd--filtering .erd__list {
		opacity: 0.35;
	}
	@container erd-root (min-width: 560px) {
		& .erd__list {
			grid-template-columns: repeat(2, 1fr);
		}
	}
	@container erd-root (min-width: 900px) {
		& .erd__list {
			grid-template-columns: repeat(var(--erd-columns, 3), 1fr);
		}
	}

	/* Only when a Splide carousel is actually mounted does the track become a flex
	   row. Absent Splide (trap 1) the grid stays; filtering still works. `gap: 0`
	   because Splide owns the inter-slide spacing (margins) — the grid's flex gap
	   would otherwise double it and overflow/clip the last card. */
	& .erd.erd--splide .erd__list {
		display: flex;
		gap: 0;
		align-items: stretch; /* equal-height cards regardless of content length. */
	}

	/* Arrows are useless without a carousel — hide unless Splide is mounted. */
	& .erd:not(.erd--splide) .erd__arrows {
		display: none;
	}

	/* Splide's stylesheet hides every `.splide` root (`visibility: hidden`) until
	   its JS adds `is-initialized` — an anti-FOUC guard that assumes the script
	   always arrives. The grid fallback (trap 1) is a legitimate no-Splide render,
	   so when the script is missing/blocked/deferred nothing ever reveals the
	   carousel: cards AND footer occupy their space and paint nothing. Reveal it
	   ourselves — .erd-scoped (0,2,0) beats Splide's `.splide` (0,1,0), and when
	   Splide does mount its own `visibility: visible` agrees with us. */
	& .erd .erd__carousel {
		visibility: visible;
	}

	/* -------------------------------------------------------------------------
	 * Card (§10.6): white card, hairline border, ~16:10 media, solid pill chips
	 * top-left over the image, muted pin pill in the body, underlined link.
	 * ------------------------------------------------------------------------- */
	& .erd-card {
		background: var(--erd-surface);
		border: 1px solid var(--erd-border);
		border-radius: var(--erd-radius);
		overflow: hidden;
		display: flex;
		flex-direction: column;
		/* No explicit height — the slide/cell's `align-items: stretch` equalizes
		   heights, and .erd-card__body{flex:1} pushes the chip to the bottom.
		   An explicit height would opt the card out of stretch. */
	}
	& .erd-card__media {
		position: relative;
		aspect-ratio: var(--erd-media-ratio);
		overflow: hidden;
		background: var(--erd-surface-muted);
	}
	/* Hard height fallback for engines without aspect-ratio: reserve 10/16. */
	@supports not (aspect-ratio: 1 / 1) {
		& .erd-card__media {
			height: 0;
			padding-top: 62.5%;
		}
	}
	& .erd-card__media img {
		position: absolute;
		inset: 0;
		width: 100%;
		height: 100%;
		object-fit: cover;
	}
	& .erd-card__chips {
		display: flex;
		flex-wrap: wrap;
		gap: 0.375rem;
	}
	& .erd-card__chips--over {
		position: absolute;
		top: 0.75rem;
		left: 0.75rem;
		max-width: calc(100% - 1.5rem);
	}
	& .erd-card__chip {
		display: inline-flex;
		align-items: center;
		gap: 0.25rem;
		padding: 0.25rem 0.625rem;
		border-radius: var(--erd-radius-pill);
		font-size: var(--erd-size-small);
		font-weight: 600;
		line-height: 1.2;
		text-decoration: none;
	}
	& .erd-card__chip--service {
		background: var(--erd-chip-solid-bg);
		color: var(--erd-chip-solid-ink);
	}
	& .erd-card__chip--location {
		background: var(--erd-chip-muted-bg);
		color: var(--erd-chip-muted-ink);
	}
	/* Kill the host theme's link underline on chips. The boost already out-specifies
	   selectors like `.ast-single-post .entry-content a`; !important stays only for
	   themes that declare their link underline !important (Astra confirmed). */
	& .erd .erd-card__chip,
	& .erd .erd-card__chip span {
		text-decoration: none !important;
	}
	& .erd-card__chip .erd-icon--pin {
		width: 0.875rem;
		height: 0.875rem;
	}
	& .erd-card__body {
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
		padding: var(--erd-pad);
		flex: 1 1 auto;
	}
	& .erd-card__title {
		font-size: var(--erd-size-title);
		font-weight: 700;
		line-height: 1.3;
	}
	& .erd-card__excerpt {
		font-size: var(--erd-size-body);
		color: var(--erd-ink-muted);
		line-height: 1.5;
	}
	& .erd-card__chips--body {
		margin-top: auto;
	}
	& .erd-card__link {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		min-height: 44px;
		font-weight: 600;
		text-decoration: underline;
		text-underline-offset: 3px;
		width: fit-content;
	}
	& .erd-card__link .erd-icon,
	& .erd__view-all .erd-icon {
		transition: transform 0.2s ease;
	}
	& .erd-card__link:hover .erd-icon,
	& .erd__view-all:hover .erd-icon {
		transform: translateX(4px);
	}

	/* -------------------------------------------------------------------------
	 * Icons.
	 * ------------------------------------------------------------------------- */
	& .erd-icon {
		width: 1rem;
		height: 1rem;
		flex: 0 0 auto;
	}
	& .erd-icon--prev {
		transform: scaleX(-1);
	}

	/* -------------------------------------------------------------------------
	 * Footer: count bottom-left, view-all, 45px black circular arrows bottom-right.
	 * ------------------------------------------------------------------------- */
	& .erd__empty {
		padding: 2rem 0;
		color: var(--erd-ink-muted);
	}
	& .erd__empty[hidden] {
		display: none;
	}
	/* Footer: count left, view-all centered, arrows right (design). */
	& .erd__footer {
		display: flex;
		align-items: center;
		gap: var(--erd-gap);
		margin-top: var(--erd-gap);
		position: relative;
	}
	& .erd__count {
		flex: 1 1 0;
		font-size: var(--erd-size-small);
		color: var(--erd-ink-muted);
	}
	& .erd__view-all {
		flex: 0 0 auto;
		margin: 0 auto;
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		min-height: 44px;
		font-weight: 600;
		color: var(--erd-accent);
		text-decoration: none;
	}
	& .erd__arrows {
		flex: 1 1 0;
		display: flex;
		gap: 0.5rem;
		justify-content: flex-end;
	}

	/* Reset Splide's absolute arrow positioning (trap 3): our CSS loads after
	   splide.min.css (declared dependency) so these win, returning the arrows to
	   the footer flow. */
	& .erd .splide__arrow {
		position: static;
		top: auto;
		left: auto;
		right: auto;
		transform: none;
		width: 45px;
		height: 45px;
		border-radius: 50%;
		background: #000000;
		color: #ffffff;
		opacity: 1;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}
	& .erd .splide__arrow svg {
		width: 1.1rem;
		height: 1.1rem;
	}
	& .erd .splide__arrow:disabled {
		opacity: 0.35;
		cursor: default;
	}
	& .erd--no-arrows .erd__arrows {
		display: none;
	}

	/* -------------------------------------------------------------------------
	 * Accessibility (§12).
	 * ------------------------------------------------------------------------- */
	& .erd .screen-reader-text {
		position: absolute !important;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
		border: 0;
	}
	& .erd :focus-visible {
		outline: 2px solid var(--erd-focus);
		outline-offset: 2px;
	}

	/* -------------------------------------------------------------------------
	 * Hover states — self-contained, so the component never inherits the host
	 * theme's button/link hovers. The boost puts these at (2,3,0), past anything a
	 * theme can write with plain selectors. Transitions are neutralized under
	 * prefers-reduced-motion below.
	 * ------------------------------------------------------------------------- */
	& .erd .erd-filter__toggle,
	& .erd .erd__back,
	& .erd .erd-filter__clear,
	& .erd .erd-filter__option-label,
	& .erd .erd-card__chip,
	& .erd .splide__arrow,
	& .erd .erd__map-toggle,
	& .erd .erd__map-close {
		transition: background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
	}
	/* !important retained for themes that hover buttons with !important of their
	   own; the boost handles the plain ID-rule case (e.g. `#main button:hover`). */
	& .erd .erd-filter__toggle:hover,
	& .erd .erd__back:hover,
	& .erd .erd__map-close:hover {
		background: var(--erd-surface-muted) !important;
		border-color: var(--erd-ink-muted) !important;
		color: var(--erd-ink) !important;
	}
	& .erd .erd-filter__option-label:hover {
		background: var(--erd-surface-muted);
		border-radius: var(--erd-radius);
	}
	& .erd .erd-filter__clear:hover,
	& .erd .erd-filter__clear:active {
		background: var(--erd-surface-muted) !important;
		color: var(--erd-accent) !important;
		text-decoration: underline;
	}
	& .erd .erd-card__chip:hover {
		opacity: 0.85;
	}
	/* Lock chip text colours on hover — theme `a:hover { color }` would otherwise
	   recolour them (invisible white-on-dark on the service chip). */
	& .erd .erd-card__chip--service:hover {
		color: var(--erd-chip-solid-ink);
	}
	& .erd .erd-card__chip--location:hover {
		color: var(--erd-chip-muted-ink);
	}
	& .erd .splide__arrow:hover:not(:disabled) {
		background: #333333 !important;
		color: #ffffff !important;
	}
	& .erd .erd__map-toggle:hover {
		opacity: 0.9;
		color: #ffffff !important;
	}

	/* -------------------------------------------------------------------------
	 * Responsive: stack header/footer under a narrow container (§10.4).
	 * ------------------------------------------------------------------------- */
	@container erd-root (max-width: 560px) {
		& .erd__header {
			flex-direction: column;
			align-items: stretch;
		}
		& .erd__filters {
			width: 100%;
		}
	}
	@container erd-cards (max-width: 560px) {
		/* Mobile footer: count + arrows on row 1, view-all centered on row 2. */
		& .erd__footer {
			flex-wrap: wrap;
			gap: 0.5rem;
		}
		& .erd__count {
			flex: 1 1 auto;
			order: 1;
		}
		& .erd__arrows {
			flex: 0 0 auto;
			order: 2;
		}
		& .erd__view-all {
			order: 3;
			flex: 0 0 100%;
			justify-content: center;
			margin: 0.75rem auto 0;
		}
	}

	@media (prefers-reduced-motion: reduce) {
		& .erd * {
			transition: none !important;
		}
	}

	/* -------------------------------------------------------------------------
	 * Map (addendum A2/A4). Rendered only when map is on and a key is present.
	 * ------------------------------------------------------------------------- */
	/* Side-by-side split (map_position right / left). */
	& .erd__layout {
		display: flex;
		gap: var(--erd-gap);
		align-items: flex-start;
	}
	& .erd__layout--left {
		flex-direction: row-reverse;
	}
	& .erd__layout .erd__main {
		flex: 1 1 0;
		min-width: 0;
	}
	& .erd__layout .erd__map {
		flex: 0 0 45%;
	}
	& .erd__map {
		position: relative;
	}
	& .erd__map-canvas {
		width: 100%;
		height: var(--erd-map-height);
		border-radius: var(--erd-radius);
		overflow: hidden;
		background: var(--erd-surface-muted);
	}

	/* Map on top (DEFAULT): full-width banner, then a panel holding the header +
	   carousel that overlaps the map bottom. On mobile the map reorders below. */
	& .erd--map-top {
		display: flex;
		flex-direction: column;
	}
	& .erd--map-top .erd__map {
		width: 100%;
		order: 0;
	}
	& .erd--map-top .erd__panel {
		order: 1;
		position: relative;
		z-index: 2;
		align-self: center;
		width: 95%;
		background: var(--erd-surface);
		border-radius: var(--erd-radius);
		margin-top: -4rem;
		padding: 1.5rem 2rem 2rem;
		box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.06);
	}

	/* Google mark badge, top-right of the map (design). */
	& .erd__map-badge {
		position: absolute;
		top: 12px;
		right: 12px;
		z-index: 4;
		width: 34px;
		height: 34px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #ffffff;
		border-radius: 50%;
		box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
	}
	& .erd__map-badge .erd-icon--google {
		width: 20px;
		height: 20px;
	}

	/* Close button — shown only in the mobile fullscreen map (replaces the badge). */
	& .erd__map-close {
		display: none;
		position: absolute;
		top: 12px;
		right: 12px;
		z-index: 6;
		width: 40px;
		height: 40px;
		padding: 0; /* beat the host theme's button padding (oblong otherwise). */
		align-items: center;
		justify-content: center;
		background: #ffffff;
		color: var(--erd-ink);
		border-radius: 50%;
		box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
	}
	& .erd__map-close svg {
		width: 20px;
		height: 20px;
		fill: currentColor;
		overflow: visible;
	}

	/* Map disabled / failed → cards take the full width (addendum A5). */
	& .erd--map-failed .erd__map {
		display: none;
	}
	& .erd--map-failed .erd__layout {
		display: block;
	}

	/* Mobile "View in map" toggle (desktop shows the map inline, no toggle). */
	& .erd__map-toggle {
		display: none;
		width: 100%;
		margin-top: 0.5rem;
		min-height: 44px;
		padding: 0.5rem 1rem;
		background: #000000;
		color: #ffffff;
		border-radius: var(--erd-radius);
		font-weight: 600;
		text-align: center;
	}

	/* Loader overlay (design v2 — map module loading state): the placeholder map
	   image sits behind a translucent scrim, with a Google badge + status text
	   centred over it. The design's loading state also dims the panel below and
	   swaps the header/filters/cards for skeleton blocks — confirmed against the
	   actual Figma node (386:3553 / 387:4316), not just this map slice. Reproduced
	   below via .erd--loading on this.root, entirely in CSS: no PHP/markup changes,
	   the real elements are just visually masked (color:transparent + a skeleton-
	   grey ::after block, or visibility:hidden for images/icons) and pointer-events
	   disabled, then released the instant the map load finishes or fails. */
	& .erd__map-loader {
		position: absolute;
		inset: 0;
		display: none;
		align-items: center;
		justify-content: center;
		background-image: var(--erd-map-loader-bg, none);
		background-size: cover;
		background-position: center;
		border-radius: var(--erd-radius);
	}
	& .erd__map-loader::before {
		content: "";
		position: absolute;
		inset: 0;
		background: rgba(255, 255, 255, 0.75);
	}
	& .erd--map-loading .erd__map-loader {
		display: flex;
	}
	& .erd__map-loader-content {
		position: relative;
		z-index: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.75rem;
	}
	& .erd__map-loader-badge {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 63px;
		height: 63px;
		background: #ffffff;
		border-radius: 50%;
		box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
	}
	& .erd__map-loader-badge .erd-icon--google {
		width: 32px;
		height: 32px;
	}
	& .erd__map-loader-text {
		margin: 0;
		font-size: var(--erd-size-small);
		font-weight: 600;
		color: var(--erd-accent);
		text-transform: uppercase;
		letter-spacing: 0.02em;
	}

	/* Google mark: continuous loop while the loader is showing (design
	   annotation — "the Google logo should continuously animate in a loop
	   while the loading state is active"). Recreated in plain CSS — no GSAP,
	   no build step per this plugin's own constraints (README) — by drawing
	   each of the 4 official-colour paths in via stroke-dashoffset (pathLength
	   normalises this to 0–1 regardless of the path's real geometry, see
	   templates/icon-google.php), staggered, then crossfading to the solid
	   fill and holding briefly before resetting. Scoped to the loader badge
	   only — the persistent map attribution badge (.erd__map-badge) and any
	   per-card usage stay static. */
	@media (prefers-reduced-motion: no-preference) {
		& .erd__map-loader-badge .erd-icon--google path {
			fill-opacity: 0.25;
			stroke-width: 1.5;
			stroke-linecap: round;
			stroke-dasharray: 1;
			stroke-dashoffset: 1;
			animation: erd-google-draw 2.6s ease-in-out infinite backwards;
		}
		& .erd__map-loader-badge .erd-icon--google path:nth-child(1) {
			stroke: #4285f4;
			animation-delay: 0s;
		}
		& .erd__map-loader-badge .erd-icon--google path:nth-child(2) {
			stroke: #34a853;
			animation-delay: 0.15s;
		}
		& .erd__map-loader-badge .erd-icon--google path:nth-child(3) {
			stroke: #fbbc05;
			animation-delay: 0.3s;
		}
		& .erd__map-loader-badge .erd-icon--google path:nth-child(4) {
			stroke: #ea4335;
			animation-delay: 0.45s;
		}
	}

	/* Panel-wide skeleton (design v2). this.root gets .erd--loading for the
	   same window .erd--map-loading covers this.region — see map.js _setLoading.
	   .erd__panel only exists on the map-top layout (the "fully designed" one,
	   README §shortcode attributes), so this is naturally scoped to it. */
	& .erd--loading .erd--map-top .erd__panel {
		opacity: 0.6;
		pointer-events: none;
	}
	& .erd--loading .erd__heading {
		color: transparent;
		background: var(--erd-surface-muted);
		border-radius: var(--erd-radius);
	}
	& .erd--loading .erd-filter__toggle {
		color: transparent;
		background: var(--erd-surface-muted);
	}
	& .erd--loading .erd-filter__caret {
		visibility: hidden;
	}
	& .erd--loading .erd-card__media img,
	& .erd--loading .erd-card__chips,
	& .erd--loading .erd-card__link .erd-icon--arrow {
		visibility: hidden;
	}
	& .erd--loading .erd-card__media {
		background: var(--erd-surface-muted);
	}
	& .erd--loading .erd-card__title,
	& .erd--loading .erd-card__excerpt,
	& .erd--loading .erd-card__link {
		position: relative;
		color: transparent;
	}
	& .erd--loading .erd-card__title::after,
	& .erd--loading .erd-card__excerpt::after,
	& .erd--loading .erd-card__link::after {
		content: "";
		position: absolute;
		inset: 0;
		background: var(--erd-surface-muted);
		border-radius: 4px;
	}
	& .erd--loading .erd__count,
	& .erd--loading .erd__view-all {
		position: relative;
		color: transparent;
	}
	& .erd--loading .erd__count::after,
	& .erd--loading .erd__view-all::after {
		content: "";
		position: absolute;
		inset: 0;
		background: var(--erd-surface-muted);
		border-radius: 4px;
	}
	& .erd--loading .erd__view-all .erd-icon--arrow {
		visibility: hidden;
	}
	& .erd--loading .splide__arrow {
		background: var(--erd-surface-muted);
	}
	& .erd--loading .splide__arrow svg {
		visibility: hidden;
	}

	@keyframes erd-google-draw {
		/* fill-opacity never reaches 0 — with 4 staggered paths, a true 0 here
		   means every path can be simultaneously transparent (confirmed: the
		   mark rendered as a blank white circle in testing). A 0.25 floor keeps
		   a faint tinted "G" always visible; the 1.0 peak is what reads as the
		   animated "bloom". */
		0% {
			stroke-dashoffset: 1;
			fill-opacity: 0.25;
		}
		40% {
			stroke-dashoffset: 0;
			fill-opacity: 0.25;
		}
		55%,
		90% {
			stroke-dashoffset: 0;
			fill-opacity: 1;
		}
		100% {
			stroke-dashoffset: 1;
			fill-opacity: 0.25;
		}
	}

	/* Pins + clusters (prototype CSS, tokenized). These are Advanced Marker
	   content nodes rendered inside the map canvas. */
	& .custom-map-pin,
	& .custom-map-cluster {
		width: var(--erd-map-pin-size, 28px);
		height: var(--erd-map-pin-size, 28px);
		background: var(--erd-map-pin, #071927);
		border-radius: 50% 50% 50% 0;
		transform: rotate(-45deg);
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
		transition: width 0.2s ease, height 0.2s ease, background-color 0.2s ease;
	}
	& .custom-map-pin span,
	& .custom-map-cluster span {
		color: var(--erd-map-pin-ink, #ffffff);
		font-size: 13px;
		font-weight: 700;
		line-height: 1;
		transform: rotate(45deg);
	}
	& .custom-map-pin.is-active {
		width: var(--erd-map-pin-size-active, 36px);
		height: var(--erd-map-pin-size-active, 36px);
		background: var(--erd-map-pin-active, #ff6422);
		z-index: 10;
	}

	/* When a map is present, location is chosen via markers on desktop, so the
	   single-select (location) dropdown is hidden there and revealed only on mobile
	   where the map is collapsed. Service (multi-select) stays visible on both. */
	& .erd--has-map .erd-filter[data-erd-single="1"] {
		display: none;
	}

	/* Stack the split + reveal the mobile map affordances under a narrow container. */
	@container erd-root (max-width: 900px) {
		/* Horizontal gutters on the stacked layout (prototype padding-global); on
		   desktop the map is a full-bleed banner so no gutter there. */
		& .erd__layout {
			flex-direction: column;
		}
		& .erd__layout .erd__map {
			flex-basis: auto;
			width: 100%;
		}
		/* Back + heading are desktop-only (prototype): hide on the stacked layout. */
		& .erd--has-map .erd__header-left {
			display: none;
		}
		/* Static preview has no markers; they appear only in the fullscreen map. */
		& .erd--has-map:not(.erd--map-open) .custom-map-pin,
		& .erd--has-map:not(.erd--map-open) .custom-map-cluster {
			display: none;
		}
		/* map-top on mobile: cards first (panel), map preview below. Gutters go on
		   the CHILDREN — a container query can't pad its own container element. */
		& .erd--map-top .erd__map {
			order: 2;
			width: 100%;
			margin-left: 0;
			margin-right: 0;
		}
		& .erd--map-top .erd__panel {
			order: 1;
			width: 100%;
			align-self: stretch;
			margin-top: 0;
			/* Bottom only: the map (order 2) follows directly after this panel on
			   mobile, and padding:0 on all sides left the view-all link flush
			   against it with no breathing room. */
			padding: 0 0 1.5rem;
			box-shadow: none;
			background: transparent;
			border-radius: 0;
		}
	}
	@container erd-root (max-width: 560px) {
		/* Location dropdown returns on mobile (no marker interaction there). */
		& .erd--has-map .erd-filter[data-erd-single="1"] {
			display: block;
		}

		/* Filters stack full-width on mobile (prototype). */
		& .erd__filters {
			flex-direction: column;
			width: 100%;
		}
		& .erd__filters .erd-filter,
		& .erd__filters .erd-filter__toggle {
			width: 100%;
		}
		& .erd__filters .erd-filter__toggle {
			justify-content: space-between;
		}
		& .erd__filters .erd-filter__panel {
			width: 100%;
			min-width: 0;
		}

		/* "View in map" is a full-width bar across the bottom of the preview
		   (prototype gmb-posts-show-map); tapping opens the map fullscreen. */
		& .erd--has-map .erd__map {
			position: relative;
		}
		& .erd--has-map .erd__map-toggle {
			display: inline-flex;
			align-items: center;
			justify-content: center;
			position: absolute;
			left: 1rem;
			right: 1rem;
			bottom: 1rem;
			width: auto;
			margin: 0;
			border-radius: var(--erd-radius);
			z-index: 5;
		}
		& .erd--has-map:not(.erd--map-open) .erd__map-canvas {
			height: 200px; /* prototype mobile-static-map height. */
		}
	}

	/* Probe: exposes the narrow-container state to JS. The fullscreen map is a
	   container-query state, but once portaled to <body> the map has left the
	   container, so map.js can't ask it anything — and a viewport media query
	   would answer the wrong question (a phone rotated to landscape is 844px wide
	   while the section may still be narrow, or not). Reading this off an element
	   that STAYS in the section gets the same answer the container query gives. */
	& .erd__carousel {
		--erd-narrow: 0;
	}
	@container erd-root (max-width: 560px) {
		& .erd__carousel {
			--erd-narrow: 1;
		}
	}

	/* -------------------------------------------------------------------------
	 * Fullscreen map (mobile). The map region is PORTALED to <body> while open —
	 * `.erd` is a container-query container, so layout containment makes the
	 * SECTION, not the viewport, the containing block for a fixed child AND traps
	 * it in the section's stacking context. That is why a `z-index` on
	 * `.erd__map` used to lose to the host theme's header and footer no matter how
	 * high it went: the header is positioned, the whole section is not, so the
	 * section paints first and nothing inside it can climb out. map.js moves the
	 * region to <body> (the same trick the post list already used) and adds
	 * `.erd .erd-map-portal` to it; these rules take over from the in-place ones
	 * above, which can no longer match once the region has left the section.
	 * ------------------------------------------------------------------------- */
	& .erd-map-portal {
		position: fixed;
		inset: 0;
		z-index: var(--erd-z-map);
		max-width: none;
		margin: 0;
		padding: 0;
		/* The portal carries `.erd` for the tokens, which drags the page geometry
		   above and the container declaration along with it. Undo both — nothing
		   inside the map queries `erd-root`, and containment here would only
		   reintroduce the containing-block problem one level down. */
		container-type: normal;
	}
	& .erd-map-portal .erd__map-canvas {
		height: 100%;
		border-radius: 0;
	}
	/* Fullscreen: Google badge → close button. */
	& .erd-map-portal .erd__map-badge {
		display: none;
	}
	& .erd-map-portal .erd__map-close {
		display: inline-flex;
	}
	/* The bar reads "View all posts" here and hands over to the post list. */
	& .erd-map-portal .erd__map-toggle {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		left: 1rem;
		right: 1rem;
		bottom: 1rem;
		width: auto;
		margin: 0;
		border-radius: var(--erd-radius);
		z-index: 5;
	}
	/* -------------------------------------------------------------------------
	 * Fullscreen post list (mobile; addendum A2). Opened from the fullscreen map —
	 * by a marker drill or by "View all posts" — as a STACKED list of the visible
	 * cards (never a carousel). directory.js reparents it to <body>, so it carries
	 * its own `.erd` class for the tokens and must undo `.erd`'s page geometry.
	 * ------------------------------------------------------------------------- */
	& .erd-modal {
		position: fixed;
		inset: 0;
		z-index: var(--erd-z-modal);
		max-width: none;
		margin: 0;
		padding: 0;
		background: var(--erd-surface);
		overflow-y: auto;
		overscroll-behavior: contain;
		-webkit-overflow-scrolling: touch;
	}
	& .erd-modal[hidden] {
		display: none;
	}

	/* Header sticks while the list scrolls — Back is always one tap away. */
	& .erd-modal__header {
		position: sticky;
		top: 0;
		z-index: 1;
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		gap: 0.75rem;
		padding: 1rem;
		background: var(--erd-surface);
		border-bottom: 1px solid var(--erd-border);
	}
	/* Same (0,2,0) as `.erd .erd__heading`, declared later so it wins. */
	& .erd .erd-modal__title {
		font-size: 1.5rem;
	}

	/* Filters ride in the sticky header — full-width stacked, like the mobile
	   section filters. These are duplicates of the section's controls; the JS keeps
	   both in lockstep. The map's location control is NOT hidden here: the list is
	   where you pick a location once the map has handed over. */
	& .erd-modal__filters {
		width: 100%;
		flex-direction: column;
		gap: 0.5rem;
	}
	& .erd-modal__filters .erd-filter,
	& .erd-modal__filters .erd-filter__toggle {
		width: 100%;
	}
	& .erd-modal__filters .erd-filter__toggle {
		justify-content: space-between;
	}
	& .erd-modal__filters .erd-filter__panel {
		width: 100%;
		min-width: 0;
	}
	& .erd-modal__body {
		padding: 1rem 1rem 2rem;
	}
	& .erd-modal__list {
		display: grid;
		grid-template-columns: 1fr;
		gap: var(--erd-gap);
	}
	/* Belt-and-braces against Splide slide geometry riding in on a clone (the JS
	   strips the slide class + inline width, this covers anything it misses). */
	& .erd-modal__list .erd-card {
		width: auto;
		margin: 0;
	}

	@media (prefers-reduced-motion: reduce) {
		& .custom-map-pin,
		& .custom-map-cluster {
			transition: none;
		}
	}
}

/* Freeze the page behind an open overlay. Two classes, not one: the fullscreen
   map (`.erd-map-lock`) and the post list (`.erd-modal-lock`) open and close
   independently — the list opens FROM the map and closes back to it — so a
   single shared class would have the list's close unlock the page while the map
   is still up. Both go on <html>, which the boost wrapper can't reach as a
   descendant, so compound rather than descend. */
:is(#erd-directory#erd-directory, html).erd-modal-lock,
:is(#erd-directory#erd-directory, html).erd-modal-lock body,
:is(#erd-directory#erd-directory, html).erd-map-lock,
:is(#erd-directory#erd-directory, html).erd-map-lock body {
	overflow: hidden;
	overscroll-behavior: none;
}
