.wxpn-site-header {
	position: relative;
	z-index: 30;
	background: #000;
	transition: box-shadow 0.2s ease;
}

.wxpn-site-header__top,
.wxpn-site-header__top .wxpn-site-header__wrap,
.wxpn-site-header__brand-logo,
.wxpn-site-header__brand .custom-logo-link img,
.wxpn-site-header__player-slot,
.wxpn-site-header__search-toggle,
.wxpn-site-header__donate,
.wxpn-site-header__menu-toggle,
.wxpn-site-header__action-label,
.wxpn-site-header__primary-list > li > a {
	transition: 0.2s ease;
}

.wxpn-site-header__wrap {
	width: min(100%, 1200px);
	margin: 0 auto;
	padding: 0 24px;
}

.wxpn-site-header__top {
	position: relative;
	overflow: hidden;
	background:
		radial-gradient(circle at 12% 50%, rgba(255, 255, 255, 0.12), transparent 22%),
		radial-gradient(circle at 88% 50%, rgba(255, 255, 255, 0.08), transparent 18%),
		linear-gradient(90deg, #4e1518 0%, #6c201d 32%, #3a0f13 70%, #d46b1b 100%);
	border-bottom: 1px solid rgba(255, 255, 255, 0.14);
	transition-property: background;
}

.wxpn-site-header__top::before {
	content: "";
	position: absolute;
	/* Oversize the pseudo-element past the header bounds so the blur filter
	   doesn't reveal transparent edges where it samples beyond the image. */
	inset: -40px;
	background-image: var(--wxpn-header-banner-art, none);
	background-size: cover;
	background-position: center center;
	background-repeat: no-repeat;
	/* Strong blur for that "ambient album art" feel matching xpn.org. */
	filter: blur(28px) saturate(1.2);
	pointer-events: none;
	transition: background-image 0.3s ease-in-out;
	z-index: 0;
}

/* Darkening overlay on top of the album-art bleed. A HORIZONTAL scrim: the
   left third (behind the player art) uses the lightness-analyzer opacity
   (--wxpn-art-overlay-opacity, set in radio-player.js) so the ambient art stays
   vibrant near the player; the right side ramps to a fixed dark value so the
   utility menu's white links always clear WCAG contrast regardless of how light
   the current album art is (prev flat 0.25 washed the menu out to ~#D4D3CF).
   Matches prod, whose header stays dark maroon behind the utility column. */
.wxpn-site-header__top::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(
		90deg,
		rgba(0, 0, 0, var(--wxpn-art-overlay-opacity, 0.25)) 0%,
		rgba(0, 0, 0, var(--wxpn-art-overlay-opacity, 0.25)) 30%,
		rgba(0, 0, 0, 0.5) 52%,
		rgba(0, 0, 0, 0.68) 100%
	);
	pointer-events: none;
	transition: background 0.3s ease-in-out;
	z-index: 0;
}

.wxpn-site-header__top .wxpn-site-header__wrap {
	position: relative;
	z-index: 1;
	display: grid;
	/* Column 2 is reserved for the player overlay — the player itself is rendered
	   outside the header DOM and positioned over this column via .wxpn-player-mount. */
	grid-template-columns: 160px minmax(300px, 430px) minmax(220px, 1fr) auto;
	align-items: stretch;
	height: 120px;
	min-height: 78px;
	transition-property: min-height, grid-template-columns;
}

.wxpn-site-header__brand   { grid-column: 1; }
.wxpn-site-header__utility { grid-column: 3; }
.wxpn-site-header__actions { grid-column: 4; }

.wxpn-site-header__brand {
	display: flex;
	align-items: center;
}

.wxpn-site-header__brand-link {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}

.wxpn-site-header__brand-logo {
	display: block;
	width: 150px;
	height: auto;
	transition-property: width;
}

.wxpn-site-header__player-slot {
	display: flex;
	align-items: center;
	padding: 0 8px 0 0;
	min-width: 0;
	transition-property: padding;
}

.wxpn-site-header__brand .custom-logo-link {
	display: inline-flex;
	align-items: center;
}

.wxpn-site-header__brand .custom-logo-link img {
	max-width: 150px;
	height: auto;
	transition-property: max-width;
}

.wxpn-site-header__brand-text {
	font-size: 2.2rem;
	font-weight: 700;
	letter-spacing: -0.05em;
	color: #fff;
	text-decoration: none;
}

.wxpn-site-header__utility {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	padding: 0 18px 0 8px;
	min-width: 0;
	width: 100%;
}

.wxpn-site-header__utility--empty {
	visibility: hidden;
	pointer-events: none;
}

.wxpn-site-header__utility-list,
.wxpn-site-header__primary-list,
.wxpn-site-header__mobile-list,
.wxpn-site-header__mobile-utility-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.wxpn-site-header__utility-list {
	/* Fixed 3-column × 2-row grid to match prod (was flex-wrap, which packed the
	   6 items unevenly as 2 / 3 / 1 because the item widths differ). */
	display: grid;
	grid-template-columns: repeat(3, auto);
	justify-content: end;
	justify-items: start;
	align-items: center;
	width: auto;
	column-gap: 24px;
	row-gap: 6px;
	/* The list items inherit Astra's ~2.1 line-height (~30px tall rows), which
	   made the two rows sit ~38px apart. Tightening the line-height + row-gap
	   drops the row-to-row distance to ~27px (≈30% closer). The list stays
	   vertically centered via the flex container (.wxpn-site-header__utility
	   align-items: center). */
	line-height: 1.3;
}

.wxpn-site-header__utility-list a {
	position: relative;
	color: rgba(255, 255, 255, 0.94);
	text-decoration: none;
	/* Prod utility links are 12px (sampled from live xpn.org). */
	font-size: 12px;
	font-weight: 400;
	line-height: 1.2;
	white-space: nowrap;
}

.wxpn-site-header__utility-list li {
	flex: 0 0 auto;
	min-width: 0;
}

/* Hover underline: an always-orange bar (never gray) that fades in, sitting
   ~6px below the text — matches prod, which uses a transparent->orange
   border-bottom with a 0.3s transition. We animate opacity (not color) so the
   bar is XPN-orange the whole time instead of flickering through the link's
   grey rest color the way text-decoration-color did. */
.wxpn-site-header__utility-list a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -4px;
	height: 2px;
	background: #f29d07;
	opacity: 0;
	transition: opacity 0.3s ease;
}

.wxpn-site-header__utility-list a:hover {
	color: #fff;
}

.wxpn-site-header__utility-list a:hover::after,
.wxpn-site-header__utility-list li.current-menu-item a::after,
.wxpn-site-header__utility-list li.current-menu-ancestor a::after {
	opacity: 1;
}

.wxpn-site-header__utility-list li.current-menu-item a,
.wxpn-site-header__utility-list li.current-menu-ancestor a {
	color: #fff;
}

.wxpn-site-header__actions {
	display: flex;
	align-items: stretch;
	flex: 0 0 auto;
}

.wxpn-site-header__search-toggle,
.wxpn-site-header__donate,
.wxpn-site-header__menu-toggle {
	display: inline-flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	align-self: stretch;
	aspect-ratio: 1 / 1;
	min-width: 78px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #fff;
	text-decoration: none;
	cursor: pointer;
	transition-property: min-width, padding;
}

.wxpn-site-header__search-toggle {
	border-left: 1px solid rgba(255, 255, 255, 0.22);
}

.wxpn-site-header__donate {
	/* Prod donate rest color (sampled from live xpn.org: rgb(214,79,25)). */
	background: #c34817;
	gap: 5px;
	/* Prod donate is a wider block (~120px) than the square search/menu icons. */
	min-width: 120px;
	aspect-ratio: auto;
	/* Ease the background darken on hover. The shared action base only
	   transitions min-width/padding, so add background-color explicitly. */
	transition-property: min-width, padding, background-color;
}

/* Hover = darken the background only; the text/icon stay white. Astra's global
   a:hover turns links blue (and our white "Donate" label has no color rule of
   its own, so it inherits that blue) — re-assert white here to override it. */
.wxpn-site-header__donate:hover,
.wxpn-site-header__donate:focus {
	/* Prod donate hover = the saturated XPN brand orange-red (sampled from
	   live xpn.org: rgb(217,62,1)) — hover goes MORE saturated, not darker. */
	background: #d93e01;
	color: #fff;
}

.wxpn-site-header__donate-heart {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: #fff;
}

.wxpn-site-header__donate-heart svg {
	display: block;
	width: 20px;
	height: 20px;
}

/* The "Search" label rides along in markup but only shows on mobile — desktop
   keeps the icon-only search per spec. */
.wxpn-site-header__action-label--search {
	display: none;
}

.wxpn-site-header__menu-toggle {
	display: none;
	border-left: 1px solid rgba(255, 255, 255, 0.22);
}

.wxpn-site-header__action-label {
	font-size: 0.78rem;
	font-weight: 700;
	transition-property: font-size;
}

.wxpn-site-header__search-icon {
	display: inline-block;
	width: 15px;
	height: 15px;
	margin-bottom: 6px;
	border: 2px solid currentColor;
	border-radius: 50%;
	position: relative;
}

.wxpn-site-header__search-icon::after {
	content: "";
	position: absolute;
	right: -6px;
	bottom: -5px;
	width: 7px;
	height: 2px;
	background: currentColor;
	transform: rotate(45deg);
	transform-origin: center;
}

.wxpn-site-header__menu-bars,
.wxpn-site-header__menu-bars::before,
.wxpn-site-header__menu-bars::after {
	display: block;
	width: 18px;
	height: 2px;
	background: currentColor;
}

.wxpn-site-header__menu-bars {
	position: relative;
	margin-bottom: 8px;
}

.wxpn-site-header__menu-bars::before,
.wxpn-site-header__menu-bars::after {
	content: "";
	position: absolute;
	left: 0;
}

.wxpn-site-header__menu-bars::before {
	top: -5px;
}

.wxpn-site-header__menu-bars::after {
	top: 5px;
}

.wxpn-site-header__search-panel {
	background: #fff;
	border-bottom: 1px solid #d9d9d9;
}

.wxpn-site-header__search-panel .search-form {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 10px;
	padding: 14px 0;
}

.wxpn-site-header__search-panel .search-field {
	width: 100%;
	min-height: 48px;
	padding: 0 14px;
	border: 1px solid #cfcfcf;
	font-size: 1rem;
}

.wxpn-site-header__search-panel .search-submit {
	min-height: 48px;
	padding: 0 18px;
	border: 0;
	background: #111;
	color: #fff;
	font-weight: 700;
}

.wxpn-site-header__nav-bar {
	background: #000;
	border-top: 1px solid rgba(255, 255, 255, 0.06);
	transition: background 0.2s ease;
}

/* On desktop/wide the nav bar sits directly under the player band, so the
   __top border-bottom + this nav border-top stack into a faint light seam
   between them. Drop both there. (On mobile the nav bar is hidden and the
   __top border still separates the header from page content, so keep it.) */
@media (min-width: 1024px) /* --wxpn-bp-lg */ {
	.wxpn-site-header__top { border-bottom: 0; }
	.wxpn-site-header__nav-bar { border-top: 0; }
}

.wxpn-site-header__primary-nav {
	display: flex;
	justify-content: center;
	width: 100%;
}

.wxpn-site-header__primary-list {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	width: 100%;
	/* Nav sizing is variable-driven so the 1024–1199px breakpoint can shrink the
	   item padding + font together (and keep the hover underline aligned) instead
	   of the items wrapping onto two rows. Defaults match prod (20px / 600). */
	--wxpn-nav-x: 64px;
	--wxpn-nav-fs: 20px;
}

.wxpn-site-header__primary-list > li {
	position: relative;
}

.wxpn-site-header__primary-list > li + li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 50%;
	width: 1px;
	/* Taller divider that extends above/below the text, matching prod. */
	height: 40px;
	background: rgba(255, 255, 255, 0.24);
	transform: translateY(-50%);
}

.wxpn-site-header__primary-list > li > a {
	display: block;
	position: relative;
	/* Horizontal padding opens the gap between items; driven by --wxpn-nav-x so
	   the narrow-desktop breakpoint can tighten it. */
	padding: 18px var(--wxpn-nav-x);
	color: #fff;
	box-sizing: border-box;
	text-decoration: none;
	/* Prod primary nav is 20px / 600 (sampled from live xpn.org). Was 24px / 700,
	   which is what overflowed and wrapped between 1024–1199px. */
	font-size: var(--wxpn-nav-fs);
	font-weight: 600;
	transition-property: padding, font-size;
}

.wxpn-site-header__primary-list > li > a::after {
	content: "";
	position: absolute;
	left: var(--wxpn-nav-x);
	right: var(--wxpn-nav-x);
	/* Sits tight against the text like prod. The links' tall line-height means
	   a larger bottom offset is needed to pull the bar up close to the text. */
	bottom: 24px;
	height: 2px;
	background: #f29d07;
	opacity: 0;
	/* Fade in quickly on hover instead of snapping on (matches prod's 0.3s). */
	transition: opacity 0.3s ease;
}

.wxpn-site-header__primary-list > li.current-menu-item > a,
.wxpn-site-header__primary-list > li.current-menu-ancestor > a,
.wxpn-site-header__primary-list > li > a:hover {
	color: #fff;
	box-shadow: none;
}

.wxpn-site-header__primary-list > li.current-menu-item > a::after,
.wxpn-site-header__primary-list > li.current-menu-ancestor > a::after,
.wxpn-site-header__primary-list > li > a:hover::after {
	opacity: 1;
}

/* Narrow desktop (1024–1199px): with the full-width 20px/64px items the five
   links ("Concert Calendar" is the widest) overflowed the row and wrapped onto
   a second line / overlapped the dividers. Tighten padding + font here so the
   nav stays on ONE row down to the 1024px breakpoint. The hover underline
   (::after) tracks --wxpn-nav-x automatically. */
@media (min-width: 1024px) and (max-width: 1199px) {
	.wxpn-site-header__primary-list {
		--wxpn-nav-x: 30px;
		--wxpn-nav-fs: 18px;
	}
}

.wxpn-site-header__mobile-drawer {
	background: #000;
	border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.wxpn-site-header__mobile-inner {
	width: min(100%, 1200px);
	margin: 0 auto;
	padding: 16px 24px 24px;
}

.wxpn-site-header__mobile-list,
.wxpn-site-header__mobile-utility-list {
	display: grid;
}

.wxpn-site-header__mobile-list a,
.wxpn-site-header__mobile-utility-list a {
	display: block;
	padding: 12px 0;
	color: #fff;
	text-decoration: none;
	border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

.wxpn-site-header__mobile-utility {
	margin-top: 18px;
}

.wxpn-site-header__mobile-utility-list a {
	color: rgba(255, 255, 255, 0.82);
	font-size: 0.92rem;
}

body.wxpn-header-is-sticky {
	padding-top: 166px;
}

.wxpn-site-header.is-sticky {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	box-shadow: 0 10px 24px rgba(0, 0, 0, 0.22);
}

/* Sticky is only a MODEST shrink of the full header, matching prod: the top
   band gets shorter (120→85) and the logo/art shrink a little, but the
   horizontal layout is unchanged and ALL font sizes stay full — prod does not
   shrink its sticky typography, and the previous aggressive shrink made the
   logo/text/nav far too tiny. */
.wxpn-site-header.is-sticky .wxpn-site-header__top .wxpn-site-header__wrap {
	/* Only the height changes; the base grid (160px col 1, etc.) is kept so the
	   logo/player/menu don't reflow horizontally when the header sticks. */
	height: 85px;
	min-height: 85px;
}

.wxpn-site-header.is-sticky .wxpn-site-header__player-slot {
	padding-right: 8px;
}

.wxpn-site-header.is-sticky .wxpn-site-header__brand .custom-logo-link img {
	max-width: 110px;
}

.wxpn-site-header.is-sticky .wxpn-site-header__brand-logo {
	width: 110px;
}

body.admin-bar .wxpn-site-header {
	top: 0;
}

body.admin-bar .wxpn-site-header.is-sticky {
	top: 32px;
}

@media (max-width: 1023px) /* --wxpn-bp-lg */ {
	/* Below desktop: the player leaves the header for a bottom bar; the
	   header itself collapses to brand + actions (search/donate/menu).
	   Utility menu and inline nav are replaced by the hamburger drawer. */

	/* Album-art bleed is desktop-only (the mobile player carries its own art). */
	.wxpn-site-header__top::before { display: none; }
	.wxpn-site-header__top {
		background:
			linear-gradient(90deg, #4e1518 0%, #6c201d 32%, #3a0f13 70%, #d46b1b 100%);
		/* The 1px bottom border added to the pinned 78px wrap → 79px total, which
		   QA flagged as "1px too tall". Prod has no seam here (the gradient meets
		   page content directly), so drop it on mobile. */
		border-bottom: 0;
	}

	body.wxpn-header-is-sticky {
		padding-top: 78px;
	}

	.wxpn-site-header__top .wxpn-site-header__wrap {
		grid-template-columns: 1fr auto;
		grid-template-rows: auto;
		/* Match prod's shorter mobile header. The desktop base sets height:120px;
		   the old mobile rule only overrode min-height, so 120px leaked through
		   and the header rendered ~121px tall. Pin it to 78px. */
		height: 78px;
		min-height: 78px;
		align-items: center;
	}

	.wxpn-site-header__brand       { grid-column: 1; }
	.wxpn-site-header__actions     { grid-column: 2; }
	.wxpn-site-header__utility     { display: none; }
	.wxpn-site-header__nav-bar     { display: none; }
	.wxpn-site-header__menu-toggle { display: inline-flex; }

	.wxpn-site-header__search-toggle,
	.wxpn-site-header__donate,
	.wxpn-site-header__menu-toggle {
		min-width: 72px;
		padding: 0;
		/* No vertical dividers between the action icons on mobile (prod has none). */
		border-left: 0;
	}

	/* Action-icon label text (Search / Donate / Menu). Prod is 16px; dev was
	   14px (QA-flagged). */
	.wxpn-site-header__action-label {
		font-size: 16px;
	}

	/* Show the "Search" label on mobile (desktop stays icon-only). */
	.wxpn-site-header__action-label--search {
		display: block;
	}

	.wxpn-site-header__search-icon {
		margin-bottom: 5px;
	}

	.wxpn-site-header__brand .custom-logo-link img { max-width: 92px; }
	.wxpn-site-header__brand-logo                  { width: 92px; }

	.wxpn-site-header__search-panel .search-form {
		grid-template-columns: 1fr;
	}

	.wxpn-site-header.is-sticky .wxpn-site-header__top .wxpn-site-header__wrap {
		grid-template-columns: 1fr auto;
		height: 78px;
		min-height: 78px;
	}

	.wxpn-site-header.is-sticky .wxpn-site-header__brand .custom-logo-link img { max-width: 92px; }
	.wxpn-site-header.is-sticky .wxpn-site-header__brand-logo                  { width: 92px; }

	body.admin-bar .wxpn-site-header.is-sticky {
		top: 46px;
	}
}

/* =========================================================================
   Player mount

   The player markup is rendered outside the header (see inc/header.php).
   This mount is a positioning wrapper that controls WHERE the player sits:
     - Desktop (>=1024px): overlays the header band, occupying the grid cell
       that header.css leaves empty in column 2.
     - Below 1024px: pinned to the bottom of the viewport as a fixed bar.

   Visual styling of the player itself lives in radio-player.css. The mount
   only deals with position, size, and z-stacking.
   ========================================================================= */

.wxpn-player-mount {
	position: absolute;
	top: 0;
	/* The mount sits inside .wxpn-site-header__wrap, whose padding-box is the
	   positioning context. left = brand column (160px) + wrap's left padding
	   (24px) + a 73px gap so the album art clears the (enlarged 150px) logo,
	   matching prod's ~83px logo-to-art spacing. */
	left: calc(160px + 24px + 73px);
	/* Width trimmed so the mount's right edge stops ~30px short of the utility
	   column (matching prod's now-playing→utility gap). Previously it landed
	   flush against the utility (only ~9px clearance), so long song/artist
	   names truncated right up against the menu text. */
	width: clamp(280px, calc(100% - 160px - 220px - 200px - 48px), 335px);
	height: 120px;
	z-index: 32;
	/* No transitions on the mount itself. The mount's position changes
	   dramatically when crossing the desktop/mobile breakpoint, and animating
	   top/left between the two contexts produces a visible "player slides
	   into place" effect that confuses the resize transition. The contents
	   of the player (icons, controls) animate their own transitions. */
	transition: none;
}

/* Sticky shrink — matches the header's sticky size (brand col 132px).
   Scoped to desktop because below 1024px the header isn't the player's
   container — the player is bottom-fixed via the mobile @media rule below.
   Without this min-width guard, the sticky height (72px) would also clamp
   the mobile mount and hide most of the expanded player content.

   Mount height (72px) matches the player section's sticky inner min-height
   exactly so the art doesn't overflow the section's bottom. */
@media (min-width: 1024px) /* --wxpn-bp-lg */ {
	.wxpn-site-header.is-sticky .wxpn-player-mount {
		/* Keep the base left (logo→art gap) — only the height shrinks. */
		height: 85px;
	}
}

@media (max-width: 1023px) /* --wxpn-bp-lg */ {
	/* Below desktop, the player leaves the header and pins to the bottom of
	   the viewport. The mount carries its own background here since the
	   header no longer hosts the album-art bleed.

	   Positioning strategy:
	   - JS sets `top = window.innerHeight - playerHeight` so the player
	     follows iOS Safari / Chrome / Firefox Android dynamic toolbars
	     (see radio-player.js — positionMobilePlayer).
	   - The CSS values here are the fallback used until the JS runs and on
	     browsers without visualViewport. `1dvh` (dynamic viewport height)
	     gives the best static fallback because it tracks toolbar changes
	     via CSS alone, where supported. */
	.wxpn-player-mount {
		position: fixed;
		top: auto;
		bottom: 0;
		left: 0;
		right: 0;
		width: 100%;
		/* Height tracks the player's collapsed/expanded state. Two parallel
		   signals from radio-player.js drive this:
		     1. --wxpn-player-mobile-height (used here and in body padding)
		     2. html.wxpn-player-expanded class (used in the override below)
		   Belt-and-suspenders — var() propagation can be flaky in some Chrome
		   states when a click flips the height; the class-driven override
		   guarantees the mount height.

		   The safe-area inset is ADDED to the player height (not left to eat into
		   it). With box-sizing: border-box, a bare `padding-bottom: env(...)` was
		   subtracting the iOS home-indicator inset (~34px) from the fixed 72px,
		   leaving only ~38px of content and clipping the album art / controls.
		   calc() keeps the content at its full height and reserves the inset
		   below it. */
		height: calc(var(--wxpn-player-mobile-height, 72px) + env(safe-area-inset-bottom, 0px));
		z-index: 50;
		background:
			radial-gradient(circle at 12% 50%, rgba(255, 255, 255, 0.12), transparent 22%),
			linear-gradient(90deg, #4e1518 0%, #6c201d 32%, #3a0f13 70%, #d46b1b 100%);
		box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.32);
		border-top: 1px solid rgba(255, 255, 255, 0.18);
		/* No height transition: collapse/expand snaps instantly so the JS
		   positionMobilePlayer() reads the final offsetHeight, not an
		   in-progress animated value. */
		transition: none;
		/* Respect the iPhone home-indicator area. */
		padding-bottom: env(safe-area-inset-bottom);
	}

	/* Expanded height is driven entirely by --wxpn-player-mobile-height (set by
	   radio-player.js: 132px expanded, or 172px when the archive scrubber row is
	   present). No hardcoded expanded override here — it would fight the dynamic
	   value. The .wxpn-player-expanded class is still toggled for other hooks. */

	/* No CSS dvh `top` override. radio-player.js owns the precise position via
	   top = window.innerHeight - offsetHeight (the proven live-site approach);
	   plain bottom:0 above is the only fallback needed before/without JS. A dvh
	   top override here was found to fight the JS and was removed on the live
	   site (PageWrapper commit 3b7d4f0). */

	.wxpn-site-header.is-sticky .wxpn-player-mount {
		left: 0;
	}

	/* Keep page content above the bottom-bar player. The padding-bottom
	   value mirrors the player's current height (set by radio-player.js
	   when collapsed/expanded) plus the safe-area inset. */
	body {
		padding-bottom: calc(var(--wxpn-player-mobile-height, 72px) + env(safe-area-inset-bottom));
	}
}
